fal-studio-app-patterns

/home/avalon/.hermes/skills/software-development/fal-studio-app-patterns/SKILL.md · raw

fal-studio App Patterns

Overview

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 to Use

Core architecture

1. Auth + persistence + storage migration

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 }

2. Schema-driven model input UI

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.

3. Concurrency and model-switch resilience

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.

4. Error normalization

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

6. fal-specific operational lessons

Common Pitfalls

  1. Using a global provider key in app state instead of the authenticated user's key
  2. Modeling uploads as one imageFile instead of semantic upload buckets
  3. Preferring previewUrl over saved URLs in gallery/share flows
  4. Blocking the whole app with one global spinner when users want multiple jobs
  5. Passing raw provider error objects to the UI and showing [object Object]
  6. Forgetting credentials: 'include' for cookie-authenticated fetches

Verification Checklist