Files
flatrender/scripts/TEMPLATE_BUNDLES.md
soroush.asadi 21b6a30f08 feat(scripts): portable template import/export (bundles)
Move a template fully between environments (local → live): container, projects, all
scenes + editable fields, shared colours/layers, its categories & tags, and the asset
files.

- export_template.py <slug> → a self-contained bundle (template.json + assets/). One
  SQL query captures the whole tree as JSON; assets are resolved from template-media
  references and copied in. Source DB via PSQL env (default = local docker).
- import_template.py <bundle> → idempotent SQL (pipe to target psql). Replaces by slug
  via one cascading delete (all content.* FKs are ON DELETE CASCADE), recreates rows
  verbatim (UUIDs preserved → FKs intact), merges categories/tags BY SLUG so they line
  up across DBs. --assets-to copies media; docker cp / mc cp hints for remote.
- TEMPLATE_BUNDLES.md documents it.

Round-trip tested on fr-instagram-promo: DB → bundle → DB restores identical
3 projects / 15 scenes / 138 fields and field values.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 10:09:41 +03:30

2.5 KiB

Template import / export (portable bundles)

Move a template — everything: container, projects, all scenes + editable fields, shared colours/layers, the categories & tags it belongs to, and the asset files — between environments (e.g. local → live).

A bundle is a self-contained directory:

dist/template-bundles/<slug>/
├── template.json   # every DB row related to the template
└── assets/         # the media it references (thumbnails, scene stills, preview…)

Export (from the source DB)

PYTHONIOENCODING=utf-8 python scripts/export_template.py <slug>
# → dist/template-bundles/<slug>/

# non-default source DB:
PSQL="psql 'postgresql://user:pass@host:5432/flatrender'" \
  python scripts/export_template.py <slug>

Import (into ANY target DB)

The importer prints idempotent SQL — pipe it to the target's psql. It replaces any template with the same slug (one cascading delete), recreates rows verbatim (original UUIDs, so foreign keys stay intact), and merges categories & tags by slug so they line up with whatever the target already calls them.

# local:
python scripts/import_template.py dist/template-bundles/<slug> \
  | docker exec -i fr2-postgres psql -U postgres -d flatrender

# live:
python scripts/import_template.py dist/template-bundles/<slug> \
  | psql "postgresql://user:pass@live-host:5432/flatrender"

Assets

The SQL only moves DB rows. Place the bundle's assets/ into the target's template-media:

# copy locally while importing:
python scripts/import_template.py <bundle> --assets-to ./public/template-media | ...

# live docker frontend:
for f in <bundle>/assets/*; do docker cp "$f" <frontend-container>:/app/public/template-media/; done

# live MinIO/object store:
mc cp --recursive <bundle>/assets/ myminio/<bucket>/template-media/

Guarantees & notes

  • Idempotent — re-importing the same bundle re-creates the template cleanly.
  • Cross-DB safe — UUIDs are preserved; categories/tags merge by their unique slug.
  • Round-trip tested — DB → bundle → DB restores identical counts and values.
  • Not exported (intentionally): user data — comments, favourites, view/use counts.
  • External (http) media referenced by a template is flagged on export but not bundled — host it on the target yourself.
  • Scope today covers FlexStory/Remotion + standard fields. AEP-specific child tables (characters, colour presets) are an easy extension — add them to the export query and the importer's insert list (both are data-driven).