Skip to content

Prod release (refactor tenantSchema) - #1493

Merged
rlho merged 3 commits into
prodfrom
main
Jun 4, 2026
Merged

rlho merged 3 commits into
prodfrom
main

Conversation

@rlho

@rlho rlho commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Summary of Changes

Schema Changes

  • No tenant schema changes
  • Schema changed (describe below)

Checklist

  • I linked relevant issue(s) in the Development section
  • I checked for existing implementations and confirmed there is no duplication
  • I thoroughly tested this feature locally
  • I added or updated unit tests (or explained why not in the PR description)
  • I attached screenshots or a video demonstrating the feature (or explained why not in the PR description)
  • I incorporated Copilot's feedback (or explained why not in the PR description), and marked conversations as resolved
  • I confirmed my PR passed all unit and end-to-end (E2E) tests
  • I confirmed there are no conflicts
  • I requested a code review from at least one other teammate

Screenshots / Video

rlho added 3 commits June 3, 2026 14:53
…1238)

Tooling to rewrite stored tenantSchema/{id} documents from the legacy flat
field layout into the canonical nested shape, completing the data side of the
#1238 rename/restructure (Phase 1 = PR #1470 shipped the read-time coercion).

- scripts/migrateTenantSchemaFirestore.ts: dry-run (writes preview JSON, no
  Firestore writes) or apply (backs up each doc to tenantSchemaBackup, then
  full-replaces with merge:false to drop stale legacy top-level keys). Uses the
  same coerceTenantSchema as runtime, so the data-loss fixes from #1470 apply.
- coerceTenantSchema: add migration-detection helpers
  (tenantSchemaFirestoreDocNeedsShapeMigration / isNestedTenantSchemaDocument /
  STALE_LEGACY_TOP_LEVEL_TENANT_SCHEMA_KEYS). Detection also flags nested docs
  whose resources[] still carry legacy training fields.
- package.json: migrate:tenant-schema[:dry-run] scripts; also add
  tsconfig-paths/register to sync:schemas so @/ imports resolve.
- docs + unit tests.

