mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
Migrate TREK 3 to NestJS + React 19 with a shared Zod contract layer
Brownfield strangler migration of the backend onto NestJS modules (auth, trips, days, places, assignments, packing, todo, budget, reservations, collab, files, photos, journey, share, settings, backup, oidc, oauth, admin, atlas, vacay, weather, airports, maps, categories, tags, notifications, system-notices) served through a per-prefix dispatcher, keeping the existing SQLite/better-sqlite3 DB and JWT httpOnly cookie auth, with behavioural parity for every route. Client: React 19 upgrade, "page = wiring container + data hook" pattern across all pages, per-domain Zustand stores bound to @trek/shared contracts, and decomposition of the large components (DayPlanSidebar, PackingListPanel, CollabNotes, FileManager, MemoriesPanel, PlacesSidebar, CollabChat, SystemNoticeModal, BudgetPanel, PlaceFormModal, ...) into focused render units backed by in-file hooks. Apply the shared global request pipeline (helmet/CSP, CORS, HSTS, forced HTTPS, the global MFA policy and request logging) to the NestJS instance as well, so a migrated route is protected identically to the legacy fallback rather than bypassing it.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# Page pattern: wiring container + data hook
|
||||
|
||||
Every page under `src/pages` follows the same shape: the exported `*Page`
|
||||
component is a thin **wiring container** and all of its state, effects, data
|
||||
loading and event handlers live in a co-located **`use<Page>()` hook**.
|
||||
|
||||
```
|
||||
src/pages/
|
||||
DashboardPage.tsx ← container: reads the hook, renders JSX
|
||||
dashboard/
|
||||
useDashboard.ts ← state, effects, API calls, handlers
|
||||
dashboardModel.ts ← (optional) pure types + helpers, no React
|
||||
```
|
||||
|
||||
## What goes where
|
||||
|
||||
**The hook (`use<Page>.ts`)** owns everything stateful:
|
||||
|
||||
- `useState` / `useReducer` / `useRef`
|
||||
- `useEffect` / `useLayoutEffect`
|
||||
- `useMemo` / `useCallback`
|
||||
- store selectors, API calls, WebSocket listeners, handlers
|
||||
- derived values
|
||||
|
||||
It returns a single object the page destructures.
|
||||
|
||||
**The page (`*Page.tsx`)** is presentation only:
|
||||
|
||||
- `const { ... } = use<Page>()`
|
||||
- `useTranslation()` for `t`/`locale` (a context hook, not state — allowed)
|
||||
- JSX, and `t`-dependent display arrays like the tab list
|
||||
- presentational sub-components and pure helpers may live in the same file,
|
||||
before or after the default export
|
||||
|
||||
```tsx
|
||||
export default function DashboardPage() {
|
||||
const { t } = useTranslation()
|
||||
const { trips, isLoading, handleCreate } = useDashboard()
|
||||
if (isLoading) return <Spinner />
|
||||
return <Grid trips={trips} onCreate={handleCreate} />
|
||||
}
|
||||
```
|
||||
|
||||
## Why
|
||||
|
||||
- **Testable** — page tests render JSX; hook logic is isolated and mockable.
|
||||
- **Readable** — the container reads top-to-bottom as "what the page shows".
|
||||
- **Diffable** — logic changes touch the hook, layout changes touch the page.
|
||||
|
||||
## Notes
|
||||
|
||||
- A `<page>Model.ts` is optional — use it for pure types and helpers shared
|
||||
between the hook and the page (no React imports). See `atlas/atlasModel.ts`
|
||||
for a mutable-lookup-table example and `admin/adminModel.ts` for types only.
|
||||
- The post-guard derivations that depend on a now-narrowed value (e.g. after
|
||||
`if (!current) return`) may stay in the page next to the JSX that uses them.
|
||||
- Keep the rendered JSX byte-identical when extracting — this is a refactor of
|
||||
where logic lives, not a redesign.
|
||||
|
||||
## Enforcement
|
||||
|
||||
`npm run lint:pages` (`scripts/check-page-pattern.mjs`) scans each `*Page.tsx`
|
||||
default-export body and fails if it calls `useState`, `useReducer`, `useEffect`,
|
||||
`useLayoutEffect`, `useMemo`, `useCallback` or `useRef` directly. Move that logic
|
||||
into the page's hook. Sub-components and helper hooks in the same file are not
|
||||
flagged.
|
||||
Reference in New Issue
Block a user