Files
web-app-launcher/plans/phase-2-enhanced-features/CONTEXT.md
T
alexei.dolgolyov 477c0e4d52 feat(phase2): localization EN/RU + additional widget types
- Add svelte-i18n with 224 translation keys (English + Russian)
- Language switcher in header (EN/RU toggle, persists to localStorage)
- Extract all hardcoded strings from 37 component/page files
- Add 4 new widget types: Bookmark, Note (markdown), Embed (iframe), Status
- WidgetRenderer dispatches by type, WidgetGrid supports full-width widgets
- Type-specific config forms in board editor
- Install marked for markdown rendering
2026-03-24 23:18:05 +03:00

4.9 KiB

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