Per-scene preview thumbnails for templates. Admin clicks "ساخت پیشنمایش صحنهها" → one single-frame AE render per scene → content.scenes.snapshot_url → shown as a thumbnail in the admin scene list (and available to the studio). - migration 30_render_snapshot_jobs.sql: render.snapshot_jobs (queued|running| done|error, per scene, image_url). - render-svc: db/snapshotjobs.go (EnqueueSceneSnapshots, List, Claim, SetResult -> writes content.scenes.snapshot_url cross-schema, SetError); handlers/ snapshotjobs.go (admin POST/GET /v1/scene-snapshots/:project_id + node-facing internal claim/result/fail); main.go routes; gateway route. - devworker: RunSnapshots — fulfils snapshot jobs with a generated placeholder PNG (data: URL, scene-key-tinted) so the flow is verifiable without an AE node. Gated by RENDER_DEV_SNAPSHOTS (default off; never hijacks real render jobs). - admin UI: ProjectScenes "generate snapshots" button (enqueue + poll + reload) and a thumbnail (snapshot_url || image) per scene row. Verified e2e via the dev mock: enqueue -> jobs run -> content.scenes.snapshot_url populated -> scenes API returns it -> admin renders the thumbnail. Remaining (C2): node-agent real-AE runner — claim snapshot, aerender -s0 -e0 -> ffmpeg still -> upload to a PERMANENT URL (mirror file-svc, not the time-limited export presign) -> post result. Needs a live AE node to build + verify. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FlatRender V2 — Database Schemas
PostgreSQL 15+. Single database, one schema per microservice.
Run order
Apply migrations in numerical order:
psql -d flatrender -f migrations/00_setup.sql
psql -d flatrender -f migrations/01_identity_tenants.sql
psql -d flatrender -f migrations/02_identity_users.sql
psql -d flatrender -f migrations/03_identity_billing.sql
psql -d flatrender -f migrations/04_identity_gamification.sql
psql -d flatrender -f migrations/05_content_taxonomy.sql
psql -d flatrender -f migrations/06_content_projects.sql
psql -d flatrender -f migrations/07_content_scenes.sql
psql -d flatrender -f migrations/08_content_characters_presets.sql
psql -d flatrender -f migrations/09_content_cms.sql
psql -d flatrender -f migrations/10_studio_saved_projects.sql
psql -d flatrender -f migrations/11_render_nodes.sql
psql -d flatrender -f migrations/12_render_jobs.sql
psql -d flatrender -f migrations/13_file_manager.sql
psql -d flatrender -f migrations/14_notification.sql
Schemas
| Schema | Owner Service | Purpose |
|---|---|---|
identity |
Identity Service (.NET) | tenants, users, auth, plans, payments, gamification |
content |
Content Service (.NET) | templates, scenes, presets, blogs, CMS |
studio |
Studio Service (.NET) | user's saved projects + audio (music/voiceover/sfx) |
render |
Render Orchestrator (Go) | jobs, nodes, frame jobs, snapshots, exports |
file_mgr |
File Service (Go) | user files, folders, quotas, cleanup |
notification |
Notification Service (Go) | in-app, push, email, SMS, telegram |
Cross-schema design
Schemas are loosely coupled. Where it matters for integrity (within a service), FKs are used. Across services, FKs are deliberately omitted so services can evolve independently — referential integrity is enforced via service code and events.
Hard FKs across schemas (intentional)
identity.earned_gifts.notification_id→notification.notifications.id
Everything else uses soft references (column documented but no FK).
Multi-tenancy
identity.tenants is the root of multi-tenancy. The default FlatRender
tenant has UUID 00000000-0000-0000-0000-000000000001.
Every user, project, render job, file, and notification carries a
tenant_id. Resellers (B2B API customers) are tenants. White-label
branding, API keys, webhooks, and usage metering all hang off
identity.tenants.*.
New features (vs V1)
- Multi-tenancy / Reseller API:
identity.tenants,tenant_branding,tenant_api_keys,tenant_webhooks,tenant_usage_daily - Voiceover support:
studio.saved_projects.voiceover_*,render.render_jobs.has_voiceover - Per-track volume:
music_volume,sfx_volume,voiceover_volume - Scene snapshots:
render.snapshotswith cache key - AE crash tracking:
render.node_crashes+ auto-recovery - Frame repair jobs:
render.frame_repair_jobs - AEP local cache on nodes:
render.node_template_cache(LRU) - SVG color previews:
content.template_svg_previews(drop image → traced SVG) - PWA push subscriptions:
identity.push_subscriptions - MFA:
identity.mfa_factors - Multipart uploads:
file_mgr.upload_sessions - Cleanup scheduler:
file_mgr.cleanup_schedules - Per-user / per-channel notification preferences:
notification.notification_preferences
Partitioning
Time-series tables are partitioned monthly (initial partition for 2026-01 created; ops creates new ones via cron):
identity.tenant_api_request_logsrender.node_health_logs
Service user grants
Each microservice connects with its own DB role limited to its schema.
See top of 00_setup.sql for the recipe.