Use this for fal-studio-class apps: Vite + React frontend, Express backend, user-supplied model/provider keys, generated image/video outputs, persisted galleries, and a fast-moving model catalog.
This umbrella replaces narrower one-session skills. The right abstraction is not "auth migration" or "dynamic uploads" alone, but the broader app class: a multi-user media-generation studio whose UI and storage model must stay resilient as providers, models, and asset flows change.
When converting a single-user prototype into a real app: - add signup/login - store per-user fal keys - persist gallery rows in SQLite - upload final outputs immediately to durable storage - prefer saved asset URLs over provider preview URLs everywhere user-visible
Recommended tables:
- users(id, email, password_hash, fal_key, created_at)
- assets(id, user_id, model, prompt, result_kind, storage_key, storage_url, params_json, created_at)
Safe user shape:
{ id, email, hasFalKey: !!fal_key }
Do not hardcode model assumptions from memory.
For each endpoint: 1. inspect the real OpenAPI schema 2. derive required fields, enums, defaults, upload requirements, and output kind from that schema 3. use human docs only as a supplement for descriptions/pricing/prompt hints
Represent uploads by semantic section keys, not one generic image input:
- generalReferences
- firstFrame
- lastFrame
- storyboardReference
Backend should use multer.any() and group files by field name before mapping them to API params.
A single global generating boolean is too weak for model-comparison workflows.
Use a lightweight frontend job queue:
- queued
- running
- completed
- failed
Preserve only compatible upload buckets across model switches. Users should not lose valid references just because they compare two nearby models.
Provider errors often arrive as nested objects, arrays, moderation payloads, or opaque strings.
Normalize in shared helpers on both backend and frontend:
- unwrap error, detail, message, msg, reason
- join validation arrays clearly
- map status classes to user-facing categories:
- 401 invalid/missing key
- 403 safety/policy or restricted capability
- 422 invalid params or blocked request
- 429 rate limit
- 5xx provider-side failure
Treat persisted assets as the source of truth.
Rules: 1. save metadata at write time 2. return stable asset URLs from the backend 3. derive absolute share URLs server-side 4. gallery and result viewers should prefer persisted URLs over preview URLs 5. never rely on temporary provider URLs for long-lived gallery/share behavior
Useful metadata to persist:
- result_kind
- storage_mode
- inference_time
- output_duration
- request params/model name/prompt
GET https://api.fal.ai/v1/account/billing?expand=credits401 across many endpoints usually means a bad user key, not a model activation issueGeneration failedimageFile instead of semantic upload bucketspreviewUrl over saved URLs in gallery/share flows[object Object]credentials: 'include' for cookie-authenticated fetches