feat(mvp): phase 5 - board, section & widget system

Add board/section/widget CRUD APIs with permission filtering, board view
page with collapsible sections and app widgets in responsive grid, form-based
board editor, and 9 Svelte components (Board, Section, Widget families).
This commit is contained in:
2026-03-24 21:05:00 +03:00
parent 4d941f566f
commit b0d77d3c29
23 changed files with 1564 additions and 27 deletions
@@ -0,0 +1,61 @@
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types.js';
import * as boardService from '$lib/server/services/boardService.js';
import * as permissionService from '$lib/server/services/permissionService.js';
import { EntityType, PermissionLevel, UserRole } from '$lib/utils/constants.js';
import { isBoardGuestAccessible } from '$lib/server/middleware/guestAccess.js';
export const load: PageServerLoad = async ({ params, locals }) => {
const { boardId } = params;
const user = locals.user;
// Permission check
if (!user) {
const isGuest = await isBoardGuestAccessible(boardId);
if (!isGuest) {
throw error(401, { message: 'Authentication required' });
}
} else if (user.role !== UserRole.ADMIN) {
const result = await permissionService.checkPermission(
EntityType.BOARD,
boardId,
user.id,
PermissionLevel.VIEW
);
if (!result.hasPermission) {
const isGuest = await isBoardGuestAccessible(boardId);
if (!isGuest) {
throw error(403, { message: 'Insufficient permissions' });
}
}
}
try {
// findBoardById includes sections -> widgets -> app -> statuses
const board = await boardService.findBoardById(boardId);
// Determine if user can edit this board
let canEdit = false;
if (user) {
if (user.role === UserRole.ADMIN) {
canEdit = true;
} else {
const editResult = await permissionService.checkPermission(
EntityType.BOARD,
boardId,
user.id,
PermissionLevel.EDIT
);
canEdit = editResult.hasPermission;
}
}
return { board, canEdit };
} catch (err) {
const message = err instanceof Error ? err.message : 'Board not found';
if (message.includes('not found')) {
throw error(404, { message: 'Board not found' });
}
throw error(500, { message });
}
};