# Feature Context: Phase 2 — Enhanced Features ## Current State Phase 1 (OAuth/Authentik Integration) and Phase 2 (DnD) are complete. Installed `openid-client` v6.8.2. OAuth login flow uses PKCE and issues local JWT tokens. Login page conditionally shows OAuth button and/or local form based on `authMode` SystemSettings. Admin settings page has a working "Test Connection" button for OAuth configuration. ## Temporary Workarounds - None yet ## Cross-Phase Dependencies - Phase 1 (OAuth) is independent — touches auth system only - Phase 2 (DnD) is independent — touches board editor UI only - Phase 3 (Widgets) depends on existing widget system from MVP - Phase 4 (Access Control) depends on existing permission system from MVP - Phase 5 (Integration) depends on all prior phases ## Implementation Notes - Big Bang strategy: intermediate phases may not build. Phase 6 is the convergence phase. - OAuth uses `openid-client` (already installed in MVP dependencies) - DnD uses `svelte-dnd-action` (installed in Phase 2) - New widget types extend the existing Widget model's `type` and `config` JSON fields ## Phase 2 (DnD) — Completed - Installed `svelte-dnd-action` package - Created `DraggableBoard.svelte`, `DraggableSection.svelte`, `DraggableWidget.svelte` component hierarchy - Board edit page now uses DnD for section and widget reordering (including cross-section widget moves) - Added `PUT /api/boards/[id]/reorder` and `PUT /api/boards/[id]/sections/[sid]/reorder` endpoints - Extended `boardService.ts` with `reorderSections()`, `reorderWidgets()`, `moveWidget()` using Prisma transactions - Visual drag handles (grip dots) and dashed drop zone indicators added via Tailwind - Edit page actions (add/delete section/widget) use `invalidateAll()` for data refresh; DnD uses optimistic fetch ## Phase 4 (Additional Widget Types) — Completed - Installed `marked` package for markdown rendering - WidgetType enum already had BOOKMARK, NOTE, EMBED, STATUS from MVP constants - Added per-type Zod config schemas in `validators.ts`: `appWidgetConfigSchema`, `bookmarkWidgetConfigSchema`, `noteWidgetConfigSchema`, `embedWidgetConfigSchema`, `statusWidgetConfigSchema` - Updated `src/lib/types/widget.ts` config interfaces to match spec (BookmarkWidgetConfig, NoteWidgetConfig, EmbedWidgetConfig, StatusWidgetConfig) - Created 4 new widget components: - `BookmarkWidget.svelte` — clickable card with icon, label, description, opens URL in new tab - `NoteWidget.svelte` — renders markdown via `marked` with basic HTML sanitization - `EmbedWidget.svelte` — iframe with configurable height, sandbox security, loading spinner - `StatusWidget.svelte` — aggregated status bar with online/offline/degraded/unknown counts, expandable per-app detail - Created `WidgetRenderer.svelte` — universal type-switch component dispatching to correct widget by type - Updated `WidgetGrid.svelte` to use WidgetRenderer; note/embed/status widgets span full grid width - Updated `DraggableSection.svelte` with widget type selector dropdown and type-specific config forms (app selector, bookmark URL/label/icon/desc, note textarea with format, embed URL/height, status multi-select apps) - `onAddWidget` callback changed from `(sectionId, appId)` to `(sectionId, widgetDataJson)` across DraggableBoard and edit page - Board view server (`[boardId]/+page.server.ts`) now loads all apps via `appService.findAll()` for StatusWidget - Plumbed `allApps` prop through Board -> Section -> WidgetGrid -> WidgetRenderer -> StatusWidget - Edit server action `addWidget` now handles `configJson` form field for non-app widget types ## Phase 3 (Localization EN/RU) — Completed - Installed `svelte-i18n` package for i18n support - Created `src/lib/i18n/en.json` and `src/lib/i18n/ru.json` with ~180 translation keys covering all UI strings - Created `src/lib/i18n/index.ts` with locale detection (localStorage > browser navigator > fallback 'en') and `storeLocale()` helper - Created `LanguageSwitcher.svelte` — EN/RU toggle button added to Header, persists preference to localStorage key `wal-locale` - Root `+layout.svelte` imports `$lib/i18n/index.js` to initialize i18n before any component renders - Extracted all hardcoded strings from: layout (Header, Sidebar, MainLayout, ThemeToggle), auth pages (login, register), board/section/widget components, app components (AppForm, AppHealthBadge, AppIconPicker), admin pages (users, groups, settings, PermissionEditor), search components (SearchDialog, SearchTrigger), home page, and DnD components - Translation key structure uses dot-notation grouped by feature: `nav.*`, `auth.*`, `board.*`, `section.*`, `widget.*`, `app.*`, `admin.*`, `search.*`, `common.*`, `status.*`, `theme.*`, `bg.*`, `sidebar.*`, `home.*` - All status labels (online/offline/degraded/unknown) are now translated via `$t('status.*')` in AppHealthBadge - Phase 4 widget type form labels (bookmark, note, embed, status fields) are partially untranslated — can be addressed in Phase 6