OctoWiki

Seed Catalog

Every database seeder in the platform — the framework (Seeder interface, runner, seed all/fresh/list/info, the load-bearing cache flush, and the absence of any prod guard), all 41 registered seeders in dependency order, the 11 unregistered test-invoked orchestration seeders that wire vendors→tests, the no-op Grasshopper D1 seed, and the committed dev credentials worth rotating.

Every seeder, what it creates, the run order, and the gotchas. This is the fixture layer the Test Catalog runs against. Reminder from the standing rules: you write seeders/migrations — the user applies them. Never run seed/migrate yourself.

The framework

The Seeder interface (database/seeder/seeder.go:14) has three methods — no priority, no declared dependencies:

type Seeder interface {
    Name() string
    Run(ctx, repository) error
    ShouldRun(ctx, repository) (bool, error)   // idempotency guard
}

Order = registration order. InitializeSeeder (runner.go:13-78) is the canonical list; RegisterSeeder just appends — there is no sort. RunAll (seeder.go:69) flushes the cache, then per seeder calls ShouldRunRun, fail-fast (any error aborts the whole run). There is no wrapping transaction across seeders, and most seeders don't wrap their own work either (the eSIM orchestration seeders are the exceptions).

CLI (main.go:334 handleSeed)

CommandEffect
seed allInitializeSeeder(...).RunAll — everything registered
seed freshInitializeFreshSeederreference data + wallets only, preserves clients & vendors (runner.go:84)
seed listlist registered seeders
seed infoper-seeder "needs to run / already run"
seed <name>run one specific seeder; unknown → seeder <name> not found

Idempotency

Two ShouldRun patterns: row-count guard (SELECT COUNT(*), run only when 0/mismatch — countries, currencies, blacklists, order-item-responses, test-configs) and lookup-by-key (admin user, credentials, vendors/products by code, orchestration by product name). Writes are guarded inserts / upsertsno seeder truncates — so re-running is generally a safe no-op.

Two load-bearing gotchas

  1. The cache flush is load-bearing. RunAll/RunSeeder wipe the whole cache (DeleteByPattern(ctx,"*"), seeder.go:41) before seeding, because repo reads hit cache first — after migrate fresh, stale cache entries make existence checks return phantom "already exists" and seeders silently skip INSERTs. A flush failure is logged but non-fatal, so a "successful" run can still leave rows missing.
  2. No prod guard anywhere. A grep for prod/APP_ENV/IsProd across all seeders finds nothing — no seeder refuses to run on prod. Safety is pure convention: operators use seed fresh (which excludes clients/vendors/orders/payouts) on shared envs, never seed all.

Registered seeders (run by seed all), in dependency order

41 registered in InitializeSeeder. Grouped by purpose; order is the actual run order.

Reference data (idempotent, prod-safe)