Does NOT run any migration. Applying is a manual, post-prod-deploy step.
Address Copilot review: `--tenant`/`--database` consumed the next argv
entry without checking it exists or isn't another flag, so e.g.
`--tenant --database staging` silently set tenant to "--database" and
failed later with a confusing "No document tenantSchema/--database".
Reject a missing value (or a value starting with `--`) up front with a
clear "Missing value for <flag>" message.
feat(schema): tenantSchema Firestore shape migration (Phase 2 of #1238)
Copilot AI review requested due to automatic review settings June 3, 2026 19:59
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

Tenant Schema Diff (development → production)

This PR targets prod. Review the diff below and confirm every change is acceptable before merging.

Key Differences by Document

📄 Document: itp
   Added keys (10)
     + tenantId
     + mappings
     + form
     + attestations
     + origins
     + training
     + interimHighlightThresholdHours
     + autoCancel
     + emailNotifications
     + termConfig
   Deleted keys (21)
     - timeSensitiveRequestWarning
     - safetyTrainingGoogleFormId
     - name
     - nameForPolicy
     - showNNumber
     - showSponsor
     - showSetup
     - showEquipment
     - showStaffing
     - showCatering
     - showHireSecurity
     - showBookingTypes
     - supportVIP
     - supportWalkIn
     - emailMessages
     - schoolMapping
     - programMapping
     - roleMapping
     - agreements
     - logo
     - permissionLabels
   Updated keys (2)
     ~ tenant
     ~ resources
📄 Document: mc
   Added keys (11)
     + tenantId
     + mappings
     + form
     + attestations
     + origins
     + training
     + supportPA
     + supportLiaison
     + interimHighlightThresholdHours
     + emailNotifications
     + termConfig
   Deleted keys (21)
     - schoolMapping
     - showNNumber
     - nameForPolicy
     - showStaffing
     - programMapping
     - logo
     - supportVIP
     - agreements
     - emailMessages
     - showEquipment
     - safetyTrainingGoogleFormId
     - showSetup
     - roleMapping
     - showBookingTypes
     - showHireSecurity
     - permissionLabels
     - showSponsor
     - timeSensitiveRequestWarning
     - supportWalkIn
     - name
     - showCatering
   Updated keys (5)
     ~ calendarConfig.timeSensitiveRequestWarning.message
     ~ calendarConfig.timeSensitiveRequestWarning.policyLink
     ~ calendarConfig.timeSensitiveRequestWarning.isActive
     ~ resources
     ~ tenant
Full dry-run output
🚀 Starting collection copy process...
📊 Options: {
  sourceCollection: 'tenantSchema',
  targetCollection: 'tenantSchema',
  sourceDatabase: 'development',
  targetDatabase: 'production',
  dryRun: true,
  reportFile: 'dry-run-pr-production-details.json'
}
📊 Using database names: {
  development: 'default',
  staging: 'booking-app-staging',
  production: 'booking-app-prod'
}
📡 Connected to source database (development -> default)
🔍 Testing connection to default...
✅ Successfully connected to default

🔍 [DRY RUN] Would back up 2 tenantSchema documents in booking-app-prod to tenantSchemaBackup
  📄 Would create backup document: tenantSchemaBackup/itp-backup-copy-2026-06-03_20-00-55-530
  📄 Would create backup document: tenantSchemaBackup/mc-backup-copy-2026-06-03_20-00-55-530

📦 Step 2: Copying tenantSchema to tenantSchema...

🔍 [DRY RUN] Analyzing tenantSchema to tenantSchema in booking-app-prod...
🔍 Testing connection to booking-app-prod...
✅ Successfully connected to booking-app-prod
📋 Found 2 tenantSchema documents to copy
📋 Found 2 existing tenantSchema documents in target
🔎 Calculating key-level diffs...

📄 Document: itp
   Target exists: yes
   Added keys (10)
     + tenantId
     + mappings
     + form
     + attestations
     + origins
     + training
     + interimHighlightThresholdHours
     + autoCancel
     + emailNotifications
     + termConfig
   Deleted keys (21)
     - timeSensitiveRequestWarning
     - safetyTrainingGoogleFormId
     - name
     - nameForPolicy
     - showNNumber
     - showSponsor
     - showSetup
     - showEquipment
     - showStaffing
     - showCatering
     - showHireSecurity
     - showBookingTypes
     - supportVIP
     - supportWalkIn
     - emailMessages
     - schoolMapping
     - programMapping
     - roleMapping
     - agreements
     - logo
     - permissionLabels
   Updated keys (2)
     ~ tenant
     ~ resources

📄 Document: mc
   Target exists: yes
   Added keys (11)
     + tenantId
     + mappings
     + form
     + attestations
     + origins
     + training
     + supportPA
     + supportLiaison
     + interimHighlightThresholdHours
     + emailNotifications
     + termConfig
   Deleted keys (21)
     - schoolMapping
     - showNNumber
     - nameForPolicy
     - showStaffing
     - programMapping
     - logo
     - supportVIP
     - agreements
     - emailMessages
     - showEquipment
     - safetyTrainingGoogleFormId
     - showSetup
     - roleMapping
     - showBookingTypes
     - showHireSecurity
     - permissionLabels
     - showSponsor
     - timeSensitiveRequestWarning
     - supportWalkIn
     - name
     - showCatering
   Updated keys (5)
     ~ calendarConfig.timeSensitiveRequestWarning.message
     ~ calendarConfig.timeSensitiveRequestWarning.policyLink
     ~ calendarConfig.timeSensitiveRequestWarning.isActive
     ~ resources
     ~ tenant

📊 Dry Run Diff Summary
   Source documents: 2
   Target documents: 2
   Changed documents: 2
   Unchanged documents: 0
   Total added keys: 21
   Total deleted keys: 42
   Total updated keys: 7
✅ [DRY RUN] Would copy 2 tenantSchema documents to tenantSchema in booking-app-prod
💾 Wrote detailed dry-run report to dry-run-pr-production-details.json

📊 Copy Summary:
✅ Successful operations: 2
  - Backup (production): 2 documents would be backed up
  - Update (production): 2 documents would be copied

🎉 tenantSchema backup and update process completed!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a one-off Firestore migration path to rewrite tenantSchema/{tenantId} documents into the canonical nested tenant schema shape, aligning stored data with the runtime coercion logic and documenting the rollout process.

Changes:

  • Introduces scripts/migrateTenantSchemaFirestore.ts (dry-run, backups, full replace with merge:false) to persist the coerced nested schema in Firestore.
  • Extends lib/tenant/coerceTenantSchema.ts with helpers/constants to detect when a stored doc still needs a shape rewrite.
  • Adds unit coverage and documentation for the migration workflow; updates package.json scripts to support @/ path resolution in scripts.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
booking-app/tests/unit/coerce-tenant-schema-migration.unit.test.ts Adds unit tests for new “needs shape migration” detection helpers.
booking-app/scripts/migrateTenantSchemaFirestore.ts New CLI script to back up and rewrite tenant schemas into the canonical nested shape.
booking-app/package.json Adds migration scripts and enables tsconfig-paths/register for schema-related scripts.
booking-app/lib/tenant/coerceTenantSchema.ts Adds stale-legacy-key detection helpers/constants for migration tooling.
booking-app/docs/TENANT_SCHEMA_FIRESTORE_MIGRATION.md Documents how to run and roll out the Firestore tenant schema shape migration.
booking-app/docs/SCHEMA_SYNC_GUIDE.md Links schema sync docs to the new one-time shape migration guide.

Comment on lines +182 to +185
const migrated = coerceTenantSchema(raw, tenantId);
const payload = serializeForFirestore(migrated) as Record<string, unknown>;
const unchanged = stableStringify(raw) === stableStringify(payload);

Comment on lines +16 to +19
import {
coerceTenantSchema,
tenantSchemaFirestoreDocNeedsShapeMigration,
} from "../lib/tenant/coerceTenantSchema";
@rlho
rlho merged commit a9ad7e8 into prod Jun 4, 2026
74 checks passed
@rlho rlho mentioned this pull request Jul 7, 2026
2 of 11 tasks

This branch was previously deployed

3 inactive deployments
production — 3c6aafe2 Deployed Jun 4, 2026 by rlho via trigger-auto-cancel-unapproved (production) #848
staging — 3c6aafe2 Deployed Jun 4, 2026 by rlho via trigger-auto-cancel-unapproved (staging) #848
dev — 3c6aafe2 Deployed Jun 3, 2026 by rlho via deploy #705
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants