feat: complete SaaS commercial delivery workflows

This commit is contained in:
2026-08-01 15:26:21 +08:00
parent 46abf4d62f
commit d58bcd97e9
56 changed files with 27505 additions and 181 deletions

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
for command_name in pg_dump pg_restore createdb dropdb psql; do
command -v "$command_name" >/dev/null || {
echo "Required PostgreSQL tool is missing: $command_name" >&2
exit 1
}
done
source_database="${TIKU_BACKUP_SOURCE_DATABASE:-tiku}"
if [[ ! "$source_database" =~ ^[A-Za-z0-9_]+$ ]] || [[ "$source_database" == "postgres" ]]; then
echo "TIKU_BACKUP_SOURCE_DATABASE must be a safe non-maintenance database name." >&2
exit 1
fi
restore_database="tiku_restore_drill_$(date -u +%Y%m%d%H%M%S)_$$"
if [[ ! "$restore_database" =~ ^tiku_restore_drill_[0-9]+_[0-9]+$ ]]; then
echo "Refusing unsafe restore database name." >&2
exit 1
fi
drill_directory="$(mktemp -d "${TMPDIR:-/tmp}/tiku-restore-drill.XXXXXX")"
dump_path="$drill_directory/tiku.dump"
cleanup() {
dropdb --if-exists --maintenance-db=postgres "$restore_database" >/dev/null 2>&1 || true
rm -rf "$drill_directory"
}
trap cleanup EXIT
echo "Creating compressed backup from database '$source_database'..."
pg_dump --format=custom --compress=6 --no-owner --no-acl --file="$dump_path" "$source_database"
test -s "$dump_path"
echo "Restoring backup into temporary database '$restore_database'..."
createdb --maintenance-db=postgres "$restore_database"
pg_restore --exit-on-error --no-owner --no-acl --dbname="$restore_database" "$dump_path"
migration_count="$(psql --no-psqlrc --tuples-only --no-align --dbname="$restore_database" --command='SELECT count(*) FROM "__EFMigrationsHistory";')"
tenant_count="$(psql --no-psqlrc --tuples-only --no-align --dbname="$restore_database" --command='SELECT count(*) FROM tenants;')"
if [[ ! "$migration_count" =~ ^[1-9][0-9]*$ ]] || [[ ! "$tenant_count" =~ ^[0-9]+$ ]]; then
echo "Restore verification failed: migrations='$migration_count', tenants='$tenant_count'." >&2
exit 1
fi
echo "Restore rehearsal passed: migrations=$migration_count, tenants=$tenant_count. Temporary database will be removed."