feat(frontend): bootstrap Vite + React 19 + TS strict toolchain (F0.1)
- Vite 8 / React 19 / TS 6 strict (noUncheckedIndexedAccess, no baseUrl deprecation)
- Tailwind 4 via @tailwindcss/vite (no PostCSS step)
- TanStack Query 5, react-router-dom 7, Recharts, clsx
- Vitest + Testing Library + jsdom for unit tests
- Playwright skeleton + first smoke spec (login redirect)
- ESLint flat config: typescript-eslint type-checked, react-hooks, react-refresh, prettier
- Prettier config (semi, single quotes, 100-col, lf)
- IBM Plex font @font-face declarations targeting /fonts/ (self-host, no CDN — OPSEC)
2026-05-21 20:30:23 +02:00
|
|
|
import { defineConfig } from 'vite';
|
|
|
|
|
import react from '@vitejs/plugin-react';
|
|
|
|
|
import tailwindcss from '@tailwindcss/vite';
|
|
|
|
|
import path from 'node:path';
|
|
|
|
|
|
feat(frontend): wire session to real /auth/me + drop sessionStorage mock
Foundations for the sprint 1 backend wiring. No UI behavior change beyond
the loading state in AppShell, but everything below the wire is now real:
- vite.config.ts adds `server.proxy['/api']` → http://localhost:5000
(overridable via VITE_DEV_API_TARGET). In prod Caddy routes /api → backend
on the same origin, so the same `/api/v1/...` paths work without changes.
- src/types/api.ts hand-rolled against the backend Pydantic schemas.
User / Engagement / EngagementCreate / Login / ApiError / ApiValidationError.
Should be regenerated from OpenAPI once backend exposes it.
- src/lib/api.ts: thin fetch wrapper. Always credentials:'include' so the
HttpOnly session cookie travels. 4xx/5xx normalize into ApiClientError
with typed `body` (ApiError | ApiValidationError | null). No retry loop —
that's TanStack Query's policy.
- src/session/sessionApi.ts: 1:1 functions for /auth/me, /auth/login,
/auth/logout. fetchMe maps 401 → null so "unauthenticated" is data, not
an error.
- src/session/useSession.ts: now a TanStack Query hook against
SESSION_QUERY_KEY (`['session']`). Returns { user, isLoading, isError,
signOut, isSigningOut }. Cookie is the source of truth, server is the
resolver, query is the cache.
- Drop sessionStorage mock layer entirely: src/mocks/session.ts,
src/session/SessionContext.{tsx,context.ts}, src/routing/Root.tsx all
removed. No more provider tree — QueryClientProvider in App.tsx is the
only global state container.
- AppShell renders a "resolving session" state during /auth/me's first
flight so users with a valid cookie don't see a /login flash on direct
navigation to a protected URL.
- StatusRail gains an optional `sessionState="resolving"` slot used by
the loading shell.
- Sidebar's Sign-out wires POST /auth/logout, invalidates the session
cache, and always navigates to /login regardless of the call outcome
(a failed logout still expires the local cache so users aren't stuck
on a broken cookie).
- types/roles.ts loses SessionUser (replaced by api.ts User which is the
authoritative shape).
2026-05-23 04:26:28 +02:00
|
|
|
const API_TARGET = process.env.VITE_DEV_API_TARGET ?? 'http://localhost:5000';
|
|
|
|
|
|
feat(frontend): bootstrap Vite + React 19 + TS strict toolchain (F0.1)
- Vite 8 / React 19 / TS 6 strict (noUncheckedIndexedAccess, no baseUrl deprecation)
- Tailwind 4 via @tailwindcss/vite (no PostCSS step)
- TanStack Query 5, react-router-dom 7, Recharts, clsx
- Vitest + Testing Library + jsdom for unit tests
- Playwright skeleton + first smoke spec (login redirect)
- ESLint flat config: typescript-eslint type-checked, react-hooks, react-refresh, prettier
- Prettier config (semi, single quotes, 100-col, lf)
- IBM Plex font @font-face declarations targeting /fonts/ (self-host, no CDN — OPSEC)
2026-05-21 20:30:23 +02:00
|
|
|
export default defineConfig({
|
|
|
|
|
plugins: [react(), tailwindcss()],
|
|
|
|
|
resolve: {
|
|
|
|
|
alias: {
|
|
|
|
|
'@': path.resolve(__dirname, './src'),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
server: {
|
|
|
|
|
port: 5173,
|
|
|
|
|
strictPort: false,
|
feat(frontend): wire session to real /auth/me + drop sessionStorage mock
Foundations for the sprint 1 backend wiring. No UI behavior change beyond
the loading state in AppShell, but everything below the wire is now real:
- vite.config.ts adds `server.proxy['/api']` → http://localhost:5000
(overridable via VITE_DEV_API_TARGET). In prod Caddy routes /api → backend
on the same origin, so the same `/api/v1/...` paths work without changes.
- src/types/api.ts hand-rolled against the backend Pydantic schemas.
User / Engagement / EngagementCreate / Login / ApiError / ApiValidationError.
Should be regenerated from OpenAPI once backend exposes it.
- src/lib/api.ts: thin fetch wrapper. Always credentials:'include' so the
HttpOnly session cookie travels. 4xx/5xx normalize into ApiClientError
with typed `body` (ApiError | ApiValidationError | null). No retry loop —
that's TanStack Query's policy.
- src/session/sessionApi.ts: 1:1 functions for /auth/me, /auth/login,
/auth/logout. fetchMe maps 401 → null so "unauthenticated" is data, not
an error.
- src/session/useSession.ts: now a TanStack Query hook against
SESSION_QUERY_KEY (`['session']`). Returns { user, isLoading, isError,
signOut, isSigningOut }. Cookie is the source of truth, server is the
resolver, query is the cache.
- Drop sessionStorage mock layer entirely: src/mocks/session.ts,
src/session/SessionContext.{tsx,context.ts}, src/routing/Root.tsx all
removed. No more provider tree — QueryClientProvider in App.tsx is the
only global state container.
- AppShell renders a "resolving session" state during /auth/me's first
flight so users with a valid cookie don't see a /login flash on direct
navigation to a protected URL.
- StatusRail gains an optional `sessionState="resolving"` slot used by
the loading shell.
- Sidebar's Sign-out wires POST /auth/logout, invalidates the session
cache, and always navigates to /login regardless of the call outcome
(a failed logout still expires the local cache so users aren't stuck
on a broken cookie).
- types/roles.ts loses SessionUser (replaced by api.ts User which is the
authoritative shape).
2026-05-23 04:26:28 +02:00
|
|
|
proxy: {
|
|
|
|
|
'/api': {
|
|
|
|
|
target: API_TARGET,
|
|
|
|
|
changeOrigin: true,
|
|
|
|
|
secure: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
feat(frontend): bootstrap Vite + React 19 + TS strict toolchain (F0.1)
- Vite 8 / React 19 / TS 6 strict (noUncheckedIndexedAccess, no baseUrl deprecation)
- Tailwind 4 via @tailwindcss/vite (no PostCSS step)
- TanStack Query 5, react-router-dom 7, Recharts, clsx
- Vitest + Testing Library + jsdom for unit tests
- Playwright skeleton + first smoke spec (login redirect)
- ESLint flat config: typescript-eslint type-checked, react-hooks, react-refresh, prettier
- Prettier config (semi, single quotes, 100-col, lf)
- IBM Plex font @font-face declarations targeting /fonts/ (self-host, no CDN — OPSEC)
2026-05-21 20:30:23 +02:00
|
|
|
},
|
|
|
|
|
});
|