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>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user