Files
flatrender/docs/SESSION_HANDOFF.md
T
2026-06-05 10:55:02 +03:30

51 lines
5.0 KiB
Markdown

# FlatRender V2 — Session Handoff & Gotchas
> Context captured 2026-06-05 so it survives a Claude-account/machine change.
> The `~/.claude` memory is machine-local; this file is the portable copy.
## How to run (V2 stack)
```bash
# Backend services + infra (Postgres + MinIO) — V2 compose, NOT the default docker-compose.yml
docker compose -f docker-compose.v2.yml --env-file .env.v2 up -d
# Rebuild one service after a code change:
docker compose -f docker-compose.v2.yml --env-file .env.v2 build <svc> && \
docker compose -f docker-compose.v2.yml --env-file .env.v2 up -d <svc>
# Services: identity-svc, content-svc, file-svc, studio-svc, render-svc, notification-svc, gateway, frontend
```
- **Open the app at `http://172.28.144.1:3000`** (the host LAN IP), NOT `localhost`.
- Gateway: `:8088`. JWT secret + service creds live in `.env.v2`.
- DB: single Postgres `flatrender`, one schema per service (`identity`, `content`, `studio`, `render`, `file`, …). User `postgres`.
- DB migrations: `backend/db/migrations/NN_*.sql`, applied **once** by `scripts/init-db.sh` on first volume creation. New SQL files must be applied manually: `docker exec fr2-postgres psql -U postgres -d flatrender -f ...` (or inline `-c`).
## ⚠️ Critical gotchas (these have each cost hours)
1. **Localhost is VPN-hijacked.** EonVPN intercepts `127.0.0.1:*`. Curl/loopback to localhost returns junk/000 even when the app is up. Use the LAN IP `172.28.144.1`, or `docker exec <container> wget -qO- http://<svc>:<port>`.
2. **Non-secure browser context.** Because the app is served over `http://172.28.144.1` (plain HTTP, non-localhost), the browser is a **non-secure context**`crypto.randomUUID`, `crypto.subtle`, clipboard, etc. are **undefined**. NEVER call them in client code — use `src/lib/uuid.ts` `uuid()` (falls back to `crypto.getRandomValues`). This silently broke the entire studio editor (`crypto.randomUUID is not a function`).
3. **Studio service binds camelCase JSON** (no snake_case naming policy, unlike identity/content which use `SnakeCaseLower`). Frontend→studio request bodies MUST be camelCase (`originalProjectId`, not `original_project_id`) or fields drop to defaults (Guid.Empty). Studio responses are camelCase too.
4. **EF Core global query filters** (`HasQueryFilter(DeletedAt==null)`) require `.IgnoreQueryFilters()` to see/revive soft-deleted rows (bit the AEP import apply).
5. **AE automation** runs on a Windows node via `node-agent.exe` (PULL model: agent dials render-svc with HMAC). Before each AE launch the agent kills stale AE processes + clears crash/Safe-Mode markers (`SCRPriorState.json` + registry `AppStates`) and launches AE with the project as an arg (bypasses the Home screen). Heavy expression-driven AEPs take >10min to open → FIX scans are now **binary-only** (`services/render/internal/aep/parse.go` `ParseNames` reads `frl_`/`frd_` names from the .aep RIFX directly; no AE).
## What this session built (commits 6e5efbd → 5b2617d)
- **AE scan hardening:** binary FIX scanner (no AE, never hangs); kill stale AE + clear crash dialog before each launch.
- **Profile = data-collection surface** (for future AI video gen, NO resume builder): full editable profile (avatar upload + slogan/about/company/website/country/birthdate/gender), `/api/profile` + user-scoped `/api/profile/upload`. Identity DTOs widened (no migration — columns existed).
- **Role-aware nav:** `UserMenu` (avatar + dropdown; admins get Admin Panel link) replaces Sign-In when logged in; real avatars in dashboard sidebar + admin shell; `Avatar` primitive; `getNavUser()`.
- **Template detail page** wired to real content (`fetchProject(slug)`; was hardcoded demo catalog → 404'd).
- **"Use template" works end-to-end:** `StudioService.CreateProjectAsync` deep-copies the content template scene graph (scenes + content elements + scene colors + shared colors) into the editable studio project via one atomic cross-schema SQL copy (enum cols cast `::text`; temp `_scene_map`). `/api/projects` resolves container slug → published variant project. **Aspect-ratio picker** (16:9/1:1/9:16) on the detail page drives which variant is copied.
## Known follow-ups (not done)
- Scene-graph copy skips **repeater children, characters, color-presets** (scenes + fields + colors ARE copied).
- Admin can't edit *other* users' full profiles yet (self-edit works for everyone).
- Test the studio editor itself once inside (large Konva surface — not exhaustively exercised).
## Debugging client-side behavior
No Playwright/Puppeteer in the repo. To reproduce browser issues headlessly: `npm i puppeteer-core` in a temp dir, launch the user's Chrome (`C:\Program Files\Google\Chrome\Application\chrome.exe`), set the auth cookie via `page.setCookie({name:'fr_access', value:<JWT>, url:'http://172.28.144.1:3000'})`, and listen on `page.on('pageerror')` / `console`. Mint a test admin JWT with the `.env.v2` `JWT_SECRET` (HS256; claims `sub`=real user id, `tenant_id`, `is_admin:"true"`, `role:"Admin"`, `iss:"flatrender-identity"`, `aud:"flatrender"`).