chore(db): squash pre-launch migrations into baseline#736
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughRewrites the historical baseline migration (1741087887225) to create enums, core and infra tables, and indexes; adds small reversible migrations (emailVerified, volume_quota, autoArchiveInterval, api_key.expiresAt, runner.serviceHealth); removes many legacy migration files; and updates migrations README and DTO/tests. ChangesMigration Squashing and Baseline
New incremental migrations extending baseline
Migration removals and README/DTO/test updates
Sequence DiagramsequenceDiagram
participant Migration as Migration1741087887225
participant DB as PostgreSQL
participant Enums as EnumTypes
participant Tables as TablesAndIndexes
Migration->>DB: CREATE EXTENSION "uuid-ossp"
Migration->>Enums: CREATE TYPE user_role_enum, api_key_permissions_enum, region_type_enum, ...
Enums-->>DB: persist enum types
Migration->>Tables: CREATE TABLE user, api_key, organization, region, volume, box, runner, job, audit_log, ...
Tables-->>DB: persist tables and constraints
Migration->>Tables: CREATE INDEX ... (B-tree / partial / GIN)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/migrations/1741087887225-migration.ts`:
- Around line 85-86: The migration creates job.runnerId as character varying
while runner.id and box.runnerId are uuid; update the Job entity's `@Column` for
runnerId to use type: 'uuid' (and update any repository/entity typing if needed)
and modify the migration SQL to create "runnerId" uuid instead of character
varying; if runnerId should enforce referential integrity, also add a FOREIGN
KEY constraint referencing runner(id) in the same migration (or create a
follow-up migration) to align types and optionally enforce the relation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 14651cde-da3f-49cf-823b-108b54b62e5d
📒 Files selected for processing (2)
apps/api/src/migrations/1741087887225-migration.tsapps/api/src/migrations/README.md
✅ Files skipped from review due to trivial changes (1)
- apps/api/src/migrations/README.md
b73f30d to
ce95ae1
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/api/src/migrations/1741087887225-migration.ts (1)
6-322: Exercise this baseline on a fresh Postgres before merge.This file is now the bootstrap path for new databases, but the PR notes only static/type checks were run. A clean
--migration-runand--migration-reverton an empty Postgres should gate merge, because DDL/type issues here only surface at execution time.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/src/migrations/1741087887225-migration.ts` around lines 6 - 322, The migration file's up/down DDL hasn't been validated against a real Postgres instance; run the migration class (the up and down methods in 1741087887225-migration.ts using QueryRunner) against a fresh, empty Postgres—execute a full --migration-run (apply) and --migration-revert (rollback) to surface runtime DDL/type errors, fix any failing CREATE/DROP statements or enum/type mismatches discovered during those runs (adjust enum names, constraints, index expressions, or table definitions in the up/down methods to be symmetric and valid), and re-run until both apply and revert complete cleanly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/migrations/1741087887225-migration.ts`:
- Around line 48-50: Change the organizationId columns from character varying to
uuid in the migration that creates the webhook_initialization and audit_log
tables and update the corresponding entity decorators to use type: 'uuid' for
organizationId; specifically, in the migration (the CREATE TABLE for
"webhook_initialization" and the CREATE for "audit_log") alter the column
definition for "organizationId" to uuid NOT NULL (and adjust defaults if any),
and in the entities webhook-initialization.entity.ts and audit-log.entity.ts
update the `@Column`(...) for organizationId to include type: 'uuid' (and ensure
TypeORM relations/use of organization.id UUID are consistent). Ensure SQL and
entity changes are in sync so joins/FKs can later be enforced without casting.
---
Nitpick comments:
In `@apps/api/src/migrations/1741087887225-migration.ts`:
- Around line 6-322: The migration file's up/down DDL hasn't been validated
against a real Postgres instance; run the migration class (the up and down
methods in 1741087887225-migration.ts using QueryRunner) against a fresh, empty
Postgres—execute a full --migration-run (apply) and --migration-revert
(rollback) to surface runtime DDL/type errors, fix any failing CREATE/DROP
statements or enum/type mismatches discovered during those runs (adjust enum
names, constraints, index expressions, or table definitions in the up/down
methods to be symmetric and valid), and re-run until both apply and revert
complete cleanly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9c8399fa-a681-425c-966d-4e6592c72dbc
📒 Files selected for processing (2)
apps/api/src/migrations/1741087887225-migration.tsapps/api/src/migrations/README.md
✅ Files skipped from review due to trivial changes (1)
- apps/api/src/migrations/README.md
| await queryRunner.query( | ||
| `CREATE TABLE "webhook_initialization" ("organizationId" character varying NOT NULL, "svixApplicationId" character varying, "lastError" text, "retryCount" integer NOT NULL DEFAULT '0', "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "webhook_initialization_organizationId_pk" PRIMARY KEY ("organizationId"))`, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Baseline schema definitions ==="
sed -n '48,56p' apps/api/src/migrations/1741087887225-migration.ts | nl -ba
sed -n '87,89p' apps/api/src/migrations/1741087887225-migration.ts | nl -ba
echo -e "\n=== Candidate app files that mention organizationId ==="
fd -t f 'webhook*' apps/api/src
fd -t f 'audit*' apps/api/src
fd -t f 'organization*.entity.ts' apps/api/src
while IFS= read -r f; do
echo "--- $f ---"
rg -n "organizationId|`@Column`|uuid|ManyToOne|JoinColumn" "$f" -C 2 || true
done < <(
{
fd -t f 'webhook*' apps/api/src
fd -t f 'audit*' apps/api/src
fd -t f 'organization*.entity.ts' apps/api/src
} | sort -u
)Repository: boxlite-ai/boxlite
Length of output: 159
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="apps/api/src/migrations/1741087887225-migration.ts"
echo "=== Migration snippet around lines 40-110 (for context) ==="
sed -n '35,110p' "$FILE" | cat -n
echo -e "\n=== Find SQL table/column occurrences in the migration ==="
rg -n "webhook_initialization|audit_log|organizationId" "$FILE" || true
echo -e "\n=== Candidate entity/model files with organizationId references ==="
# Try common entity locations
fd -t f "organization*.entity.ts" apps/api/src -x echo {} >/dev/null || true
fd -t f "webhook*" apps/api/src | sort -u
fd -t f "audit*" apps/api/src | sort -u
# Search for type/relation hints
FILES=$(fd -t f '(' -name 'webhook*' -o -name 'audit*' -o -name 'organization*.entity.ts' ')' apps/api/src | sort -u || true)
if [ -z "${FILES:-}" ]; then
echo "(No matching files found for webhook/audit/organization*.entity.ts)"
exit 0
fi
echo -e "\n=== Ripgrep hits for organizationId / uuid / relations ==="
# Keep output small: only show matches with a little context
printf "%s\n" "$FILES" | while read -r f; do
echo "--- $f ---"
rg -n "organizationId|uuid|`@Column`|ManyToOne|JoinColumn" "$f" -C 1 || true
doneRepository: boxlite-ai/boxlite
Length of output: 27261
🏁 Script executed:
#!/bin/bash
set -euo pipefail
WEBHOOK_ENTITY="apps/api/src/webhook/entities/webhook-initialization.entity.ts"
AUDIT_ENTITY="apps/api/src/audit/entities/audit-log.entity.ts"
echo "=== webhook-initialization.entity.ts (organizationId) ==="
rg -n "organizationId|`@Column`|uuid" "$WEBHOOK_ENTITY" || true
sed -n '1,200p' "$WEBHOOK_ENTITY" | cat -n
echo -e "\n=== audit-log.entity.ts (organizationId) ==="
rg -n "organizationId|`@Column`|uuid" "$AUDIT_ENTITY" || true
sed -n '1,220p' "$AUDIT_ENTITY" | cat -n
echo -e "\n=== Other TS code touching webhook_initialization/audit_log organizationId ==="
rg -n "webhook_initialization|audit_log|organizationId" \
apps/api/src/webhook apps/api/src/audit \
-S | head -n 80Repository: boxlite-ai/boxlite
Length of output: 14082
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate likely Organization entity
echo "=== Organization entity candidates ==="
fd -t f "*organization*.entity.ts" apps/api/src | head -n 50
ORG_FILE="$(fd -t f "organization*.entity.ts" apps/api/src | head -n 1 || true)"
if [ -z "${ORG_FILE:-}" ]; then
ORG_FILE="$(fd -t f "*organization*.entity.ts" apps/api/src | head -n 1 || true)"
fi
echo -e "\nUsing ORG_FILE=$ORG_FILE"
if [ -n "${ORG_FILE:-}" ]; then
sed -n '1,220p' "$ORG_FILE" | cat -n
rg -n "class .*Organization|id:|`@PrimaryColumn`|`@PrimaryGeneratedColumn`|organizationId" "$ORG_FILE" || true
fi
# Check Box entity organizationId typing
echo -e "\n=== Box entity candidates ==="
fd -t f "*box*.entity.ts" apps/api/src | head -n 50
BOX_FILE="$(fd -t f "box*.entity.ts" apps/api/src | head -n 1 || true)"
if [ -z "${BOX_FILE:-}" ]; then
BOX_FILE="$(fd -t f "*box*.entity.ts" apps/api/src | head -n 1 || true)"
fi
echo -e "\nUsing BOX_FILE=$BOX_FILE"
if [ -n "${BOX_FILE:-}" ]; then
sed -n '1,240p' "$BOX_FILE" | cat -n
rg -n "organizationId|`@Column`" "$BOX_FILE" || true
fiRepository: boxlite-ai/boxlite
Length of output: 423
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Organization entity files (glob match) ==="
ORG_FILES=$(fd -t f -g '*organization*.entity.ts' apps/api/src | sort -u)
echo "$ORG_FILES" | head -n 50
ORG_FILE=$(echo "$ORG_FILES" | head -n 1 || true)
if [ -n "${ORG_FILE:-}" ]; then
echo -e "\n=== Inspect $ORG_FILE ==="
sed -n '1,220p' "$ORG_FILE" | cat -n
rg -n "class .*Organization|`@PrimaryColumn`|`@PrimaryGeneratedColumn`|organizationId|id:" "$ORG_FILE" || true
else
echo "No organization entity file found with *organization*.entity.ts"
fi
echo -e "\n=== Box entity files (glob match) ==="
BOX_FILES=$(fd -t f -g '*box*.entity.ts' apps/api/src | sort -u)
echo "$BOX_FILES" | head -n 50
BOX_FILE=$(echo "$BOX_FILES" | head -n 1 || true)
if [ -n "${BOX_FILE:-}" ]; then
echo -e "\n=== Inspect $BOX_FILE ==="
sed -n '1,260p' "$BOX_FILE" | cat -n
rg -n "organizationId|`@Column`" "$BOX_FILE" || true
else
echo "No box entity file found with *box*.entity.ts"
fi
echo -e "\n=== Volume entity files (glob match) ==="
VOL_FILES=$(fd -t f -g '*volume*.entity.ts' apps/api/src | sort -u)
echo "$VOL_FILES" | head -n 50
VOL_FILE=$(echo "$VOL_FILES" | head -n 1 || true)
if [ -n "${VOL_FILE:-}" ]; then
echo -e "\n=== Inspect $VOL_FILE ==="
sed -n '1,220p' "$VOL_FILE" | cat -n
rg -n "organizationId|`@Column`" "$VOL_FILE" || true
else
echo "No volume entity file found with *volume*.entity.ts"
fiRepository: boxlite-ai/boxlite
Length of output: 5924
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ORG_ENTITY="apps/api/src/organization/entities/organization.entity.ts"
BOX_ENTITY="apps/api/src/box/entities/box.entity.ts"
echo "=== organization.entity.ts ==="
sed -n '1,220p' "$ORG_ENTITY" | cat -n
rg -n "id:|`@PrimaryGeneratedColumn`|`@PrimaryColumn`|`@Column`\\(\\{[^}]*type:'uuid'|`@Column`\\(\\{[^}]*type: 'uuid'|uuid" "$ORG_ENTITY" || true
echo -e "\n=== box.entity.ts (organizationId) ==="
sed -n '1,260p' "$BOX_ENTITY" | cat -n
rg -n "organizationId|`@Column`" "$BOX_ENTITY" || true
echo -e "\n=== any explicit uuid validation for organizationId in webhook/audit paths ==="
rg -n "organizationId|uuid|isUUID|validate.*organizationId|ParseUUID" apps/api/src/webhook apps/api/src/audit || trueRepository: boxlite-ai/boxlite
Length of output: 26744
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILES=$(fd -t f -g '*organization-user*.entity.ts' apps/api/src/organization || true)
echo "$FILES"
if [ -n "$FILES" ]; then
f=$(echo "$FILES" | head -n 1)
echo -e "\n=== Inspect $f ==="
sed -n '1,220p' "$f" | cat -n
rg -n "organizationId|`@Column`\\(\\{|`@JoinColumn`|`@ManyToOne`|uuid" "$f" || true
fi
# Also inspect any user/request typing for organizationId usage patterns
echo -e "\n=== Search for request.user.organizationId type hints ==="
rg -n "request\\.user\\.organizationId|organizationId:.*uuid|organizationId\\?:.*uuid" apps/api/src -S | head -n 80Repository: boxlite-ai/boxlite
Length of output: 3320
Align organizationId column types for webhook_initialization / audit_log with organization.id (uuid).
apps/api/src/migrations/1741087887225-migration.ts creates:
webhook_initialization.organizationIdascharacter varyingaudit_log.organizationIdascharacter varying
…but organization.id is uuid, and other tables/relations use uuid (e.g., box.organizationId / organization_user.organizationId). The corresponding TypeORM entities (apps/api/src/webhook/entities/webhook-initialization.entity.ts, apps/api/src/audit/entities/audit-log.entity.ts) also leave organizationId as plain string without type: 'uuid', so the drift is preserved in the ORM mapping. If these store internal org IDs, switch both DB columns (and entity decorators) to uuid to avoid cast-heavy joins and make future FK enforcement straightforward.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/src/migrations/1741087887225-migration.ts` around lines 48 - 50,
Change the organizationId columns from character varying to uuid in the
migration that creates the webhook_initialization and audit_log tables and
update the corresponding entity decorators to use type: 'uuid' for
organizationId; specifically, in the migration (the CREATE TABLE for
"webhook_initialization" and the CREATE for "audit_log") alter the column
definition for "organizationId" to uuid NOT NULL (and adjust defaults if any),
and in the entities webhook-initialization.entity.ts and audit-log.entity.ts
update the `@Column`(...) for organizationId to include type: 'uuid' (and ensure
TypeORM relations/use of organization.id UUID are consistent). Ensure SQL and
entity changes are in sync so joins/FKs can later be enforced without casting.
ce95ae1 to
803bc40
Compare
…uota init The previous step UPDATE'd organization WHERE id='4a1eef70-...' — a UUID that happened to be the admin's default-org id in earlier e2e-ci stack instances. After this PR's DB schema reset (required to recover from #736's pre-launch migration squash being deployed against a stack whose history was already past those migrations), the app re-runs initializeAdminUser at boot and creates a new admin user + auto- generates a new default-org UUID. The hardcoded id no longer matches, UPDATE touches 0 rows, SELECT returns empty, the step fails. Switch the SQL to resolve the admin's default org via a subquery against organization_user (userId='boxlite-admin' AND isDefaultForUser=true) — that membership row is what app code already uses to find the admin's working org, and survives any future schema reset where the org UUID changes.
Pre-#735/#736 box schemas accumulated several columns the new entity no longer touches — boxId, autoArchiveInterval, backup{ErrorReason, RegistryId,Snapshot}, snapshot{,Name}, template{,Id}, artifactRef. Any of them being NOT NULL is enough to fail every box INSERT. Drop them all up-front so the next deploy converges in one shot instead of chasing one bad column per e2e cycle.
#755 #755 edited the squashed baseline file in-place to rename warm_pool.savedImage → warm_pool.image and add box.image, and a pre-#736 stack additionally dropped box.boxId via 0e6b875. TypeORM keys the ledger by class name, so Tokyo's recorded Migration1741087887225 row will never re-run with the new content — producing the live errors column WarmPool.image does not exist column Box.boxId does not exist on POST/GET/DELETE /boxes. This new class adds box.boxId (NOT NULL char(12), backfilled with a 12-hex slice of uuid_generate_v4 so SET NOT NULL holds), box.image (nullable), and warm_pool.image (renamed from savedImage if present, otherwise added). All steps are wrapped in information_schema guards so the file is a no-op on fresh stacks and on any stack that converged via another path. Local-verified on a legacy-shape DB (box without boxId/image, warm_pool with savedImage) and re-run for idempotency.
Summary
apps/api/src/migrations/1741087887225-migration.tspre-deployexpand migrationCREATE TABLEstatements so the baseline reads like final schema definition instead of a replayed migration historyorganization_roleseed data from the baseline; keep the role tables/custom-role API intact[]so the API no longer references removed global role IDsDeployment note
Review notes
pre-deploy/andpost-deploy/now only keep their data-source files until new expand/contract migrations are addedVerification
git diff --checkcd apps && yarn prettier --check \"api/src/migrations/1741087887225-migration.ts\" \"api/src/organization/dto/create-organization-invitation.dto.ts\" \"api/src/organization/dto/update-organization-member-access.dto.ts\" \"api/src/organization/services/default-organization-membership.spec.ts\"cd apps && yarn eslint \"api/src/migrations/1741087887225-migration.ts\" \"api/src/organization/dto/create-organization-invitation.dto.ts\" \"api/src/organization/dto/update-organization-member-access.dto.ts\" \"api/src/organization/services/default-organization-membership.spec.ts\"cd apps && yarn jest --config api/jest.config.ts api/src/organization/services/default-organization-membership.spec.ts api/src/organization/guards/organization-resource-action.guard.spec.ts --runInBandcd apps && yarn tsc -p api/tsconfig.app.json --noEmitcd apps/api && npx ts-node -P ./tsconfig.json -r tsconfig-paths/register -e \"require('./src/migrations/1741087887225-migration')\"Not run
psqland Docker did not expose a running serverSummary by CodeRabbit