04ca431fbc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
6.9 KiB
Markdown
77 lines
6.9 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.
|
|
|
|
## ⏭️ NEXT UP — Studio↔Template binding EPIC (agreed priority)
|
|
|
|
**Phase B DONE (commits a69bc62 B1, 47a4ced B2).** Edit→render binding works:
|
|
- **B1 ✅** studio input edits persist to `saved_scene_contents` via studio-svc
|
|
`PATCH /v1/saved-projects/{id}/contents` (Next `/api/projects/[id]/contents`); the
|
|
persistence hook pushes edited values (bridged `c-<key>` layers) on every save.
|
|
- **B2 ✅** render-svc claim now includes `bindings` (GetRenderBindings = saved_scene_contents
|
|
with non-empty value); node-agent `binder.go` emits a JSON bind-spec + downloads media, runs
|
|
the data-driven `bind.jsx` via afterfx (sets Source Text, replaces footage) → saves `bound.aep`
|
|
→ aerender renders THAT.
|
|
- **VERIFY (needs node-agent re-run):** re-run the updated `node-agent.exe`, edit a text input in
|
|
the studio (wait for "saved"), render, confirm the MP4 shows the edited text. Colours
|
|
(saved_shared_colors → spec.colors) + footage-item media (vs layer-source) are follow-ups.
|
|
|
|
- **Done since:** per-tier render height (#36), FIX-hides-add-scene (#42), admin/renders
|
|
pagination + user-name links + output (#41), Persian/Jalali date pickers (#40).
|
|
- **Still open in B:** colours binding (saved_shared_colors → spec.colors), footage-item
|
|
media (vs layer-source), deeper per-input controllers in the admin scene-inputs editor.
|
|
- Next epic phase: **A** admin preset stories (premade videos — model `preset_stories`/`preset_scenes`
|
|
exists, no endpoints/UI; detail "ویدیوهای ساختهشده" is placeholder), and **C** AE single-frame
|
|
scene snapshots (`scenes.snapshot_url` empty → node `aerender -s 0 -e 0`).
|
|
|
|
Also smaller, still open: per-tier render **height** (render-svc r_height hardcoded 1080 + node
|
|
ffmpeg scale), **FIX hides add-scene** (mode not plumbed into studio store), **Persian/Jalali
|
|
date pickers** in admin, **admin/renders** pagination + video/output + user-name → profile link,
|
|
deeper per-input controllers in the admin scene-inputs editor.
|
|
|
|
## Done follow-ups (this session)
|
|
- Scene-graph copy now includes repeater children, characters/controllers, color-presets.
|
|
- Admin CAN edit any user's full profile (Users → «پروفایل»).
|
|
- Studio now shows ALL template inputs (contents→layers bridge).
|
|
|
|
## 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"`).
|