timezones (~431 from data/timezones.json) → countries (~245) → currencies (~156) → categories (10) → subcategories (16) → forex_values (~22 pairs). All load from data/*.json.

Config (clients, users, vendors)

admin_user (creates admin + the system_admin user that order/payout seeders use for transactions) → clients (29 from data/clients.json) → client_users (bcrypt password123) → tenant_connectionsclient_credentialswebhook_urlsuserswallets (USD/INR/AED per client) → products (57 from data/products.json; test products ids 13/14/15).

Vendor seeders (each writes vendors + vendor_attributes): vendors (Wupex WPX, iRewardify IRW, EpinForce, Grasshopper) → seagm_vendordtone_vendor (service_id 1) → dtone_esim_vendor (service_id 13 + webhook token) → runa_vendorneo_vendoroctopus_vendoroctopus_topup_vendor (OCTO_TOPUP) → octopus_esim_vendor (OCTO_ESIM).

Then (order matters — after vendors and clients): client_vendor_blacklists, client_product_blacklists, vendor_products, vendor_wallets, client_product_details.

Fixtures (destructive on prod)

inventory (1000 voucher items) → orders (sample orders + items + responses inline) → payout providers merit_provider (MERIT) + ledig_provider (LEDIG) → beneficiariespayoutsfiles.

Migration/backfill & test config

shopify_product_mapping_backfill (idempotent, UNIQUE-guarded — safe to leave registered) → test_configs (12 from data/test_configs.json, gated on client_id=10, runs last).

Unregistered seeders (test-invoked or disabled)

11 seeder files exist but are not in runner.go — invoked directly by orchestration tests, or disabled:

  • Orchestration fixtures (test-invoked): dtone_topup_orchestration, dtone_esim_orchestration, seagm_topup_orchestration, octopus_topup_orchestration, octopus_esim_orchestration, and the voucher-side runa_vendor_products, neo_vendor_products, wupex_vendor_products, irewardify_vendor_products.
  • Inline (done by the orders seeder): order_items, order_item_responses.
  • Disabled stress seeders: bulk_orders (1000/wallet, runner.go:60), large_inventory (10,000 items, commented out runner.go:58).

Orchestration seeders — where seeders meet tests

Orchestration fixtures are no longer auto-seeded (runner.go:54); after a fresh DB, topup/eSIM/voucher products come only from vendor catalog sync, and each orchestration test calls its seeder in setup. Each wires: a pre-seeded parent vendor → one deterministic product+variant → credentials pointing at the mock server.

SeederVendorProduct / denomMock targetCredentials
dtone_topup_orchestrationDTONEAirtel India topup, $0.15mocky dtone_products id 8141dtone_test/dtone_secret_123
dtone_esim_orchestrationDTONE_ESIM1GB/7d Albania, $0.85mocky dtone_products id 70000self-heals to same
seagm_topup_orchestrationSEAGMPUBG UC gaming, $0.99mocky seagm_recharge_types id 1SEAGM vendor sk_test_...
octopus_topup_orchestrationOCTO_TOPUPMobile topup 1:1, $0.15in-process octopusfakeenv=sandbox
octopus_esim_orchestrationOCTO_ESIMeSIM 1:1, $0.85in-process octopusfakeenv=sandbox
runa/neo/wupex/irewardify_vendor_productsRUNA/NEO/WPX/IRWvoucher denoms (open 5–500 / fixed 10)mocky localhost:8788 hostsseeded by vendor seeders

This coupling is fragile in one place: each voucher orchestration suite self-seeds its product because the shared vendor_product seeder randomly assigns variants to only the first 10 vendors, and Runa/others were added later — if seeder ordering changes, suites break.

Grasshopper D1 seed — a no-op

frontend/grasshopper/drizzle/seed.sql is verified to contain only SELECT 1+1 AS result;. Grasshopper's voucher_types catalog is repopulated by the Octopus → Grasshopper sync, not by a seed file (provisioning).

  • db:seed → runs the no-op SQL.
  • db:reset → local wipe + migrate + no-op seed.
  • db:reset:remotereset-remote.sh deletes+recreates the prod D1 with no confirmation — the most destructive item here — then migrates, no seed.
  • db:reset:sandboxreset-sandbox.sh, guarded (refuses if the DB name lacks "sandbox"), then instructs re-running the sync.

The mock rows the orchestration seeders point at live in mocky-balboa's own seed.sql/seed.ts (frontend/mocky-balboa/), the source of truth for those dtone_products/seagm_recharge_types ids.

Committed dev credentials (rotation review)

All appear to be dev/mock values but are in git:

SecretWhere
Grasshopper vendor api_key Pnw0ohHAJoyqi254QRdBmDTFzAPUYk (real-shaped — verify first)vendor_seeder.go:235
Runa webhook secret whsec_MfKQ9r8tZlF3q+bJvR2GkXcPdS5TmYwA6HnV1xJ4eUo= + api key xx_test_runa_playground_123runa_vendor_seeder.go:92,96
DTOne dtone_test/dtone_secret_123, SEAGM sk_test_seagm_secret_key_12345, Neo neo_local_*, Wupex test-api-key, EpinForce/iRewardify tokensvendor seeders
Admin default password WmQIcJ5XgrJ3OsZp9VIGvVkKPqFrkw (#nosec)admin_user_seeder.go:73
Portal/API password123 / demo123; JWT fallback your-super-secret-keyclient_credentials_seeder.go:20,145

These join the broader committed-secrets finding. Because no seeder has a prod guard, running a vendor/credential seeder against a shared env would overwrite live credentials with localhost mock values — the practical danger, beyond the fixtures simply inserting junk rows.

Key files

  • Framework: database/seeder/{seeder,runner}.go; CLI main.go:96,265,334
  • Data: database/seeder/data/*.json (timezones/countries/currencies/clients/products/test_configs)
  • Orchestration: database/seeder/*_orchestration_seeder.go, *_vendor_product_seeder.go
  • Grasshopper: frontend/grasshopper/drizzle/seed.sql, scripts/reset-{remote,sandbox}.sh; mock data frontend/mocky-balboa/

On this page