D1¶
Purpose¶
The one relational database backing the API Worker and 3 apps' own portal/admin logic.
Database / binding names¶
- Database name:
akshaya-group-global - Binding:
DB(identical inworkers/api,apps/corporate-web,apps/software-web,apps/admin-web- see Architecture → Data Platform) database_id: committed in eachwrangler.jsonc(shown here as<D1_DATABASE_ID>for consistency with this portal's placeholder convention, even though it is a resource identifier rather than a credential and is safe to have in git - seedocs/DEPLOYMENT.md§2). Look up the real value withwrangler d1 listor by readingworkers/api/wrangler.jsoncdirectly.
Schema / migrations¶
9 migration files in workers/api/migrations/, applied in filename order, all additive-only
(new tables/columns, never DROP/rename/type-change) - see
Architecture → Data Platform for the full list and what each
adds.
Local vs. remote commands¶
| Local (emulator, safe) | Remote (production D1) | |
|---|---|---|
| Apply migrations | wrangler d1 migrations apply akshaya-group-global --local (from workers/api), or npm run db:local -w @akshaya/api-worker |
[REMOTE / MUTATING] npm run migrate:api:remote, or wrangler d1 migrations apply akshaya-group-global --remote --config workers/api/wrangler.jsonc |
| List applied migrations | wrangler d1 migrations list akshaya-group-global --local |
[READ-ONLY, REMOTE] wrangler d1 migrations list akshaya-group-global --remote --config workers/api/wrangler.jsonc |
| Query | wrangler d1 execute akshaya-group-global --local --command "SELECT ..." |
[READ-ONLY if SELECT, REMOTE] wrangler d1 execute akshaya-group-global --remote --config workers/api/wrangler.jsonc --command "SELECT ..." |
docs/DEPLOYMENT.md §4 is explicit: "This repo's automation must never run wrangler d1
migrations apply --remote outside of the deploy-production CI job." Treat remote migration
application as part of the deploy, never a standalone action from a laptop.
Safe SELECT / read commands (production)¶
# [READ-ONLY, REMOTE] - requires CLOUDFLARE_API_TOKEN/ACCOUNT_ID or `wrangler login`
wrangler d1 execute akshaya-group-global --remote --config workers/api/wrangler.jsonc \
--command "SELECT COUNT(*) FROM contacts;"
wrangler d1 migrations list akshaya-group-global --remote --config workers/api/wrangler.jsonc
SELECT through wrangler d1 execute --remote reads production data but changes nothing
- still requires real Cloudflare credentials, so it is not something to run casually from an
unattended process; treat it the same as any other authenticated production access.
Backup / export¶
No automated D1 backup exists in this repository - no scheduled export, no scripts/*backup*
for D1 (checked: scripts/ contains only cloudflare-bootstrap.sh, the smoke-test scripts, and
sync-portal-shared-css.mjs). The available, unautomated option is Wrangler's own export:
# [READ-ONLY, REMOTE] - produces a local .sql file, does not modify the database
wrangler d1 export akshaya-group-global --remote --config workers/api/wrangler.jsonc --output backup-$(date +%Y%m%d).sql
Troubleshooting¶
| Symptom | Likely cause |
|---|---|
database not found |
database_id in a wrangler.jsonc doesn't match the account being deployed to - compare against wrangler d1 list |
| Migration step reports a table/column already exists | Already partially/fully applied (e.g. a manual run outside CI) - check wrangler d1 migrations list ... --remote before hand-editing anything |
A query works --local but not --remote |
Local emulator schema has diverged from production - re-run db:local from a clean state, or confirm the remote migrations are actually up to date |
Recovery¶
There is no "undo" for an applied migration - see docs/DEPLOYMENT.md §5 "D1 migrations must
stay backward-compatible" and Operations → Rollback. Recovery from a
genuinely bad write (not a bad migration) would mean restoring from the manual export above, if
one exists - there is no other recovery path today.
Security considerations¶
- Every remote D1 command requires
CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID- never embed these in a script or commit them. database_idis not secret;CLOUDFLARE_API_TOKENis - do not confuse the two when deciding what's safe to paste into a PR/issue.