1239 lines
63 KiB
Markdown
1239 lines
63 KiB
Markdown
# Frontend Architecture
|
||
|
||
## Overview
|
||
|
||
The frontend is a **Next.js 15** application with **React 19**, **TypeScript**, **Redux Toolkit**, and **Tailwind CSS**. It uses the Pages Router with client-side rendering (CSR), optimized for complex admin/builder interactions and PWA offline capabilities.
|
||
|
||
**Location:** `frontend/src/`
|
||
|
||
**Total Files:** 408 TypeScript/TSX files across 14 directories
|
||
|
||
---
|
||
|
||
## Tech Stack
|
||
|
||
| Technology | Version | Purpose |
|
||
|------------|---------|---------|
|
||
| Next.js | 15.3.1 | React framework with Pages Router |
|
||
| React | 19.0.0 | UI library |
|
||
| TypeScript | 5.x | Type safety |
|
||
| Redux Toolkit | 2.1.0 | State management |
|
||
| MUI X DataGrid | 7.0.0 | Data tables |
|
||
| Tailwind CSS | 3.4.1 | Utility-first styling |
|
||
| Formik | 2.4.x | Form management |
|
||
| Axios | 1.x | HTTP client |
|
||
| Serwist | 9.x | PWA service worker |
|
||
| Dexie.js | 4.x | IndexedDB wrapper |
|
||
|
||
---
|
||
|
||
## Architecture Diagram
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ ENTRY LAYER │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ pages/_app.tsx │ │
|
||
│ │ • Redux Provider (store.ts) │ │
|
||
│ │ • DownloadContext (PWA progress) │ │
|
||
│ │ • Axios interceptors (JWT refresh, error handling) │ │
|
||
│ │ • PWA service worker registration (Serwist) │ │
|
||
│ │ • ErrorBoundary wrapper │ │
|
||
│ │ • i18n initialization │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ LAYOUT LAYER │
|
||
│ ┌───────────────────────────────────┐ ┌─────────────────────────────────┐ │
|
||
│ │ Authenticated.tsx │ │ Guest.tsx │ │
|
||
│ │ • JWT validation (client-side) │ │ • Public routes only │ │
|
||
│ │ • Permission checking per route │ │ • Login, Register, Forgot │ │
|
||
│ │ • Project existence guard │ │ • Minimal layout │ │
|
||
│ │ • NavBar, AsideMenu, FooterBar │ │ │ │
|
||
│ │ • Tour guide (IntroGuide) │ │ │ │
|
||
│ └───────────────────────────────────┘ └─────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ PAGE LAYER (99 pages) │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Entity CRUD Pages (78 pages = 13 entities × 6 pages each) │ │
|
||
│ │ • [entity]-list.tsx → createListPage factory │ │
|
||
│ │ • [entity]-new.tsx → Formik forms with validation │ │
|
||
│ │ • [entity]-edit.tsx → useEditPageSync hook │ │
|
||
│ │ • [entity]-view.tsx → Read-only display │ │
|
||
│ │ • [entity]-table.tsx → Embedded table view │ │
|
||
│ │ • [entityId].tsx → Dynamic route handler │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Special Pages (21 pages) │ │
|
||
│ │ • constructor.tsx → Visual tour builder (47KB) │ │
|
||
│ │ • dashboard.tsx → Admin home with entity counts │ │
|
||
│ │ • p/[slug]/index.tsx → Public production presentation │ │
|
||
│ │ • p/[slug]/stage.tsx → Stage preview presentation │ │
|
||
│ │ • login.tsx, forgot.tsx, password-reset.tsx → Auth flows │ │
|
||
│ │ • profile.tsx → User profile management │ │
|
||
│ │ • element-type-defaults.tsx → Global element defaults │ │
|
||
│ │ • project-element-defaults.tsx → Project element overrides │ │
|
||
│ │ • search.tsx → Global search │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ COMPONENT LAYER (193 components) │
|
||
│ ┌────────────────────────┐ ┌────────────────────────┐ ┌────────────────┐ │
|
||
│ │ Entity Components (78) │ │ Constructor (15) │ │ Runtime (5) │ │
|
||
│ │ • Table[Entity] │ │ • ElementEditorPanel │ │ • Runtime- │ │
|
||
│ │ • configure*Cols │ │ • CanvasElement │ │ Presentation│ │
|
||
│ │ • Card[Entity] │ │ • CanvasBackground │ │ • Runtime- │ │
|
||
│ │ • List[Entity] │ │ • ConstructorMenu │ │ Element │ │
|
||
│ │ • Form fields │ │ • PageSelector │ │ • UiElement- │ │
|
||
│ └────────────────────────┘ │ • TransitionPreview │ │ Renderer │ │
|
||
│ ┌────────────────────────┐ └────────────────────────┘ │ │ │
|
||
│ │ ElementSettings (23) │ ┌────────────────────────┐ └────────────────┘ │
|
||
│ │ • StyleSettings │ │ Offline/PWA (5) │ ┌────────────────┐ │
|
||
│ │ • NavigationSettings │ │ • DownloadProgress │ │ Generic (50+) │ │
|
||
│ │ • EffectsSettings │ │ • OfflineToggle │ │ • CardBox* │ │
|
||
│ │ • CarouselSettings │ │ • StorageUsage │ │ • FormField* │ │
|
||
│ │ • MediaSettings │ │ • OfflineStatus │ │ • NavBar* │ │
|
||
│ │ • TooltipSettings │ └────────────────────────┘ │ • AsideMenu* │ │
|
||
│ └────────────────────────┘ │ • BaseButton │ │
|
||
│ ┌────────────────────────┐ │ • Pagination │ │
|
||
│ │ Factories (2) │ │ • Search │ │
|
||
│ │ • createTableComp │ └────────────────┘ │
|
||
│ │ • configBuilderFact │ │
|
||
│ └────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ HOOKS LAYER (32 hooks) │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Runtime/Preloading (8 hooks) │ │
|
||
│ │ usePreloadOrchestrator ──→ usePageSwitch ──→ useBackgroundTransition │ │
|
||
│ │ │ │ │ │
|
||
│ │ ▼ ▼ │ │
|
||
│ │ useNeighborGraph useTransitionPlayback ──→ useReversePlayback│ │
|
||
│ │ │ │ │
|
||
│ │ ▼ │ │
|
||
│ │ usePageDataLoader ──→ usePreloadProgress │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Constructor (7 hooks) │ │
|
||
│ │ useConstructorElements ──→ useConstructorPageActions │ │
|
||
│ │ │ │ │
|
||
│ │ ▼ │ │
|
||
│ │ useCanvasElementDrag ──→ useCanvasElapsedTime │ │
|
||
│ │ │ │ │
|
||
│ │ ▼ │ │
|
||
│ │ useTransitionPreview ──→ useIconPreload ──→ useMediaDurationProbe │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌────────────────────────┐ ┌────────────────────────┐ ┌────────────────┐ │
|
||
│ │ Offline/PWA (4) │ │ Forms/Tables (4) │ │ Utility (8) │ │
|
||
│ │ • useOfflineMode │ │ • useFormSync │ │ • useCSV- │ │
|
||
│ │ • usePWAPreload │ │ • useEntityTable │ │ Handling │ │
|
||
│ │ • useStorageQuota │ │ • useFilterItems │ │ • useElement- │ │
|
||
│ │ • useNetworkAware │ │ • useEditPageSync │ │ Effects │ │
|
||
│ └────────────────────────┘ └────────────────────────┘ │ • useOutside- │ │
|
||
│ │ Click │ │
|
||
│ │ • useDraggable│ │
|
||
│ └────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ STATE LAYER │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Redux Store (stores/store.ts) │ │
|
||
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ Entity Slices (13) - via createEntitySlice factory │ │ │
|
||
│ │ │ users, roles, permissions, projects, project_memberships, │ │ │
|
||
│ │ │ assets, asset_variants, presigned_url_requests, tour_pages, │ │ │
|
||
│ │ │ project_audio_tracks, publish_events, pwa_caches, access_logs │ │ │
|
||
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
|
||
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ Core Slices (3) │ │ │
|
||
│ │ │ • authSlice - JWT token, current user, permissions │ │ │
|
||
│ │ │ • mainSlice - UI state (sidebar, dark mode) │ │ │
|
||
│ │ │ • styleSlice - Theme configuration │ │ │
|
||
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ React Context │ │
|
||
│ │ • DownloadContext - PWA download progress tracking │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ LIBRARY LAYER (20 files) │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ lib/offline/ - PWA Storage │ │
|
||
│ │ • StorageManager.ts - Cache API + IndexedDB dual storage │ │
|
||
│ │ • DownloadManager.ts - Asset download orchestration │ │
|
||
│ │ • DownloadEventBus.ts - Progress event system (Observer pattern) │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ lib/offlineDb/ - IndexedDB Persistence │ │
|
||
│ │ • OfflineDbManager.ts - Dexie.js wrapper for large assets │ │
|
||
│ │ • schema.ts - Database schema definition │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ lib/ - Utilities │ │
|
||
│ │ • assetUrl.ts - Presigned URL management, expiry handling │ │
|
||
│ │ • elementDefaults.ts - Default element configurations (17KB) │ │
|
||
│ │ • elementStyles.ts - Element CSS generation │ │
|
||
│ │ • elementEffects.ts - Element animation effects │ │
|
||
│ │ • constructorHelpers.ts - Canvas manipulation utilities │ │
|
||
│ │ • navigationHelpers.ts - Link resolution, transition detection │ │
|
||
│ │ • extractPageLinks.ts - Parse navigation links from ui_schema │ │
|
||
│ │ • imagePreDecode.ts - Image pre-decoding for smooth transitions │ │
|
||
│ │ • mediaDuration.ts - Audio/video duration extraction │ │
|
||
│ │ • mediaHelpers.ts - Media URL handling │ │
|
||
│ │ • parseJson.ts - Safe JSON parsing with fallbacks │ │
|
||
│ │ • logger.ts - Structured logging (dev/prod modes) │ │
|
||
│ │ • slugHelpers.ts - URL slug generation │ │
|
||
│ │ • tourFlowHelpers.ts - Page ordering utilities │ │
|
||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
│ SUPPORT LAYER │
|
||
│ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────────┐ │
|
||
│ │ factories/ (3) │ │ schemas/ (6) │ │ types/ (12) │ │
|
||
│ │ • createListPage │ │ • userSchema │ │ • constructor.ts │ │
|
||
│ │ • createFormPage │ │ • assetSchema │ │ • entities.ts │ │
|
||
│ │ • index │ │ • projectSchema │ │ • runtime.ts │ │
|
||
│ └────────────────────┘ │ • tourPageSchema │ │ • preload.ts │ │
|
||
│ ┌────────────────────┐ │ • roleSchema │ │ • presentation.ts │ │
|
||
│ │ helpers/ (6) │ └────────────────────┘ │ • offline.ts │ │
|
||
│ │ • dataFormatter │ ┌────────────────────┐ │ • permissions.ts │ │
|
||
│ │ • textFormatters │ │ config/ (2) │ │ • forms.ts │ │
|
||
│ │ • userPermissions │ │ • preload.config │ │ • filters.ts │ │
|
||
│ │ • notifyState │ │ • offline.config │ │ • api.ts │ │
|
||
│ │ • humanize │ └────────────────────┘ │ • redux.ts │ │
|
||
│ │ • fileSaver │ └────────────────────────┘ │
|
||
│ └────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Directory Structure
|
||
|
||
```
|
||
frontend/src/
|
||
├── pages/ # 99 files - Next.js pages
|
||
│ ├── _app.tsx # App entry point
|
||
│ ├── api/ # API routes (logError.ts, hello.js)
|
||
│ ├── p/[projectSlug]/ # Public presentation routes
|
||
│ │ ├── index.tsx # Production presentation
|
||
│ │ └── stage.tsx # Stage preview
|
||
│ ├── constructor.tsx # Visual tour builder
|
||
│ ├── dashboard.tsx # Admin home
|
||
│ ├── [entity]/ # 13 entity directories
|
||
│ │ ├── [entityId].tsx # Dynamic route
|
||
│ │ ├── [entity]-list.tsx # List page
|
||
│ │ ├── [entity]-new.tsx # Create page
|
||
│ │ ├── [entity]-edit.tsx # Edit page
|
||
│ │ ├── [entity]-view.tsx # View page
|
||
│ │ └── [entity]-table.tsx# Embedded table
|
||
│ └── ... # Auth, profile, search, etc.
|
||
│
|
||
├── components/ # 193 files - React components
|
||
│ ├── [Entity]/ # 13 entity component directories
|
||
│ │ ├── Table[Entity].tsx # DataGrid wrapper
|
||
│ │ ├── configure[Entity]Cols.tsx # Column config
|
||
│ │ ├── Card[Entity].tsx # Card view
|
||
│ │ └── List[Entity].tsx # List view
|
||
│ ├── Constructor/ # 15 files - Tour builder components
|
||
│ ├── ElementSettings/ # 23 files - Element configuration
|
||
│ ├── UiElements/ # 16 files - Unified element rendering (shared by Constructor + Runtime)
|
||
│ ├── Offline/ # 5 files - PWA components
|
||
│ ├── Generic/ # 3 files - Reusable table/form
|
||
│ ├── DataGrid/ # 1 file - Column config factory
|
||
│ ├── Factory/ # 1 file - Table component factory
|
||
│ ├── Uploaders/ # 1 file - Upload service
|
||
│ └── *.tsx # ~50 standalone components
|
||
│
|
||
├── hooks/ # 32 files - Custom React hooks
|
||
│ ├── index.ts # Re-exports
|
||
│ ├── usePreloadOrchestrator.ts # Asset preloading (26KB)
|
||
│ ├── useTransitionPlayback.ts # Video transitions (23KB)
|
||
│ ├── usePageSwitch.ts # Page navigation (14KB)
|
||
│ ├── useConstructorElements.ts # Element CRUD (12KB)
|
||
│ └── ... # 26 more hooks
|
||
│
|
||
├── stores/ # Redux state
|
||
│ ├── store.ts # Store configuration
|
||
│ ├── hooks.ts # useAppSelector, useAppDispatch
|
||
│ ├── createEntitySlice.ts # Entity slice factory (10KB)
|
||
│ ├── authSlice.ts # Authentication state
|
||
│ ├── mainSlice.ts # UI state
|
||
│ ├── styleSlice.ts # Theme state
|
||
│ └── [entity]/ # 13 entity slice directories
|
||
│ └── [entity]Slice.ts # Generated via factory
|
||
│
|
||
├── lib/ # 20 files - Utility libraries
|
||
│ ├── offline/ # PWA storage layer
|
||
│ │ ├── StorageManager.ts # Cache API + IndexedDB
|
||
│ │ ├── DownloadManager.ts# Download orchestration
|
||
│ │ └── DownloadEventBus.ts # Progress events
|
||
│ ├── offlineDb/ # IndexedDB layer
|
||
│ │ ├── OfflineDbManager.ts # Dexie wrapper
|
||
│ │ └── schema.ts # DB schema
|
||
│ ├── assetUrl.ts # Presigned URL management
|
||
│ ├── elementDefaults.ts # Default element configs
|
||
│ ├── elementStyles.ts # CSS generation
|
||
│ ├── elementEffects.ts # Animation effects
|
||
│ ├── constructorHelpers.ts # Canvas utilities
|
||
│ ├── navigationHelpers.ts # Link resolution
|
||
│ ├── extractPageLinks.ts # Parse links from schema
|
||
│ ├── imagePreDecode.ts # Image pre-decoding
|
||
│ ├── mediaDuration.ts # Media duration extraction
|
||
│ ├── mediaHelpers.ts # Media URL handling
|
||
│ ├── parseJson.ts # Safe JSON parsing
|
||
│ ├── logger.ts # Structured logging
|
||
│ ├── slugHelpers.ts # Slug generation
|
||
│ └── tourFlowHelpers.ts # Page ordering
|
||
│
|
||
├── types/ # 12 files - TypeScript definitions
|
||
│ ├── constructor.ts # Canvas/element types
|
||
│ ├── entities.ts # Entity interfaces
|
||
│ ├── runtime.ts # Presentation runtime
|
||
│ ├── preload.ts # Preloading state
|
||
│ ├── presentation.ts # Navigation/transitions
|
||
│ ├── offline.ts # PWA/cache types
|
||
│ ├── permissions.ts # RBAC types
|
||
│ ├── forms.ts # Form field types
|
||
│ ├── filters.ts # Data filtering
|
||
│ ├── api.ts # API response types
|
||
│ ├── redux.ts # Store types
|
||
│ └── index.ts # Re-exports
|
||
│
|
||
├── factories/ # 3 files - Page generators
|
||
│ ├── createListPage.tsx # List page factory
|
||
│ ├── createFormPage.tsx # Form page factory
|
||
│ └── index.ts # Re-exports
|
||
│
|
||
├── schemas/ # 6 files - Validation schemas
|
||
│ ├── userSchema.ts # User validation
|
||
│ ├── assetSchema.ts # Asset validation
|
||
│ ├── projectSchema.ts # Project validation
|
||
│ ├── tourPageSchema.ts # Tour page validation
|
||
│ ├── roleSchema.ts # Role validation
|
||
│ └── index.ts # Re-exports
|
||
│
|
||
├── helpers/ # 6 files - Utility functions
|
||
│ ├── dataFormatter.js # Data formatting
|
||
│ ├── textFormatters.ts # Text formatting
|
||
│ ├── userPermissions.ts # Permission checking
|
||
│ ├── notifyStateHandler.ts # Toast notifications
|
||
│ ├── humanize.ts # Human-readable strings
|
||
│ └── fileSaver.ts # File download
|
||
│
|
||
├── layouts/ # 2 files - Page layouts
|
||
│ ├── Authenticated.tsx # Auth layout with nav
|
||
│ └── Guest.tsx # Public layout
|
||
│
|
||
├── config/ # 2 files - Configuration
|
||
│ ├── preload.config.ts # Preload settings
|
||
│ └── offline.config.ts # PWA settings
|
||
│
|
||
├── context/ # 1 file - React Context
|
||
│ └── DownloadContext.tsx # PWA download progress
|
||
│
|
||
├── interfaces/ # 1 file - Shared interfaces
|
||
│ └── index.ts # Common UI interfaces
|
||
│
|
||
└── css/ # Stylesheets
|
||
└── _theme.css # Tailwind theme customization
|
||
```
|
||
|
||
---
|
||
|
||
## Module Details
|
||
|
||
### 1. Pages Module (99 files)
|
||
|
||
#### Entity CRUD Pages (78 files)
|
||
Each of the 13 entities has 6 standardized pages:
|
||
|
||
| Page Pattern | Purpose | Factory/Hook |
|
||
|--------------|---------|--------------|
|
||
| `[entity]-list.tsx` | List with filters, pagination, CSV export | `createListPage` factory |
|
||
| `[entity]-new.tsx` | Create form with validation | Formik + entity schema |
|
||
| `[entity]-edit.tsx` | Edit form with data sync | `useEditPageSync` hook |
|
||
| `[entity]-view.tsx` | Read-only display | Direct entity fetch |
|
||
| `[entity]-table.tsx` | Embedded table view | `createTableComponent` |
|
||
| `[entityId].tsx` | Dynamic route redirect | Redirects to -view |
|
||
|
||
**Entities:** users, roles, permissions, projects, project_memberships, assets, asset_variants, presigned_url_requests, tour_pages, project_audio_tracks, publish_events, pwa_caches, access_logs
|
||
|
||
#### Special Pages (21 files)
|
||
|
||
| Page | Size | Description |
|
||
|------|------|-------------|
|
||
| `index.tsx` | 1KB | Root redirect to login or projects list |
|
||
| `constructor.tsx` | 47KB | Visual tour builder with canvas, drag-drop, element editing |
|
||
| `dashboard.tsx` | 6KB | Admin home with entity counts, quick actions |
|
||
| `p/[projectSlug]/index.tsx` | 2KB | Public production presentation (wraps RuntimePresentation) |
|
||
| `p/[projectSlug]/stage.tsx` | 2KB | Stage preview presentation |
|
||
| `_app.tsx` | 11KB | App entry, providers, interceptors |
|
||
| `login.tsx` | 8KB | Authentication with OAuth options |
|
||
| `forgot.tsx` | 3KB | Password reset request |
|
||
| `profile.tsx` | 6KB | User profile management |
|
||
| `element-type-defaults.tsx` | 4KB | Global element defaults editor |
|
||
| `project-element-defaults.tsx` | 6KB | Project-level element overrides |
|
||
| `search.tsx` | 3KB | Global search results |
|
||
|
||
---
|
||
|
||
### 2. Components Module (193 files)
|
||
|
||
#### Entity Components (78 files, 13 directories)
|
||
|
||
Each entity directory contains:
|
||
|
||
| File Pattern | Purpose |
|
||
|--------------|---------|
|
||
| `Table[Entity].tsx` | MUI DataGrid wrapper with actions |
|
||
| `configure[Entity]Cols.tsx` | Column definitions using configBuilderFactory |
|
||
| `Card[Entity].tsx` | Card view for single entity |
|
||
| `List[Entity].tsx` | List view variant |
|
||
| `useAssetUploader.ts` | (Assets only) Upload hook |
|
||
| `ProjectSelector.tsx` | (Assets only) Project filter |
|
||
|
||
#### Constructor Components (15 files)
|
||
|
||
| Component | Size | Description |
|
||
|-----------|------|-------------|
|
||
| `ElementEditorPanel.tsx` | 22KB | Right panel for element editing |
|
||
| `ConstructorToolbar.tsx` | ~19KB | Floating main toolbar with mode, Page actions, Elements actions, save/stage/exit controls |
|
||
| `ConstructorMenu.tsx` | 5KB | Legacy/collapsible constructor menu component |
|
||
| `ConstructorControlsPanel.tsx` | 2KB | Legacy/secondary constructor controls |
|
||
| `CanvasElement.tsx` | 3KB | Draggable element on canvas |
|
||
| `CanvasBackground.tsx` | 3KB | Background image/video layer |
|
||
| `CreateTransitionForm.tsx` | 3KB | Transition configuration modal |
|
||
| `TransitionPreviewOverlay.tsx` | 1KB | Transition video preview |
|
||
| `PageSelector.tsx` | 1KB | Page dropdown selector |
|
||
| `InteractionModeToggle.tsx` | 2KB | Edit/interact mode toggle |
|
||
| `AssetSelectCompact.tsx` | 2KB | Compact asset picker |
|
||
| `BackgroundSettingsEditor.tsx` | 2KB | Background configuration |
|
||
| `ElementEditorHeader.tsx` | 1KB | Editor panel header |
|
||
| `MenuActionButton.tsx` | 1KB | Menu button component |
|
||
| `types.ts` | 7KB | Constructor type definitions |
|
||
| `index.ts` | 0.3KB | Re-exports |
|
||
|
||
#### ElementSettings Components (23 files)
|
||
|
||
Settings panels for different element aspects:
|
||
|
||
| Component | Description |
|
||
|-----------|-------------|
|
||
| `StyleSettingsSection.tsx` | Position, size, colors, borders |
|
||
| `StyleSettingsSectionCompact.tsx` | Compact version for constructor |
|
||
| `NavigationSettingsSection.tsx` | Link targets, transitions |
|
||
| `NavigationSettingsSectionCompact.tsx` | Compact version |
|
||
| `EffectsSettingsSection.tsx` | Animations, hover effects |
|
||
| `EffectsSettingsSectionCompact.tsx` | Compact version |
|
||
| `CarouselSettingsSection.tsx` | Gallery/carousel configuration |
|
||
| `GallerySettingsSection.tsx` | Image gallery settings |
|
||
| `MediaSettingsSection.tsx` | Video/audio player settings |
|
||
| `MediaSettingsSectionCompact.tsx` | Compact version |
|
||
| `TooltipSettingsSection.tsx` | Tooltip configuration |
|
||
| `TooltipSettingsSectionCompact.tsx` | Compact version |
|
||
| `DescriptionSettingsSection.tsx` | Text content settings |
|
||
| `DescriptionSettingsSectionCompact.tsx` | Compact version |
|
||
| `CommonSettingsSection.tsx` | Shared element settings |
|
||
| `CommonSettingsSectionCompact.tsx` | Compact version |
|
||
| `GallerySettingsSection.tsx` | Gallery settings |
|
||
| `GallerySettingsSectionCompact.tsx` | Compact version |
|
||
| `GalleryCarouselSettingsSectionCompact.tsx` | Gallery carousel settings |
|
||
| `ElementSettingsTabs.tsx` | Tab navigation |
|
||
| `useElementSettingsForm.ts` | Form state management hook |
|
||
| `types.ts` | Type definitions |
|
||
| `index.ts` | Re-exports |
|
||
|
||
#### UiElements Components (16 files)
|
||
|
||
Unified element rendering shared by both Constructor (CanvasElement) and Runtime (RuntimeElement):
|
||
|
||
| Component | Description |
|
||
|-----------|-------------|
|
||
| `UiElementRenderer.tsx` | Main entry point - delegates to per-type components |
|
||
| `shared/useElementWrapperStyle.ts` | Shared hook for consistent wrapper styling |
|
||
| `elements/NavigationElement.tsx` | Navigation button (next/prev) |
|
||
| `elements/GalleryElement.tsx` | Image gallery grid |
|
||
| `elements/TooltipElement.tsx` | Tooltip with icon |
|
||
| `elements/DescriptionElement.tsx` | Title + text block |
|
||
| `elements/CarouselElement.tsx` | Image carousel with navigation |
|
||
| `elements/LogoElement.tsx` | Logo display |
|
||
| `elements/SpotElement.tsx` | Hotspot/clickable area |
|
||
| `elements/VideoPlayerElement.tsx` | Embedded video player |
|
||
| `elements/AudioPlayerElement.tsx` | Embedded audio player |
|
||
| `elements/PopupElement.tsx` | Popup/modal dialog |
|
||
| `GalleryCarouselOverlay.tsx` | Gallery/carousel fullscreen overlay |
|
||
| `ElementPreview.tsx` | Preview element in constructor |
|
||
| `defaults.ts` | Default element configurations |
|
||
| `types.ts` | Element type definitions |
|
||
|
||
#### Offline Components (5 files)
|
||
|
||
| Component | Description |
|
||
|-----------|-------------|
|
||
| `DownloadProgressPanel.tsx` | Shows download progress for PWA |
|
||
| `OfflineToggle.tsx` | Enable/disable offline mode |
|
||
| `StorageUsageDisplay.tsx` | Shows storage quota usage |
|
||
| `OfflineStatusIndicator.tsx` | Online/offline status badge |
|
||
| `index.ts` | Re-exports |
|
||
|
||
#### Factory Components (2 files)
|
||
|
||
| Component | Description |
|
||
|-----------|-------------|
|
||
| `createTableComponent.tsx` | Factory that generates table wrapper components |
|
||
| `configBuilderFactory.tsx` | Factory that generates DataGrid column configurations |
|
||
|
||
#### Generic Components (3 files)
|
||
|
||
| Component | Size | Description |
|
||
|-----------|------|-------------|
|
||
| `GenericTable.tsx` | 14KB | Reusable DataGrid with filters, pagination |
|
||
| `GenericFormField.tsx` | 6KB | Reusable form field component |
|
||
| `index.ts` | 0.2KB | Re-exports |
|
||
|
||
#### Standalone Components (~50 files)
|
||
|
||
| Category | Components |
|
||
|----------|------------|
|
||
| **Layout** | `NavBar`, `NavBarItem`, `FooterBar`, `AsideMenu`, `AsideMenuItem`, `AsideMenuLayer`, `AsideMenuList` |
|
||
| **Cards** | `CardBox`, `CardBoxModal`, `CardBoxComponentBody`, `CardBoxComponentTitle`, `CardBoxComponentFooter`, `CardBoxComponentEmpty` |
|
||
| **Forms** | `FormField`, `FormFieldCompact`, `FormFilePicker`, `FormImagePicker`, `FormCheckRadio`, `FormCheckRadioGroup` |
|
||
| **Buttons** | `BaseButton`, `BaseButtons`, `BaseIcon`, `BaseDivider` |
|
||
| **Data** | `DataGridMultiSelect`, `SelectField`, `SelectFieldMany`, `SwitchField`, `RichTextField`, `ImageField` |
|
||
| **Sections** | `SectionMain`, `SectionFullScreen`, `SectionTitle`, `SectionTitleLineWithButton` |
|
||
| **User** | `UserAvatar`, `UserAvatarCurrentUser`, `UserCard`, `IconRounded` |
|
||
| **Utils** | `Pagination`, `Search`, `SearchResults`, `LoadingSpinner`, `NotificationBar`, `OverlayLayer`, `ClickOutside` |
|
||
| **Auth** | `PasswordSetOrReset` |
|
||
| **Features** | `TourFlowManager`, `RuntimePresentation`, `RuntimeElement`, `DevModeBadge`, `IntroGuide`, `LanguageSwitcher`, `ErrorBoundary`, `DragDropFilePicker`, `ListActionsPopover` |
|
||
|
||
---
|
||
|
||
### 3. Hooks Module (32 files)
|
||
|
||
#### Runtime/Preloading Hooks (8 hooks)
|
||
|
||
| Hook | Size | Description | Used By |
|
||
|------|------|-------------|---------|
|
||
| `usePreloadOrchestrator` | 26KB | Coordinates asset preloading with priority queue, blob URL caching | RuntimePresentation |
|
||
| `useTransitionPlayback` | 23KB | Manages video transition playback (forward/reverse) | RuntimePresentation |
|
||
| `usePageSwitch` | 14KB | Handles page navigation with preloaded assets | RuntimePresentation |
|
||
| `useReversePlayback` | 11KB | Reverse video playback for back navigation | useTransitionPlayback |
|
||
| `useNeighborGraph` | 8KB | Builds navigation graph for preload prioritization | usePreloadOrchestrator |
|
||
| `usePageDataLoader` | 7KB | Loads project and pages data with caching | RuntimePresentation |
|
||
| `usePreloadProgress` | 6KB | Tracks preload progress percentages | RuntimePresentation |
|
||
| `useBackgroundTransition` | 5KB | Fade-out animation during page transitions | RuntimePresentation |
|
||
|
||
#### Constructor Hooks (7 hooks)
|
||
|
||
| Hook | Size | Description | Used By |
|
||
|------|------|-------------|---------|
|
||
| `useConstructorElements` | 12KB | Element CRUD operations on canvas | constructor.tsx |
|
||
| `useConstructorPageActions` | 10KB | Page management (create, delete, reorder) | constructor.tsx |
|
||
| `useMediaDurationProbe` | 6KB | Extracts duration from video/audio files | constructor.tsx |
|
||
| `useTransitionPreview` | 6KB | Previews transition videos | constructor.tsx |
|
||
| `useDraggable` | 6KB | Generic drag functionality | CanvasElement |
|
||
| `useIconPreload` | 5KB | Preloads icon assets | constructor.tsx |
|
||
| `useCanvasElementDrag` | 4KB | Canvas-specific element dragging | CanvasElement |
|
||
| `useCanvasElapsedTime` | 3KB | Animation timing for canvas | constructor.tsx |
|
||
|
||
#### Offline/PWA Hooks (4 hooks)
|
||
|
||
| Hook | Size | Description | Used By |
|
||
|------|------|-------------|---------|
|
||
| `useOfflineMode` | 11KB | Detects and manages offline state | _app.tsx, Offline components |
|
||
| `usePWAPreload` | 5KB | Preloads assets for PWA mode | RuntimePresentation |
|
||
| `useNetworkAware` | 5KB | Network quality detection | usePreloadOrchestrator |
|
||
| `useStorageQuota` | 3KB | Monitors storage usage | StorageUsageDisplay |
|
||
|
||
#### Form/Table Hooks (4 hooks)
|
||
|
||
| Hook | Size | Description | Used By |
|
||
|------|------|-------------|---------|
|
||
| `useEntityTable` | 8KB | Table state management (pagination, sorting, filters) | All entity tables |
|
||
| `useEditPageSync` | 5KB | Syncs form data with Redux on edit pages | All -edit pages |
|
||
| `useFilterItems` | 5KB | Filter state management | createListPage |
|
||
| `useFormSync` | 3KB | Form state synchronization | Form components |
|
||
|
||
#### Utility Hooks (8 hooks)
|
||
|
||
| Hook | Size | Description | Used By |
|
||
|------|------|-------------|---------|
|
||
| `useDashboardCounts` | 8KB | Fetches entity counts for dashboard | dashboard.tsx |
|
||
| `useElementEffects` | 3KB | Applies element animation effects | RuntimeElement |
|
||
| `useCSVHandling` | 4KB | CSV import/export | List pages |
|
||
| `useOutsideClick` | 3KB | Detects clicks outside element | Modals, dropdowns |
|
||
| `usePageNavigation` | 5KB | Page navigation state | RuntimePresentation |
|
||
| `useProjectAssets` | 3KB | Fetches and manages project assets | Projects pages |
|
||
| `useDevCompilationStatus` | 1KB | Hot reload status indicator | DevModeBadge |
|
||
|
||
---
|
||
|
||
### 4. Stores Module (22 files)
|
||
|
||
#### Store Configuration
|
||
|
||
| File | Description |
|
||
|------|-------------|
|
||
| `store.ts` | Redux store configuration with all slices |
|
||
| `hooks.ts` | Typed hooks: `useAppSelector`, `useAppDispatch` |
|
||
| `createEntitySlice.ts` | Factory for generating entity slices |
|
||
| `introSteps.ts` | Tour guide step definitions |
|
||
|
||
#### Core Slices
|
||
|
||
| Slice | Size | State |
|
||
|-------|------|-------|
|
||
| `authSlice.ts` | 4KB | `{ token, currentUser, permissions, loading, error }` |
|
||
| `mainSlice.ts` | 1KB | `{ isAsideMobileExpanded, isAsideLgActive, darkMode }` |
|
||
| `styleSlice.ts` | 3KB | `{ asideStyle, navBarStyle, footerStyle, ... }` |
|
||
| `usersSlice.ts` | 3KB | Extended user slice with password reset actions |
|
||
|
||
#### Entity Slices (13)
|
||
|
||
Generated via `createEntitySlice` factory, each provides:
|
||
|
||
```typescript
|
||
interface EntityState<T> {
|
||
rows: T[];
|
||
row: T | null;
|
||
loading: boolean;
|
||
error: string | null;
|
||
count: number;
|
||
filters: FilterState;
|
||
}
|
||
|
||
// Async thunks
|
||
fetch({ query: string }) // GET /api/[entity]?...
|
||
findById(id: string) // GET /api/[entity]/:id
|
||
create(data: T) // POST /api/[entity]
|
||
update({ id, data }) // PUT /api/[entity]/:id
|
||
deleteItem(id: string) // DELETE /api/[entity]/:id
|
||
```
|
||
|
||
---
|
||
|
||
### 5. Library Module (20 files)
|
||
|
||
#### Offline Storage (lib/offline/)
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `StorageManager.ts` | 7KB | Dual storage abstraction (Cache API < 5MB, IndexedDB >= 5MB) |
|
||
| `DownloadManager.ts` | 12KB | Download orchestration with retry, progress |
|
||
| `DownloadEventBus.ts` | 5KB | Event system for download progress (Observer pattern) |
|
||
|
||
#### IndexedDB (lib/offlineDb/)
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `OfflineDbManager.ts` | 8KB | Dexie.js wrapper for large asset storage |
|
||
| `schema.ts` | 1KB | IndexedDB schema: `assets { url, blob, size, timestamp }` |
|
||
|
||
#### Element Utilities
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `elementDefaults.ts` | 18KB | Default configurations for all 11 element types |
|
||
| `elementStyles.ts` | 3KB | Generates inline CSS from element config |
|
||
| `elementEffects.ts` | 6KB | Animation effect definitions and application |
|
||
| `fonts.ts` | 2KB | Font family definitions and mappings |
|
||
|
||
#### Asset Utilities
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `assetUrl.ts` | 10KB | Presigned URL management, expiry tracking, refresh |
|
||
| `imagePreDecode.ts` | 6KB | Pre-decodes images for smooth transitions |
|
||
| `mediaDuration.ts` | 3KB | Extracts duration from video/audio elements |
|
||
| `mediaHelpers.ts` | 4KB | Media URL normalization, type detection |
|
||
|
||
#### Navigation Utilities
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `navigationHelpers.ts` | 4KB | `resolveNavigationTarget()`, `isTransitionBlocking()` |
|
||
| `extractPageLinks.ts` | 6KB | Parses navigation links from `ui_schema_json` |
|
||
|
||
#### Constructor Utilities
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `constructorHelpers.ts` | 8KB | Canvas manipulation, element positioning |
|
||
| `slugHelpers.ts` | 2KB | URL slug generation for pages |
|
||
| `tourFlowHelpers.ts` | 3KB | Page ordering, drag-drop reordering |
|
||
|
||
#### General Utilities
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `parseJson.ts` | 3KB | Safe JSON parsing with fallbacks |
|
||
| `logger.ts` | 4KB | Structured logging (console in dev, silent in prod) |
|
||
|
||
---
|
||
|
||
### 6. Types Module (12 files)
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `constructor.ts` | 10KB | Canvas element, page, selection types |
|
||
| `entities.ts` | 7KB | All 13 entity interfaces |
|
||
| `runtime.ts` | 2KB | Runtime presentation state types |
|
||
| `preload.ts` | 1KB | Preload queue, progress types |
|
||
| `presentation.ts` | 2KB | Navigation, transition types |
|
||
| `offline.ts` | 4KB | PWA cache, download types |
|
||
| `permissions.ts` | 4KB | RBAC permission types |
|
||
| `forms.ts` | 2KB | Form field, validation types |
|
||
| `filters.ts` | 2KB | Data filter types |
|
||
| `api.ts` | 1KB | API response types |
|
||
| `redux.ts` | 1KB | Store, dispatch types |
|
||
| `index.ts` | 0.3KB | Re-exports |
|
||
|
||
---
|
||
|
||
### 7. Factories Module (3 files)
|
||
|
||
| Factory | Size | Description |
|
||
|---------|------|-------------|
|
||
| `createListPage.tsx` | 6KB | Generates list pages with filters, CSV, pagination |
|
||
| `createFormPage.tsx` | 9KB | Generates form pages with validation |
|
||
| `index.ts` | 0.1KB | Re-exports |
|
||
|
||
**createListPage Usage:**
|
||
```typescript
|
||
export default createListPage({
|
||
entityName: 'assets',
|
||
entityNamePlural: 'Assets',
|
||
permissionPrefix: 'ASSETS',
|
||
columns: configureAssetsCols,
|
||
filterFields: ['name', 'type', 'status'],
|
||
});
|
||
```
|
||
|
||
**createFormPage Usage:**
|
||
```typescript
|
||
export default createFormPage({
|
||
entityName: 'assets',
|
||
schema: assetSchema,
|
||
fields: ['name', 'file', 'project'],
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
### 8. Schemas Module (6 files)
|
||
|
||
Formik/Yup validation schemas:
|
||
|
||
| Schema | Fields Validated |
|
||
|--------|-----------------|
|
||
| `userSchema.ts` | email, firstName, lastName, password, role |
|
||
| `assetSchema.ts` | name, file, type, project |
|
||
| `projectSchema.ts` | name, slug, description |
|
||
| `tourPageSchema.ts` | name, slug, order, background |
|
||
| `roleSchema.ts` | name, permissions |
|
||
| `index.ts` | Re-exports |
|
||
|
||
---
|
||
|
||
### 9. Helpers Module (6 files)
|
||
|
||
| Helper | Description |
|
||
|--------|-------------|
|
||
| `dataFormatter.js` | Format dates, numbers, booleans for display |
|
||
| `textFormatters.ts` | Truncate, capitalize, slugify text |
|
||
| `userPermissions.ts` | `hasPermission()`, `canAccess()` utilities |
|
||
| `notifyStateHandler.ts` | Toast notification triggers |
|
||
| `humanize.ts` | Convert snake_case to readable text |
|
||
| `fileSaver.ts` | Trigger file downloads |
|
||
|
||
---
|
||
|
||
### 10. Layouts Module (2 files)
|
||
|
||
| Layout | Description |
|
||
|--------|-------------|
|
||
| `Authenticated.tsx` | Full layout with JWT validation, permission checks, NavBar, AsideMenu, FooterBar, IntroGuide |
|
||
| `Guest.tsx` | Minimal layout for public pages (login, password reset, public presentations) |
|
||
|
||
**Per-Page Layout Pattern:**
|
||
```typescript
|
||
UsersListPage.getLayout = (page: ReactElement) => (
|
||
<LayoutAuthenticated permission="READ_USERS">
|
||
{page}
|
||
</LayoutAuthenticated>
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
### 11. Config Module (2 files)
|
||
|
||
| Config | Settings |
|
||
|--------|----------|
|
||
| `preload.config.ts` | Priority weights, batch sizes, concurrent limits |
|
||
| `offline.config.ts` | Cache names, storage thresholds, expiry times |
|
||
|
||
**Preload Priority Weights:**
|
||
```typescript
|
||
export const PRELOAD_PRIORITY = {
|
||
TRANSITION_VIDEO: 150, // Highest - needed for navigation
|
||
IMAGE: 100,
|
||
AUDIO: 50,
|
||
VIDEO: 30, // Lowest - large files
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### 12. Context Module (1 file)
|
||
|
||
| Context | Description |
|
||
|---------|-------------|
|
||
| `DownloadContext.tsx` | PWA download progress tracking, shared across components |
|
||
|
||
**Usage:**
|
||
```typescript
|
||
const { progress, isDownloading, startDownload, cancelDownload } = useDownloadContext();
|
||
```
|
||
|
||
---
|
||
|
||
## Design Patterns
|
||
|
||
### 1. Factory Pattern
|
||
|
||
**Eliminates ~80% boilerplate code:**
|
||
|
||
| Factory | Generates | Files Eliminated |
|
||
|---------|-----------|-----------------|
|
||
| `createEntitySlice` | Redux slices with CRUD thunks | 13 × 200 LOC = 2600 LOC |
|
||
| `createListPage` | List pages with filters, pagination | 13 × 150 LOC = 1950 LOC |
|
||
| `createFormPage` | Form pages with validation | 13 × 180 LOC = 2340 LOC |
|
||
| `createTableComponent` | Table wrapper components | 13 × 50 LOC = 650 LOC |
|
||
| `configBuilderFactory` | Column configurations | 13 × 80 LOC = 1040 LOC |
|
||
|
||
**Total: ~8500 LOC eliminated through factories**
|
||
|
||
### 2. Custom Hook Pattern
|
||
|
||
Hooks are composed hierarchically:
|
||
|
||
```
|
||
usePreloadOrchestrator
|
||
├── useNeighborGraph (build priority queue)
|
||
├── useNetworkAware (adjust batch size)
|
||
└── Internal: presigned URL fetching, blob caching
|
||
|
||
usePageSwitch
|
||
├── usePreloadOrchestrator.getReadyBlobUrl()
|
||
└── useBackgroundTransition (fade animation)
|
||
|
||
useTransitionPlayback
|
||
├── useReversePlayback (back navigation)
|
||
└── Internal: video element management
|
||
```
|
||
|
||
### 3. HOC via getLayout
|
||
|
||
Per-page layout injection without wrapper components:
|
||
|
||
```typescript
|
||
// Page defines its layout
|
||
MyPage.getLayout = (page) => (
|
||
<LayoutAuthenticated permission="READ_ASSETS">
|
||
{page}
|
||
</LayoutAuthenticated>
|
||
);
|
||
|
||
// _app.tsx applies it
|
||
const getLayout = Component.getLayout ?? ((page) => page);
|
||
return getLayout(<Component {...pageProps} />);
|
||
```
|
||
|
||
### 4. Repository Pattern
|
||
|
||
Entity slices abstract all API calls:
|
||
|
||
```typescript
|
||
// Component only knows about Redux actions
|
||
dispatch(fetch({ query: '?limit=100' }));
|
||
dispatch(create(newAsset));
|
||
dispatch(update({ id, data: changes }));
|
||
dispatch(deleteItem(id));
|
||
|
||
// Slice handles API communication
|
||
const fetch = createAsyncThunk('assets/fetch', async ({ query }) => {
|
||
const response = await axios.get(`/api/assets${query}`);
|
||
return response.data;
|
||
});
|
||
```
|
||
|
||
### 5. Observer Pattern
|
||
|
||
Download progress events:
|
||
|
||
```typescript
|
||
// DownloadEventBus.ts
|
||
class DownloadEventBus {
|
||
private listeners: Map<string, Set<Callback>>;
|
||
|
||
emit(event: 'progress' | 'complete' | 'error', data: any) {
|
||
this.listeners.get(event)?.forEach(cb => cb(data));
|
||
}
|
||
|
||
on(event: string, callback: Callback) {
|
||
this.listeners.get(event)?.add(callback);
|
||
}
|
||
}
|
||
|
||
// Consumer
|
||
downloadEventBus.on('progress', ({ url, percent }) => {
|
||
setProgress(prev => ({ ...prev, [url]: percent }));
|
||
});
|
||
```
|
||
|
||
### 6. Strategy Pattern
|
||
|
||
Storage selection based on file size:
|
||
|
||
```typescript
|
||
// StorageManager.ts
|
||
class StorageManager {
|
||
async store(url: string, blob: Blob) {
|
||
if (blob.size < 5 * 1024 * 1024) { // < 5MB
|
||
return this.cacheApiStore(url, blob); // Fast, limited
|
||
} else {
|
||
return this.indexedDbStore(url, blob); // Slow, unlimited
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Key Flows
|
||
|
||
### 1. Runtime Presentation Flow
|
||
|
||
```
|
||
User navigates to /p/[slug]
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ usePageDataLoader │
|
||
│ • Fetch project by slug │
|
||
│ • Fetch pages for environment │
|
||
│ • Determine initial page │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ usePreloadOrchestrator │
|
||
│ • Build neighbor graph │
|
||
│ • Calculate priorities │
|
||
│ • Request presigned URLs │
|
||
│ • Download assets to cache │
|
||
│ • Pre-decode images │
|
||
│ • Store blob URLs │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ RuntimePresentation renders │
|
||
│ • Background (image/video) │
|
||
│ • RuntimeElement for each element │
|
||
│ └── UiElementRenderer │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ User clicks navigation element │
|
||
│ • resolveNavigationTarget() │
|
||
│ • isTransitionBlocking() │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ usePageSwitch │
|
||
│ • Get blob URL from cache (O(1)) │
|
||
│ • useBackgroundTransition() │
|
||
│ • If transition video: │
|
||
│ useTransitionPlayback() │
|
||
│ • Switch to new page │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### 2. Constructor Flow
|
||
|
||
```
|
||
User opens /constructor?projectId=X
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ Fetch project and pages │
|
||
│ • Redux: projects.findById() │
|
||
│ • Redux: tour_pages.fetch() │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ useConstructorElements │
|
||
│ • Parse ui_schema_json │
|
||
│ • Initialize element state │
|
||
│ • Provide CRUD methods │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ Canvas renders │
|
||
│ • CanvasBackground │
|
||
│ • CanvasElement for each element │
|
||
│ • useCanvasElementDrag │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ User edits element │
|
||
│ • ElementEditorPanel opens │
|
||
│ • useElementSettingsForm │
|
||
│ • Settings sections render │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ Save changes │
|
||
│ • Update ui_schema_json │
|
||
│ • Redux: tour_pages.update() │
|
||
│ • API: PUT /api/tour_pages/:id │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### 3. Offline/PWA Flow
|
||
|
||
```
|
||
User enables offline mode
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ DownloadManager.startDownload() │
|
||
│ • Get asset manifest │
|
||
│ • Request presigned URLs │
|
||
│ • Queue downloads │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ For each asset: │
|
||
│ • Fetch with progress tracking │
|
||
│ • DownloadEventBus.emit() │
|
||
│ • StorageManager.store() │
|
||
│ - Cache API (< 5MB) │
|
||
│ - IndexedDB (>= 5MB) │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ Service worker intercepts │
|
||
│ • Check Cache API │
|
||
│ • Check IndexedDB │
|
||
│ • Return cached response │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Entity Architecture
|
||
|
||
Each entity follows a consistent structure:
|
||
|
||
```
|
||
[Entity] (e.g., Assets)
|
||
│
|
||
├── pages/assets/
|
||
│ ├── [assetsId].tsx # Dynamic route → view
|
||
│ ├── assets-list.tsx # List with filters
|
||
│ ├── assets-new.tsx # Create form
|
||
│ ├── assets-edit.tsx # Edit form
|
||
│ ├── assets-view.tsx # Read-only view
|
||
│ └── assets-table.tsx # Embedded table
|
||
│
|
||
├── components/Assets/
|
||
│ ├── TableAssets.tsx # DataGrid wrapper
|
||
│ ├── configureAssetsCols.tsx # Column definitions
|
||
│ ├── CardAssets.tsx # Card view
|
||
│ ├── ListAssets.tsx # List view
|
||
│ ├── useAssetUploader.ts # Upload hook (assets only)
|
||
│ └── ProjectSelector.tsx # Filter component
|
||
│
|
||
├── stores/assets/
|
||
│ └── assetsSlice.ts # Redux slice via factory
|
||
│
|
||
└── schemas/
|
||
└── assetSchema.ts # Validation schema
|
||
```
|
||
|
||
**13 Entities:**
|
||
- users, roles, permissions
|
||
- projects, project_memberships
|
||
- assets, asset_variants, presigned_url_requests
|
||
- tour_pages, project_audio_tracks
|
||
- publish_events, pwa_caches, access_logs
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
### Next.js Config (`next.config.mjs`)
|
||
|
||
```javascript
|
||
const nextConfig = {
|
||
reactStrictMode: true,
|
||
|
||
typescript: {
|
||
ignoreBuildErrors: false, // Enforce type checking
|
||
},
|
||
|
||
eslint: {
|
||
ignoreDuringBuilds: false, // Enforce linting
|
||
},
|
||
|
||
images: {
|
||
domains: ['cdn.platform.com', 's3.amazonaws.com'],
|
||
},
|
||
|
||
// PWA via Serwist
|
||
// Turbopack enabled for dev
|
||
};
|
||
```
|
||
|
||
### Tailwind Config
|
||
|
||
Theme customization in `css/_theme.css`:
|
||
|
||
```css
|
||
/* Sidebar styling */
|
||
#asideMenu {
|
||
@apply bg-gray-900 text-white;
|
||
}
|
||
|
||
/* Theme variants */
|
||
.theme-pink .card {
|
||
@apply border-pink-500;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Performance Optimizations
|
||
|
||
### 1. Asset Preloading
|
||
|
||
- **Priority Queue:** Transition videos > Images > Audio > Video
|
||
- **Batch Fetching:** Max 50 presigned URLs per request
|
||
- **Network Awareness:** Reduce batch size on slow connections
|
||
- **Blob URL Caching:** O(1) lookup during navigation
|
||
|
||
### 2. Image Pre-Decoding
|
||
|
||
```typescript
|
||
// imagePreDecode.ts
|
||
export async function preDecodeImage(blobUrl: string): Promise<void> {
|
||
const img = new Image();
|
||
img.src = blobUrl;
|
||
await img.decode(); // Decode before display
|
||
}
|
||
```
|
||
|
||
### 3. Lazy Loading
|
||
|
||
- Route-based code splitting (Next.js automatic)
|
||
- Dynamic imports for large components
|
||
|
||
### 4. Redux Optimization
|
||
|
||
- Normalized entity state
|
||
- Selective re-renders via `useAppSelector`
|
||
- Memoized selectors where needed
|
||
|
||
---
|
||
|
||
## Related Documentation
|
||
|
||
| Document | Description |
|
||
|----------|-------------|
|
||
| [hooks-reference.md](./hooks-reference.md) | Detailed hook documentation |
|
||
| [runtime-presentation.md](./runtime-presentation.md) | Runtime presentation architecture |
|
||
| [constructor-page-editor.md](./constructor-page-editor.md) | Constructor page documentation |
|
||
| [assets-preloading.md](../../documentation/assets-preloading.md) | Asset preloading strategy |
|
||
| [offline-pwa-mode.md](../../documentation/offline-pwa-mode.md) | PWA offline capabilities |
|
||
| [ui-elements.md](../../documentation/ui-elements.md) | UI element types and configuration |
|
||
|
||
---
|
||
|
||
## File Reference by Size
|
||
|
||
### Largest Files (> 10KB)
|
||
|
||
| File | Size | Description |
|
||
|------|------|-------------|
|
||
| `pages/constructor.tsx` | 47KB | Visual tour builder |
|
||
| `hooks/usePreloadOrchestrator.ts` | 26KB | Asset preloading |
|
||
| `hooks/useTransitionPlayback.ts` | 23KB | Video transitions |
|
||
| `components/Constructor/ElementEditorPanel.tsx` | 22KB | Element editor |
|
||
| `components/RuntimePresentation.tsx` | 19KB | Tour playback |
|
||
| `lib/elementDefaults.ts` | 18KB | Element defaults |
|
||
| `components/TourFlowManager.tsx` | 17KB | Page management |
|
||
| `hooks/usePageSwitch.ts` | 14KB | Page navigation |
|
||
| `components/Generic/GenericTable.tsx` | 14KB | Reusable table |
|
||
| `hooks/useConstructorElements.ts` | 12KB | Element CRUD |
|
||
| `lib/offline/DownloadManager.ts` | 12KB | Download management |
|
||
| `hooks/useReversePlayback.ts` | 11KB | Reverse video |
|
||
| `hooks/useOfflineMode.ts` | 11KB | Offline detection |
|
||
| `pages/_app.tsx` | 11KB | App entry |
|
||
| `lib/assetUrl.ts` | 10KB | Presigned URLs |
|
||
| `stores/createEntitySlice.ts` | 10KB | Slice factory |
|
||
| `types/constructor.ts` | 10KB | Constructor types |
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
The frontend architecture demonstrates several strong patterns:
|
||
|
||
**Strengths:**
|
||
- Factory patterns eliminate ~8500 LOC of boilerplate
|
||
- 32 custom hooks provide clean separation of concerns
|
||
- Dual storage strategy (Cache API + IndexedDB) enables robust offline
|
||
- Per-page layout pattern with permission checking
|
||
- Strong TypeScript typing across 12 type definition files
|
||
|
||
**Architecture Decisions:**
|
||
- CSR-only approach (appropriate for admin/builder app)
|
||
- Pages Router (stable, full-featured)
|
||
- Redux Toolkit for predictable state management
|
||
- MUI X DataGrid for complex data tables
|
||
- Tailwind CSS for utility-first styling
|
||
|
||
**Total Codebase:**
|
||
- 408 TypeScript/TSX files
|
||
- ~80,000 LOC estimated
|
||
- 14 distinct modules
|
||
- 13 entity CRUD implementations
|