fix(migrations): use exact smartdata collection names in route unification migration

This commit is contained in:
2026-04-13 18:08:36 +00:00
parent 19398ea836
commit 36b629676f
5 changed files with 36 additions and 12 deletions

17
AGENTS.md Normal file
View File

@@ -0,0 +1,17 @@
# Agent Instructions for dcrouter
## Database & Migrations
### Collection Names
smartdata uses the **exact class name** as the MongoDB collection name. No lowercasing.
- `StoredRouteDoc` → collection `StoredRouteDoc`
- `TargetProfileDoc` → collection `TargetProfileDoc`
- `RouteDoc` → collection `RouteDoc`
When writing migrations in `ts_migrations/index.ts`, use the exact class name casing in `ctx.mongo!.collection('ClassName')` and `db.listCollections({ name: 'ClassName' })`.
### Migration Rules
- All DB schema migrations go EXCLUSIVELY in `ts_migrations/index.ts` as smartmigration steps.
- NEVER put migration logic in application code (services, managers, startup hooks).
- Migration step `.to()` version must match the release version so smartmigration can plan the step.
- Steps must be idempotent — smartmigration may re-run them in skip-forward resume mode.

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 2026-04-13 - 13.16.1 - fix(migrations)
use exact smartdata collection names in route unification migration
- Update the 13.16.0 migration to rename StoredRouteDoc to RouteDoc using case-sensitive collection names
- Apply the origin backfill against the RouteDoc collection and drop RouteOverrideDoc with matching class-name casing
- Clarify migration description and comments to reflect smartdata's exact class-name collection mapping
## 2026-04-13 - 13.16.0 - feat(routes) ## 2026-04-13 - 13.16.0 - feat(routes)
unify route storage and management across config, email, dns, and API origins unify route storage and management across config, email, dns, and API origins

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '13.16.0', version: '13.16.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }

View File

@@ -95,30 +95,30 @@ export async function createMigrationRunner(
}) })
.step('unify-routes-rename-collection') .step('unify-routes-rename-collection')
.from('13.8.2').to('13.16.0') .from('13.8.2').to('13.16.0')
.description('Rename storedroutedoc → routedoc, add origin field, drop routeoverridedoc') .description('Rename StoredRouteDoc → RouteDoc, add origin field, drop RouteOverrideDoc')
.up(async (ctx) => { .up(async (ctx) => {
const db = ctx.mongo!; const db = ctx.mongo!;
// 1. Rename storedroutedoc → routedoc // 1. Rename StoredRouteDoc → RouteDoc (smartdata uses exact class names)
const collections = await db.listCollections({ name: 'storedroutedoc' }).toArray(); const collections = await db.listCollections({ name: 'StoredRouteDoc' }).toArray();
if (collections.length > 0) { if (collections.length > 0) {
await db.renameCollection('storedroutedoc', 'routedoc'); await db.renameCollection('StoredRouteDoc', 'RouteDoc');
ctx.log.log('info', 'Renamed storedroutedoc → routedoc'); ctx.log.log('info', 'Renamed StoredRouteDoc → RouteDoc');
} }
// 2. Set origin='api' on all migrated docs (they were API-created) // 2. Set origin='api' on all migrated docs (they were API-created)
const routeCol = db.collection('routedoc'); const routeCol = db.collection('RouteDoc');
const result = await routeCol.updateMany( const result = await routeCol.updateMany(
{ origin: { $exists: false } }, { origin: { $exists: false } },
{ $set: { origin: 'api' } }, { $set: { origin: 'api' } },
); );
ctx.log.log('info', `Set origin='api' on ${result.modifiedCount} migrated route(s)`); ctx.log.log('info', `Set origin='api' on ${result.modifiedCount} migrated route(s)`);
// 3. Drop routeoverridedoc collection // 3. Drop RouteOverrideDoc collection
const overrideCollections = await db.listCollections({ name: 'routeoverridedoc' }).toArray(); const overrideCollections = await db.listCollections({ name: 'RouteOverrideDoc' }).toArray();
if (overrideCollections.length > 0) { if (overrideCollections.length > 0) {
await db.collection('routeoverridedoc').drop(); await db.collection('RouteOverrideDoc').drop();
ctx.log.log('info', 'Dropped routeoverridedoc collection'); ctx.log.log('info', 'Dropped RouteOverrideDoc collection');
} }
}); });

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '13.16.0', version: '13.16.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }