Files
flatrender/scripts/TEMPLATE_BUNDLES.md
T
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

68 lines
2.5 KiB
Markdown

# 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)
```bash
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.
```bash
# 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`:
```bash
# 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).