# AGENTS.md This file provides guidance to CODEX when working with code in this repository. **MAIN RULE:** DON'T MADE UP ANYTHING!!! IF YOU NOT SURE - DOUBLECHECK IT VIA PROJECT DOCUMENTATION, TOOL DOCUMENTATION, APPROPRIATE MCP, WEB SEARCH OR JUST ASK FOR ME TO CLARIFY. ## Project Overview Tour Builder Platform - a web application for building and managing interactive virtual tours. Built with: - **Frontend**: Next.js 15 with React 19, TypeScript, Redux Toolkit, Tailwind CSS - **Backend**: Node.js/Express with Sequelize ORM - **Database**: PostgreSQL ## System Requirements ### Required Software - **Node.js** 24.x for backend runtime and TypeScript migration work - **PostgreSQL** 14+ ### FFmpeg FFmpeg is bundled with the backend via `ffmpeg-static` and `ffprobe-static` npm packages. No manual installation is required. **How it works:** - Pre-compiled binaries are downloaded during `npm install` - `fluent-ffmpeg` is configured to use bundled binaries in `backend/src/services/videoProcessing.js` - Works across all platforms (Linux, macOS, Windows) and Docker environments **Supported use case:** - Reversed video generation for back navigation transitions ## Important Rules - **Never change global app configs casually** - Do not modify `.env` or database configuration without verifying the target environment. These configs are shared across environments and incorrect changes can break production. - **Centralize environment variables** - Do not read new app/runtime environment variables directly from services, routes, components, hooks, or feature modules. Backend app env vars must be added to `backend/src/utils/env-validation.ts`, typed in `backend/src/types/env.ts` / `backend/src/types/config.ts`, exposed through `backend/src/config.ts`, and consumed via `config`. Frontend public env vars must be centralized in `frontend/src/config.ts`. Direct `process.env` access is acceptable only in bootstrap/config entrypoints (`load-env`, logger bootstrap, DB/Umzug config, Next config), scripts, migrations, seeders, and tests. - **Backend async handlers** must be wrapped with `wrapAsync` helper for error propagation. - **Use Passport JWT** for protected routes: `passport.authenticate('jwt', { session: false })`. Secure routes must read the authenticated user through `getCurrentUser(req)` from `backend/src/utils/request-context.ts`; if absent, return `ForbiddenError`. - **Access model** - Keep the current permission model: effective permissions are `app_role.permissions + user.custom_permissions`. `Administrator`, `Platform Owner`, and `Account Manager` are platform-wide internal roles. Other internal users currently have all-project scope by default unless a future explicit override system is implemented. `Public` users must not have admin API permissions and can only access public production pages plus explicitly granted private production presentations. - **Public role hardening** - Do not grant RBAC permissions or custom permissions to `Public` users. Do not represent private production presentation grants as `READ_PROJECTS`, `READ_TOUR_PAGES`, or other admin permissions; use `production_presentation_access`. - **Centralize access decisions** - New authorization logic must go through an `AccessPolicy`-style helper/service rather than ad hoc checks in routes/components. Keep admin API permissions separate from runtime presentation access. ## Mandatory Rules For New Code These rules are required for new code and for touched code when practical. ### Backend Boundaries - **Routes/controllers**: only authenticate, read runtime context, validate request input, call a service, and map the response. Do not put business logic in routes. - **Services/domain**: own business logic, transactions, permission decisions, and orchestration. - **DB API/repository**: only data access, filters, includes, pagination, and persistence mapping. - **Policy**: all role/permission/runtime access decisions belong in policy/helper services, not scattered across routes. - **Validation**: all new external `body`, `query`, and `params` inputs must be validated before service calls. `Joi` is already available in backend and should be preferred unless there is a clear reason to use another validator. - **ID handling**: route params are canonical. For `PUT/PATCH/DELETE /:id`, use `req.params.id`; reject mismatched body ids. - **Query safety**: new list/autocomplete endpoints must define max `limit`, default pagination, allowed sort fields, and allowed sort directions. - **Service contracts**: new service/DB API methods should use object/options signatures, e.g. `Service.update({ id, data, currentUser, transaction, runtimeContext })` and `DBApi.findAll(filter, { currentUser, transaction, runtimeContext })`. - **Logging**: use the project logger in runtime backend code (`services`, `routes`, `middlewares`, `db/api`, `utils`, app/bootstrap/config). Do not add new `console.*` calls outside migrations, seeders, scripts, or explicit debug-only CLI tooling. ### Backend Typing - New backend pure helpers, validators, and policy modules should use TypeScript or JSDoc/checkJs-compatible types. - Define shared shapes for `currentUser`, `runtimeContext`, service options, and validation results when touching related code. - Do not add global `Express.Request` augmentation for project request fields. Use `backend/src/utils/request-context.ts` helpers for request-scoped `currentUser`, `runtimeContext`, logging, runtime-public flags, and permission overrides. - Keep active backend source in strict TypeScript/ESM. ### Frontend State And API - **Redux is for client/app state only**: auth/session UI, theme/style, layout/sidebar, constructor UI state, and app preferences. - **TanStack Query is for server state**: API reads, entity lists/details, mutations, invalidation, and background refetch. - Do not create new entity CRUD Redux slices or new Redux thunks for server reads/mutations. - Centralize API access through query hooks or a shared API client. Avoid direct `axios` calls inside feature UI components unless there is a clear existing local pattern. - New feature-specific code should live near the feature/domain it belongs to. Do not put feature logic into generic `components`, `hooks`, or `lib` folders when a feature-local module is clearer. ### Frontend TypeScript And React - Do not add new `any` without a specific reason. Prefer existing domain types or add a narrow local type. - Avoid new `eslint-disable`, `@ts-ignore`, and hook dependency suppressions. If unavoidable, add a short reason. - New hooks must follow React hook rules and should be structured so `react-hooks/exhaustive-deps` can be enabled. - Do not add new client usage of `jsonwebtoken`; use `jwt-decode` or `/auth/me` for client-side identity. ### Database And Migrations - Do not add indexes speculatively. Add indexes after checking query patterns or explaining the expected query. - Migrations must be reversible or include an explicit rollback/backup plan. - Do not drop columns/tables in the same change that stops using them unless explicitly requested and production data safety is covered. - Do not normalize `ui_schema_json` into new tables unless there is a concrete current need; prefer validation/extraction helpers first. - Do not rewrite, rename, or reformat already applied backend migration files. Add new migrations only for new schema changes. ## Disabled Features The following features are implemented but currently disabled with `false &&` conditions: - **Navigation blocking while preloading** - Navigation buttons can be disabled until neighbor page backgrounds are preloaded. Currently disabled to allow instant navigation response. To re-enable, remove `false &&` in: - `frontend/src/components/RuntimePresentation.tsx` (isForwardNavDisabled, handleElementClick) - `frontend/src/pages/constructor.tsx` (handleElementClick, isNavDisabled calculation) ## Documentation Workflow - **Before each task**: Research relevant documentation in `documentation/` to understand existing implementations, patterns, and conventions. - **After each task**: Update affected documentation to reflect changes (API changes, new fields, modified workflows). - **After implementing new features/modules**: Create new documentation file in `documentation/` following the existing format, and add reference to the Feature Documentation table in this file. ## Quick Start ```bash # Terminal 1 - Backend (port 3000) cd backend && npm run start-dev # Terminal 2 - Frontend (port 3001) cd frontend && npm run dev ``` ## Common Commands ### Backend (run from `backend/` directory, runs on port 3000 in the default dev_stage flow) ```bash npm install # Install dependencies npm run start-dev # Start server (loads .env, migrates, seeds, watches) npm run lint # ESLint check npm run typecheck # Strict TypeScript check for migrated backend scope npm run test # Unit tests (Node test runner) npm run test:integration # Integration tests; DB tests skip when Postgres is unavailable npm run test:e2e # E2E HTTP tests with a local listener npm run test:all # Unit, integration, and e2e suites npm run build # Compile migrated TypeScript files npm run db:migrate # Run migrations only npm run db:migrate:undo # Undo last migration npm run db:seed # Seed database only npm run db:reset # Drop, create, migrate, and seed ``` **Creating new migrations:** Add new migration files deliberately under `backend/src/db/migrations/` only when a schema change is required. Keep them reversible and preserve already applied migration files unchanged. **Note:** Backend `.env` is loaded centrally by `backend/src/load-env.ts` for app and DB entrypoints. If `NODE_ENV` is absent, it defaults to `dev_stage`, matching the standard VM backend flow and using the `.env` DB settings. Do not add `NODE_ENV=production` to local startup unless a task explicitly requires the production config. The backend defaults to port `3000` in `dev_stage` and `8080` otherwise; set `PORT` explicitly when a task needs a different port. ### Frontend (run from `frontend/` directory) ```bash npm install # Install dependencies npm run dev # Start dev server with Turbopack (port 3001) npm run typecheck # TypeScript check without production build npm run verify # Typecheck, lint, and production build npm run build # Production build npm run lint # ESLint check (.ts, .tsx files) npm run format # Format code with Prettier ``` ### Standard VM Environment The standard VM port split is: - **Frontend PM2 app `frontend-dev`**: Next.js production server on port `3001` - **Backend PM2 app `backend-dev`**: `npm run start` with `NODE_ENV=dev_stage` on port `3000` - **Apache**: public entrypoint and reverse proxy on port `80` Direct VM backend health checks should target `http://127.0.0.1:3000/api/...`. A protected endpoint returning `401 Unauthorized` without JWT means the backend is reachable. ### Docker (run from `docker/` directory) ```bash chmod +x start-backend.sh && chmod +x wait-for-it.sh # First time setup docker-compose up # Start all services rm -rf data && docker-compose up # Start with fresh database ``` ## Architecture ### Backend Structure (`backend/src/`) - **routes/**: Express route handlers (RESTful endpoints) - **db/api/**: Database access layer (CRUD operations per model) - **db/models/**: Sequelize model definitions - **db/migrations/**: Database migrations - **db/seeders/**: Seed data - **auth/**: Passport.js authentication (JWT, Google OAuth, Microsoft OAuth) - **services/**: Business logic services (emails, notifications, publishing, file storage) - **factories/**: Router and service generation (`router.factory.js`, `service.factory.js`) - **middlewares/**: Permission checking, runtime context handling - **helpers/**: Utility functions (e.g., `wrapAsync` for async error handling) ### Frontend Structure (`frontend/src/`) - **pages/**: Next.js pages (each entity has `-list`, `-edit`, `-new`, `-view`, `-table` variants) - **components/**: React components (PascalCase naming) - **stores/**: Redux Toolkit slices (per entity + auth, main, style slices) - **layouts/**: Page layouts (Authenticated, Guest) - **hooks/**: Global custom hooks (`usePreloadOrchestrator`, `useNeighborGraph`, etc.) - **lib/**: Utility libraries (`elementStyles`, `imagePreDecode`, `mediaDuration`, `parseJson`) - **types/**: TypeScript type definitions (`constructor.ts`, `runtime.ts`, `preload.ts`) - **helpers/**: Utility functions - **styles/**: Global CSS with Tailwind (`_theme.css` uses `@apply`) ### Key Domain Models Projects, Tour Pages, Assets, Asset Variants, Permissions, Roles, Users, Publish Events, PWA Caches, Element Type Defaults, Project Element Defaults **Note:** Page elements, navigation links, and transitions are stored directly in `tour_pages.ui_schema_json`. ### Element Defaults Hierarchy The system has a two-level defaults cascade for UI elements: 1. **element_type_defaults** - Global platform-wide defaults (11 predefined types) 2. **project_element_defaults** - Project-specific overrides (auto-snapshotted from global on project creation) When creating new elements, defaults cascade: global → project. Instance-specific settings are stored in `tour_pages.ui_schema_json`. ### Special Pages - **`constructor.tsx`**: Tour builder/editor with drag-drop, element positioning, page management - **`runtime.tsx`**: Tour playback with transitions, preloading, navigation - **`p/[slug].tsx`**: Public tour pages with PWA offline support ### State Management - **Redux Toolkit is the default only for client/app state** (auth/session UI, style/theme, layout/sidebar, constructor UI state, app preferences) - **TanStack Query is the default for server state** (API reads, entity lists/details, mutations, invalidation, background refetch) - Do not create new entity CRUD Redux slices in `stores/[entity]/[entity]Slice.ts`. - Core slices: `authSlice.ts` (auth), `mainSlice.ts` (UI), `styleSlice.ts` (theming), `constructorSlice.ts` (editor) - Use `useAppSelector` and `useAppDispatch` hooks from `stores/hooks.ts` - **Local hooks acceptable** for ephemeral, component-scoped state (e.g., `usePageNavigation` for session-scoped page history) - See [stores-module.md](frontend/docs/stores-module.md#state-management-guidelines) for decision tree ## Code Conventions ### Backend - ES6+ with arrow functions, const/let - Document endpoints with Swagger JSDoc comments - Lowercase filenames (e.g., `auth.js`, `projects.js`) ### Frontend - Functional components with TypeScript - PascalCase for components and types, camelCase for variables/functions - Custom hooks prefixed with `use` (e.g., `useAuth`) - Tailwind CSS with theme customization in `_theme.css` ### Styling - Theme customization uses `@apply` directive in `_theme.css` - **Sidebar styles**: Target `#asideMenu` (defined in `AsideMenuLayer.tsx`) for sidebar overrides - Use highly specific selectors when overriding Tailwind utilities to avoid conflicts - Themed blocks (`.theme-pink`, `.theme-green`) standardize UI appearance - ensure custom overrides integrate cleanly ### Error Handling - Backend: Use centralized `commonErrorHandler` middleware for uniform error responses - Frontend: Use React error boundaries for runtime errors ## API Patterns Routes follow pattern: `/api/[entity]/` with standard CRUD operations - `POST /api/auth/signin/local` - Login - `GET /api/auth/me` - Current user (requires JWT) - Self-registration is disabled. New users are created by Administrator, Platform Owner, or Account Manager through the Users flow and receive an invitation/setup link. All entity routes support: list, findOne, create, update, destroy operations with pagination and filtering. ## Backend Factory Patterns ### Router Factory (`factories/router.factory.js`) Generates standard CRUD routes for entities: ```javascript module.exports = createEntityRouter('assets', AssetsService, AssetsDBApi, { permissionEntity: 'assets', }); ``` ### Service Factory (`factories/service.factory.js`) Generates service classes with transaction handling: ```javascript module.exports = createEntityService('assets', AssetsDBApi); ``` ### Base DB API (`db/api/base.api.js`) All entity APIs extend `GenericDBApi` and override: - `MODEL` - Sequelize model reference - `SEARCHABLE_FIELDS` - Fields for text search - `RANGE_FIELDS` - Fields for range filtering - `ENUM_FIELDS` - Fields for exact match filtering - `getFieldMapping(data)` - Transform input data before save ## File Storage Controlled by `FILE_STORAGE_PROVIDER` env var or auto-detected from credentials: - `s3` - AWS S3 (requires `S3_BUCKET`, `S3_REGION`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`) - `gcloud` - Google Cloud Storage - `local` - Local filesystem (default) ## Publishing Workflow Three-tier **content environment** model (distinct from `NODE_ENV` server environment): - **Dev** (constructor editing) → **Stage** (preview) → **Production** (public) **Route-based environment access:** - `/p/[slug]` - Production presentation - `/p/[slug]/stage` - Stage presentation - `/constructor?projectId=` - Dev editing (always dev environment) Key endpoints: - `POST /api/publish/save-to-stage` - Dev → Stage (body: `{ projectId }`) - `POST /api/publish` - Stage → Production (body: `{ projectId }`) **Environment isolation:** Pages have `environment` field (`dev`, `stage`, `production`). The `X-Runtime-Environment` header (set by frontend) determines which content environment to query. Both frontend (`RuntimePresentation.tsx`) and backend (`runtime-context.js`) filter by this field. **Server Environment vs Content Environment:** - `NODE_ENV` controls database config (production/dev_stage/development) - `tour_pages.environment` controls content visibility (dev/stage/production) ### Private Production Presentations Production presentations are public by default at `/p/[slug]`. Each project can switch production runtime visibility through `projects.production_presentation_visibility` (`public` default, `private` optional). - Platform staff users with any RBAC permission can visit every private production presentation - Customer users with `Public` role can visit only private production presentations granted in `production_presentation_access` - `Administrator`, `Platform Owner`, and `Account Manager` can create users - When creating or editing a `Public` user, the form shows a selector for private production presentations and saves DB access grants - Do not use config files or env vars for customer allowlists - Do not grant customer viewer users broad permissions such as `READ_PROJECTS` or `READ_TOUR_PAGES`; any RBAC permission makes the user platform staff for private presentation access See [private-production-presentations.md](documentation/private-production-presentations.md). ## PWA & Offline Support - **Service Worker**: Generated by Serwist from `frontend/src/sw.ts` → `public/sw.js` - **Offline Caching**: PWA_Caches model tracks cached assets per project - **Runtime Mode**: Middleware distinguishes public vs authenticated access for offline tours ## Asset Preloading Architecture Runtime presentations use direct S3 downloads via presigned URLs for instant page navigation: ``` 1. Request presigned URLs (max 50 per batch, 1-hour expiry) POST /api/file/presign { urls: ["assets/img.jpg", ...] } 2. Download directly from S3 → Store in Cache API (< 5MB) or IndexedDB (≥ 5MB) 3. Create blob URL → Decode image → Store in readyBlobUrlsRef 4. Instant lookup during navigation (O(1)) const blobUrl = preloadOrchestrator.getReadyBlobUrl(originalUrl); ``` **Preload Priority:** Transition videos (+150) > Images (+100) > Audio (+50) > Video (+30) **Storage Layers:** | Layer | Size Limit | Purpose | |-------|------------|---------| | Cache API | < 5MB | Fast asset storage | | IndexedDB (Dexie) | ≥ 5MB | Large assets, offline data | | Blob URLs | Memory | Pre-decoded for instant display | ## Frontend Patterns ### MUI X Data Grid v7 Use new `valueGetter` signature: ```typescript // For value transformation valueGetter: (value) => value?.id ?? value // For row access valueGetter: (_value, row) => new Date(row.created_at) ``` ### Custom Hooks Hooks are located in three places: - **`src/hooks/`**: Global hooks (`usePreloadOrchestrator`, `usePageNavigationState`, `useTransitionPlayback`, `usePageNavigation`) - **`src/hooks/video/`**: Video playback primitives (8 composable hooks for video playback scenarios) - **Component directories**: Domain-specific hooks (`components/Assets/useAssetUploader.ts`) Key runtime hooks: | Hook | Purpose | |------|---------| | `usePreloadOrchestrator` | Stream-first asset preloading (current page + transitions only) | | `usePageNavigationState` | Unified navigation state machine (replaces 6+ hooks) | | `useTransitionPlayback` | Video transition playback coordination | | `usePageNavigation` | Page history tracking with browser-like back behavior | | `useCanvasScale` | Responsive canvas scaling with letterbox mode | | `useNetworkAware` | Network condition monitoring for adaptive transitions | | `useBackgroundDimensionSuggestion` | Detect background media dimensions for canvas size suggestions | **Video Hooks (`src/hooks/video/`):** | Hook | Purpose | |------|---------| | `useVideoBlobUrl` | Resolve video URLs to blob URLs from preload cache | | `useVideoPlaybackCore` | Core playback logic combining multiple primitives | | `useVideoPlayer` | Complete UI video player hook | ### Redux Entity Pattern Use this pattern only when maintaining an existing Redux entity flow; new server-state code should use TanStack Query hooks instead. ```typescript import { fetch, deleteItem } from '../../stores/assets/assetsSlice'; const dispatch = useAppDispatch(); dispatch(fetch({ query: '?limit=100' })); ``` ## Feature Documentation Detailed feature documentation is available in `documentation/`: | Document | Description | |----------|-------------| | [project-architecture.md](documentation/project-architecture.md) | Overall project structure and architecture | | [api-reference.md](documentation/api-reference.md) | API endpoints reference | | [authentication-system.md](documentation/authentication-system.md) | JWT, OAuth (Google, Microsoft) authentication | | [rbac-system.md](documentation/rbac-system.md) | Role-based access control system | | [user-management.md](documentation/user-management.md) | User CRUD, roles assignment, account management | | [project-memberships.md](documentation/project-memberships.md) | Team collaboration, per-project access control | | [asset-upload-variants.md](documentation/asset-upload-variants.md) | Asset upload pipeline and variant generation | | [ui-elements.md](documentation/ui-elements.md) | UI Elements stored in `ui_schema_json` (buttons, hotspots, galleries, tooltips, media players) | | [page-transitions.md](documentation/page-transitions.md) | Video transitions stored on navigation elements | | [project-transition-settings.md](documentation/project-transition-settings.md) | Environment-aware CSS transition settings (fade, duration, easing) | | [video-playback.md](documentation/video-playback.md) | Video player implementation, iOS autoplay compatibility | | [assets-preloading.md](documentation/assets-preloading.md) | Asset preloading and caching strategy | | [publishing-workflow.md](documentation/publishing-workflow.md) | Dev → Stage → Production publishing | | [private-production-presentations.md](documentation/private-production-presentations.md) | Private production presentation allowlist, viewer users, and runtime access flow | | [offline-pwa-mode.md](documentation/offline-pwa-mode.md) | PWA offline capabilities and caching | | [email-notification-service.md](documentation/email-notification-service.md) | Nodemailer/SES integration, verification emails, invitations | | [search-system.md](documentation/search-system.md) | Global full-text search, permission-based filtering | | [deployment-vm.md](documentation/deployment-vm.md) | Standard VM deployment topology, PM2 recovery, ports, OOM/ffmpeg diagnostics | | [custom-domains-apache.md](documentation/custom-domains-apache.md) | Customer-owned presentation domains via Apache, DNS A records, Certbot, and host/path routing | | [page-links-navigation.md](documentation/page-links-navigation.md) | Page navigation using `targetPageSlug` in elements | | [access-logs-audit-trail.md](documentation/access-logs-audit-trail.md) | Access logging, audit trail, activity tracking | | [db-cleanup-audit.md](documentation/db-cleanup-audit.md) | Non-destructive DB cleanup audit, orphan checks, legacy schema checks, and soft-delete retention policy | | [global-ui-controls.md](documentation/global-ui-controls.md) | Configurable fullscreen, sound, and offline system controls with global/project/page cascade | | [backend/database-schema.md](backend/docs/database-schema.md) | Complete database schema - all models, fields, relationships, indexes, constraints | | [backend/backend-architecture.md](backend/docs/backend-architecture.md) | Backend architecture - layers, design patterns, middleware, factories, file storage | | [backend/api-endpoints.md](backend/docs/api-endpoints.md) | Complete API reference - all endpoints, request/response formats, authentication, rate limits | | [backend/modules/core.md](backend/docs/modules/core.md) | Core module - index.js (entry), config.ts (configuration), helpers.js/utilities | | [backend/modules/auth.md](backend/docs/modules/auth.md) | Auth module - Passport.js strategies (JWT, Google, Microsoft), login, invitation setup, password reset, email verification | | [backend/modules/middleware.md](backend/docs/modules/middleware.md) | Middleware module - rate limiting, permissions, runtime context, public access control, file uploads | | [backend/modules/routes.md](backend/docs/modules/routes.md) | Routes module - 22 route files, factory pattern, CRUD endpoints, Swagger docs, auth/file/search/sql routes | | [backend/modules/services.md](backend/docs/modules/services.md) | Services module - business logic layer, 34 service files, factory pattern, file storage (S3/GCloud/Local), email, notifications, publishing | | [backend/modules/email.md](backend/docs/modules/email.md) | Email module - Nodemailer/AWS SES, transactional emails, HTML templates, token management, email verification, password reset, invitations | | [backend/modules/notifications.md](backend/docs/modules/notifications.md) | Notifications module - error classes (ValidationError, ForbiddenError), i18n message catalog, helper functions | | [backend/modules/factories.md](backend/docs/modules/factories.md) | Factories module - createEntityRouter and createEntityService functions, code generation patterns for CRUD operations, boilerplate elimination | | [backend/modules/db-models.md](backend/docs/modules/db-models.md) | DB Models module - 16 Sequelize models, entity definitions, associations, validations, lifecycle hooks, soft delete patterns | | [backend/modules/db-api.md](backend/docs/modules/db-api.md) | DB API module - GenericDBApi base class, 18 entity APIs, declarative configuration, query filtering, runtime context helpers | | [backend/modules/db-migrations.md](backend/docs/modules/db-migrations.md) | DB Migrations module - Umzug runner, migration safety rules, schema evolution, data backfill | | [backend/modules/db-seeders.md](backend/docs/modules/db-seeders.md) | DB Seeders module - Umzug seeders, RBAC setup (7 roles, 54 permissions), sample data opt-in | | [backend/modules/db-config.md](backend/docs/modules/db-config.md) | DB Config module - typed DB config, environment validation (Joi), Umzug commands, sync/reset scripts | | [backend/modules/utilities.md](backend/docs/modules/utilities.md) | Utilities module - error classes, Pino logging, env validation, request helpers (wrapAsync, commonErrorHandler), DB utils, i18n messages | | [backend/testing.md](backend/docs/testing.md) | Backend test strategy - unit, integration, and e2e coverage, helpers, commands, and environment notes | | [frontend/hooks-reference.md](frontend/docs/hooks-reference.md) | React hooks reference (useFormSync, useEntityTable, useOfflineMode, etc.) | | [frontend/video-hooks-module.md](frontend/docs/video-hooks-module.md) | Video playback primitive hooks (8 composable hooks for video scenarios) | | [frontend/constructor-page-editor.md](frontend/docs/constructor-page-editor.md) | Constructor page editor - visual tour builder with drag-drop elements | | [frontend/runtime-presentation.md](frontend/docs/runtime-presentation.md) | Runtime presentation viewer - full-screen tour playback with transitions | | [frontend/navigation-smooth-transitions.md](frontend/docs/navigation-smooth-transitions.md) | Navigation & smooth transitions - page switching, transition video playback, last frame preservation, online/offline modes | | [frontend/ui-adaptivity-system.md](frontend/docs/ui-adaptivity-system.md) | UI Adaptivity System - canvas units (--cu), responsive scaling, letterbox mode, element styling | | [frontend/ui-element-preloading-analysis.md](frontend/docs/ui-element-preloading-analysis.md) | UI element processing & neighbor preloading - deep analysis of asset extraction, preload flow, offline caching | | [frontend/asset-upload-preloading-pwa-analysis.md](frontend/docs/asset-upload-preloading-pwa-analysis.md) | Deep analysis of asset upload, preload orchestrator, PWA/offline mode, storage layers, network awareness | | [frontend/frontend-architecture.md](frontend/docs/frontend-architecture.md) | Frontend architecture - 386 files, 14 modules, factories, hooks, Redux, PWA/offline, design patterns | | [frontend/pages-module.md](frontend/docs/pages-module.md) | Pages module - 99 pages, _app.tsx entry, entity CRUD pattern, constructor, runtime presentations, layouts | | [frontend/components-module.md](frontend/docs/components-module.md) | Components module - 183 files, entity tables, factories, constructor, element settings, runtime, PWA/offline | | [frontend/hooks-module.md](frontend/docs/hooks-module.md) | Hooks module - 52 custom hooks, runtime/preloading, PWA/offline, constructor, tables/forms, UI utilities | | [frontend/stores-module.md](frontend/docs/stores-module.md) | Stores module - Redux Toolkit, 17 slices (4 core + 13 entity), createEntitySlice factory, typed hooks | | [frontend/lib-module.md](frontend/docs/lib-module.md) | Lib module - 19 utility files, asset URL management, element defaults/styles/effects, offline storage (Cache API + IndexedDB), download queue | | [frontend/types-module.md](frontend/docs/types-module.md) | Types module - 18 TypeScript definition files, entity types, constructor/runtime types, API/Redux types, permissions enum, offline/preload types | | [frontend/factories-module.md](frontend/docs/factories-module.md) | Factories module - 5 factory files (~1,285 LOC), createListPage, createFormPage, createTableComponent, configBuilderFactory, createEntitySlice for 91% boilerplate reduction | | [frontend/schemas-module.md](frontend/docs/schemas-module.md) | Schemas module - 6 Zod validation schema files (~257 LOC), form validation for User, Asset, Project, TourPage, Role entities with type inference | | [frontend/helpers-module.md](frontend/docs/helpers-module.md) | Helpers module - 6 utility files (~304 LOC), dataFormatter (entity display), hasPermission (RBAC), notifyStateHandler (Redux), text formatters, file saver | | [frontend/layouts-module.md](frontend/docs/layouts-module.md) | Layouts module - 2 layout files (~262 LOC), LayoutAuthenticated (JWT auth, permissions, UI chrome), LayoutGuest (public pages), getLayout pattern | | [frontend/config-module.md](frontend/docs/config-module.md) | Config module - 12 config files (~523 LOC), Next.js/Tailwind/TypeScript build config, runtime settings (config.ts), menu configs, offline/preload configs, ESLint rules | | [frontend/context-module.md](frontend/docs/context-module.md) | Context module - DownloadContext (~256 LOC) for PWA download progress state, DownloadEventBus integration, useDownloadContext/useDownloadContextOptional hooks | | [frontend/interfaces-module.md](frontend/docs/interfaces-module.md) | Interfaces module - ~15 type definition files (~2,200+ LOC), entity types, API contracts, Redux state shapes, permissions enum, constructor/runtime/offline/preload interfaces |