Skip to content

feat(cms): add data snapshot for dev database seeding#519

Merged
tataihono merged 7 commits intomainfrom
feat/cms-data-snapshot
Mar 24, 2026
Merged

feat(cms): add data snapshot for dev database seeding#519
tataihono merged 7 commits intomainfrom
feat/cms-data-snapshot

Conversation

@tataihono
Copy link
Contributor

@tataihono tataihono commented Mar 24, 2026

Summary

  • Adds a Strapi-owned data snapshot system that exports video, language, and country content tables via pg_dump, compresses and uploads to Railway S3 after each nightly gateway-sync
  • Exposes secret-protected API endpoints (/api/data-snapshot/trigger, /download, /status) for manual triggers and pre-signed download URLs
  • Adds pnpm data-import CLI script that downloads the latest snapshot and restores it into a local PostgreSQL database in minutes (replaces the 4+ hour gateway-sync for local dev)
  • Adds PostgreSQL sidecar to the devcontainer and switches CMS to PostgreSQL-only (drops SQLite support)

What's included

Area Changes
Export service api::data-snapshot — pg_dump allowlisted tables, gzip, S3 upload, 2-snapshot retention
Auth middleware x-snapshot-secret header validated with timingSafeEqual
Cron chaining Snapshot triggers automatically after gateway-sync completion
Import script pnpm data-import — downloads snapshot, preprocesses SQL, atomic psql --single-transaction restore
Devcontainer PostgreSQL 16 sidecar, DATABASE_URL wired up
Database config PostgreSQL-only, SQLite removed
Dockerfile postgresql-client added for pg_dump availability

Test plan

  • pnpm test — 31 unit tests pass for import utilities (connection string parsing, SQL filtering, byte formatting)
  • End-to-end: pnpm data-import from empty local DB to working CMS dataset (requires prod snapshot in S3)
  • Verify POST /api/data-snapshot/trigger creates snapshot on deployed instance
  • Verify GET /api/data-snapshot/download returns pre-signed URL
  • Confirm endpoints reject requests without valid x-snapshot-secret

Post-merge

  • Add DATA_SNAPSHOT_SECRET to Doppler (forge-cms/dev and forge-cms/prd)
  • Delete old branch feat/cms-database-export-import

🤖 Generated with Claude Code

Replaces the GitHub Actions-based export approach with a Strapi-native
solution. After nightly gateway-sync completes, Strapi runs pg_dump on
video/language/country content tables, compresses and uploads to Railway
S3. Developers pull the snapshot via a secret-protected API endpoint
and restore locally with `pnpm data-import`, reducing setup from 4+ hours
to minutes.

- Export service with pg_dump table allowlist (17 content tables)
- Secret-auth middleware using timing-safe comparison
- Trigger + download + status API endpoints
- Cron chaining after gateway-sync completion
- Import script adapted from feat/cms-database-export-import branch
- 2-snapshot retention policy (always one available during export)
- postgresql-client added to Dockerfile
- 31 unit tests for import utilities

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app
Copy link

railway-app bot commented Mar 24, 2026

🚅 Deployed to the forge-pr-519 environment in forge

Service Status Web Updated (UTC)
@forge/cms ✅ Success (View Logs) Web Mar 24, 2026 at 9:15 am
2 services not affected by this PR
  • @forge/web
  • @forge/manager

- Change DATABASE_CLIENT default from sqlite to postgres
- Move pg to dependencies, better-sqlite3 to optionalDependencies
- Update .env.example with PostgreSQL defaults and SQLite fallback docs
- Add Strapi component tables to snapshot (cloudflare-image, variant-download, audio-preview)
- Add Strapi join table globs (*_lnk, *_cmps) for relation and component links
- Add --sequence-data to pg_dump for correct auto-increment counter restore
- Add imports/ to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to forge / forge-pr-519 March 24, 2026 08:50 Destroyed
Remove better-sqlite3 dependency, SQLite connection config, and
DATABASE_CLIENT/DATABASE_FILENAME env vars. The CMS now requires
PostgreSQL in all environments, matching production and enabling
the data-import workflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to forge / forge-pr-519 March 24, 2026 09:04 Destroyed
More general-purpose name for the production CMS base URL env var.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to forge / forge-pr-519 March 24, 2026 09:09 Destroyed
Separate naming: DATA_SNAPSHOT_SECRET protects the endpoint in production,
PROD_DATA_SNAPSHOT_SECRET is what developers set locally (same value) to
authenticate via pnpm data-import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to forge / forge-pr-519 March 24, 2026 09:10 Destroyed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to forge / forge-pr-519 March 24, 2026 09:10 Destroyed
Switch from standalone Dockerfile build to Docker Compose so a
PostgreSQL 16 sidecar runs alongside the dev container. The app
service waits for the DB healthcheck before starting, and
DATABASE_URL is set automatically. Also marks the CMS data snapshot
plan as completed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tataihono tataihono changed the title feat(cms): Strapi-owned data snapshot for dev database seeding feat(cms): add data snapshot for dev database seeding Mar 24, 2026
@tataihono tataihono merged commit a85e2d9 into main Mar 24, 2026
26 checks passed
@tataihono tataihono deleted the feat/cms-data-snapshot branch March 24, 2026 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant