The Operaciones panel (backup, restore, sync, re-import) shelled out to mysqldump as the application user, parsed straight out of DATABASE_URL. `--single-transaction` issues FLUSH TABLES, which needs the global RELOAD privilege, and the app user is granted only ALL ON jorgecuadros.* plus USAGE ON *.*. BACKUP failed outright; SYNC and REIMPORT failed with it, since both take a safety backup first. An admin credential is now supplied out of band via OPS_DB_ADMIN_USER / OPS_DB_ADMIN_PASSWORD, mirroring what deploy/scripts/pre-migrate-backup.mjs already does, rather than permanently elevating the user the API serves requests as. Host, port and database still come from DATABASE_URL, so the override can only change who logs in, never which server. Unset, it falls back to the DATABASE_URL credentials and warns — local development is unaffected. Two defects in the dumps themselves, both shared with the deploy backup before it was rewritten: - No --set-gtid-purged=OFF. The production server is the replication source with GTID on, so every dump embedded SET @@GLOBAL.GTID_PURGED and was unrestorable onto the server it came from — the one thing the restore screen is for. - The pipeline's exit status was gzip's, and gzip succeeded. A mysqldump that died on its first statement left a small, perfectly valid archive that the job recorded as SUCCESS and the restore screen listed as an ordinary restore point. Dumps now run under `set -o pipefail`, assert a CREATE TABLE count, and delete their own output on failure. Verified with a stubbed mysqldump: a failing dump exits 1, surfaces the real error, removes the partial file, and — critically — stops SYNC/REIMPORT before the ETL touches anything. Restores gained pipefail too: a corrupt archive made gunzip fail while mysql, fed a truncated stream, could still exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
27 lines
1.1 KiB
Bash
27 lines
1.1 KiB
Bash
# Copy to .env and fill in for local development.
|
|
DATABASE_URL=mysql://jorgecuadros:jorgecuadros@localhost:3306/jorgecuadros
|
|
SESSION_SECRET=change-me-to-a-random-string
|
|
WEB_ORIGIN=http://localhost:3000
|
|
NEXT_PUBLIC_API_ORIGIN=http://localhost:3001
|
|
|
|
# Login the "Operaciones" screen runs mysqldump/mysql as. Optional locally: when
|
|
# unset it falls back to the DATABASE_URL credentials, which a dev MySQL usually
|
|
# grants enough for. Required in any deployment, where the application user has
|
|
# only ALL ON jorgecuadros.* and mysqldump --single-transaction needs the global
|
|
# RELOAD privilege. Host/port/database always come from DATABASE_URL.
|
|
OPS_DB_ADMIN_USER=
|
|
OPS_DB_ADMIN_PASSWORD=
|
|
|
|
# Company info — printed in the header of every report (PDF + browser
|
|
# print). Leave blank to use the placeholders. COMPANY_LOGO_PATH is
|
|
# optional; when unset the API falls back to apps/api/assets/company_logo.png.
|
|
COMPANY_NAME=Jorge Cuadros & Asociados
|
|
COMPANY_ADDRESS_LINE1=
|
|
COMPANY_ADDRESS_LINE2=
|
|
COMPANY_CITY_STATE=
|
|
COMPANY_PHONE=
|
|
COMPANY_EMAIL=
|
|
COMPANY_TAX_ID=
|
|
COMPANY_WEBSITE=
|
|
COMPANY_LOGO_PATH=
|