Home/Operations/Rebuilding the Seed ENУКРРУС API Reference (ReDoc) ↗

Rebuilding the Seed

Refreshing the catalog from the legacy console — read-only, deterministic, reviewable.

The catalog was seeded from the console database (animated-spoon). When the console gains languages or provider mappings worth importing, the seed is rebuilt from a fresh dump.

The console database is production, and is only ever read

scripts/dump_console_db.sh opens the connection with default_transaction_read_only=on and a 30-second statement timeout, set at the server through PGOPTIONS. Every statement in it is a SELECT. Even a typo introducing a write would be refused by Postgres rather than executed.

Data flows one way only: console → JSON dump → seed files → this service's own database. There is no path back, and the application itself never holds a connection to the console.

Rebuilding

# 1. Dump (needs .env-console-db in the repo root — gitignored, never committed)
./scripts/dump_console_db.sh build/console-dump

# 2. Transform
python scripts/build_seed.py build/console-dump --out data/seed

# 3. Read the report
$EDITOR data/seed/REPORT.md

# 4. Review the diff and commit
git diff --stat data/seed/

The transformation is pure and deterministic: the same dump in produces byte-identical files out, so the diff is genuinely reviewable.

Reading the report

data/seed/REPORT.md lists every decision the builder made:

Multi-code (provider, language) pairs collapsed — where the console offered several codes, which one won and what the runners-up were. Every runner-up is kept as an inbound alias, so nothing that resolved before stops resolving.

Alias contests resolved — where one code claimed two languages, which one got it. fa-af going to "Farsi (Afghanistan)" rather than "Dari" is the kind of call worth a second opinion.

Merged duplicate console languages — rows describing the same language under different ids.

Languages with no usable code — imported inactive, with a placeholder code, so nothing is lost.

Aliases dropped (key already owned) — a curated alias that collided with an existing language code. Usually correct: de-DE is its own language row, so de does not also get de-de.

Providers with no regional overrides — not a gap. The console only stored codes for regional languages.

Applying it

Committing is enough — the deploy runs python -m app.cli seed after migrations. Locally:

python -m app.cli seed
python -m app.cli stats

The seed is idempotent and upsert-shaped: rows are matched on their natural key and updated in place. It never deletes.

The seed wins for rows it knows about

A code pinned in the admin panel for a pair the seed also carries is reset to the seeded value on the next deploy. Permanent corrections belong in the seed — either fix the console and re-dump, or add the pair to the catalog table in scripts/build_seed.py. Rows the seed has never heard of are untouched.

Adding a provider to the seed

CATALOG in scripts/build_seed.py mirrors provider_credentials' config/providers.yaml. A new entry needs code, vendor_code, vendor_name, name, category, fallback_policy, and legacy — the console service_names that map onto it.

Getting legacy right is what keeps old callers working: every listed name becomes a provider alias, and every console mapping under those names is folded into this provider's table.

Next