11 KiB
PRD — Mongo Retirement: Full Code Nuke
Status: In Progress
Date: 2026-06-06
Scope: Remove every Mongoose/MongoDB reference from the codebase and replace Mongo-style ObjectId fields with plain UUID strings throughout.
Context
The Mongo→Postgres migration scaffolding is complete:
- 25 Drizzle schemas cover all 23 collections
- 11 Drizzle repos, 11 Mongo repos, 9 DualWrite fan-out repos
- Backfill scripts written (not yet run against production)
- Factory defaults to
mongo; reads not yet cut over - Chat uses a JSONB shim (acceptable for now — normalize later)
This PRD covers the code-level retirement: delete all Mongoose artifacts, flip the factory to Postgres-only, remove MongoDB from docker-compose and package.json, and replace Types.ObjectId with string (UUID) across every interface and schema.
Production data migration (backfill execution + read-cutover per domain) is a separate, human-gated operation and is NOT in scope here.
Goals
- Zero
mongooseormongodbimports anywhere inbackend/ - Zero
Schema.Types.ObjectId/Types.ObjectIdfield types - Zero
_id: ObjectIdinterface declarations (replaced withid: string) - Zero
ObjectId(...)constructors or.toString()coercions on IDs - MongoDB service removed from all docker-compose files
mongooseremoved frompackage.jsonMONGODB_URI/MONGO_*env vars removed from config and docs- Factory defaults to
pg; Mongo and DualWrite modes deleted - Seeds and scripts updated to target Postgres only
- Frontend: legacy ObjectId validation path removed
Out of Scope
- Backfill execution against production data
- Production env var changes (
REPO_*,MONGO_CONNECT_MODE) - Chat normalization (JSONB → child tables) — tracked separately
- Drizzle schema changes (schemas are already correct)
- Any Drizzle repo logic changes
Phased Work Plan
Phase 1 — Factory Cutover & Repo Deletion (Day 1)
1.1 Factory: delete Mongo + DualWrite modes
- File:
src/db/repositories/factory.ts - Change: remove all
mongoanddualbranches; every domain returns its Drizzle repo directly - Remove
REPO_*env flag checks (no longer needed) - Remove all imports of Mongo repos and DualWrite repos
1.2 Delete Mongo repo files (11 files)
src/db/repositories/mongo/MongoUserRepo.ts
src/db/repositories/mongo/MongoPaymentRepo.ts
src/db/repositories/mongo/MongoPointsRepo.ts
src/db/repositories/mongo/MongoMarketplaceRepo.ts
src/db/repositories/mongo/MongoBlogRepo.ts
src/db/repositories/mongo/MongoNotificationRepo.ts
src/db/repositories/mongo/MongoDisputeRepo.ts
src/db/repositories/mongo/MongoTrezorAccountRepo.ts
src/db/repositories/mongo/MongoDerivedDestinationRepo.ts
src/db/repositories/mongo/MongoChatRepo.ts
src/db/repositories/mongo/MongoReleaseHoldRepo.ts
src/db/repositories/mongo/index.ts
1.3 Delete DualWrite repo files (9 files)
src/db/repositories/dual/DualWriteUserRepo.ts
src/db/repositories/dual/DualWritePaymentRepo.ts
src/db/repositories/dual/DualWritePointsRepo.ts
src/db/repositories/dual/DualWriteMarketplaceRepo.ts
src/db/repositories/dual/DualWriteBlogRepo.ts
src/db/repositories/dual/DualWriteNotificationRepo.ts
src/db/repositories/dual/DualWriteDisputeRepo.ts
src/db/repositories/dual/DualWriteTrezorAccountRepo.ts
src/db/repositories/dual/DualWriteDerivedDestinationRepo.ts
src/db/repositories/dual/index.ts
Phase 2 — Mongoose Model Deletion & Interface Extraction (Day 1–2)
2.1 Extract pure TS interfaces from each model file
For each of the 24 model files in src/models/, the plan is:
- Keep the
I<Name>TypeScript interface (withid: stringreplacing_id: Types.ObjectId) - Delete the
new Schema(...)definition, virtual fields, pre/post hooks - Delete the
mongoose.model<I<Name>>(...)export - Delete the mongoose import
The interface files move to src/types/models/ (or inline into the Drizzle schema files as inferred types).
2.2 Convert all _id → id: string in interfaces
Key changes per domain:
IUser._id: Types.ObjectId→id: stringICategory._id→id: string,parentId: string | nullIPurchaseRequest._id→id: string,buyerId/sellerId: stringISellerOffer._id→id: string,sellerId/purchaseRequestId: stringIPayment._id→id: string, polymorphic fields →stringIChat._id→id: string,senderId/userId: stringIDispute._id→id: string, all ref fields →string- All others follow same pattern
2.3 Delete src/models/ directory after interfaces extracted
Phase 3 — Mongoose Connection & Config Removal (Day 2)
3.1 src/infrastructure/database/connection.ts
- Remove
mongoose.connect()call and all Mongo connection logic - Remove
MONGO_CONNECT_MODEhandling - Keep only the Postgres pool initialization
3.2 src/shared/config/index.ts
- Remove
mongoUrifield - Remove
MONGODB_URIenv var read
3.3 src/services/auth/authStore.ts
- Remove
AUTH_FALLBACK_MONGO,AUTH_MIRROR_MONGO,MONGO_CONNECT_MODEbranches - Auth reads only from Postgres
3.4 src/services/health/healthCheckService.ts
- Remove MongoDB health check
- Remove
MONGO_CONNECT_MODEreference
3.5 src/app.ts
- Remove
mongoose.connect()/connectMongo()call on startup - Remove
p.userId.toString()ObjectId coercions (already string)
Phase 4 — Seeds & Scripts Cleanup (Day 2)
4.1 Seeds (src/seeds/)
- Remove
mongoose.connect()from all 7 seed files - Seeds already have PG-aware paths; remove Mongo dual-path
seedUsers.ts,seedLevels.ts,seedCategories.ts, etc.
4.2 Scripts (src/scripts/)
- Remove Mongoose imports from 13 scripts
- Scripts that only operated on Mongo (e.g.
clearChats.ts,updateRequestStatus.ts) — convert to Postgres queries or delete if obsolete
Phase 5 — Backfill Infrastructure (Day 3)
5.1 Archive backfill scripts (don't delete — needed for production data migration)
- Move
src/db/backfill/→src/db/backfill/_archive/ - OR keep as-is but add a
.nocompileflag / remove from tsconfig paths - The backfill scripts import mongoose (to read from Mongo) — they're tools for ops, not app code
5.2 Remove verification layer Mongo references
src/db/verify/shadowRead.ts— remove Mongo comparison pathsrc/db/verify/rowCounts.ts— remove Mongo row count queriessrc/db/verify/checksums.ts— remove Mongo checksum queriessrc/db/verify/reconcile.ts— keep (handlespg_dualwrite_gapsreplay, still useful)
5.3 _idMap.ts — keep as a utility for ops scripts only; remove from app imports
Phase 6 — Docker & Dependencies (Day 3)
6.1 docker-compose.dev.yml
- Remove
mongodbservice block - Remove
depends_on: mongodbfrom backend service - Remove all
*_STORE=mongoenv vars (Auth, Config, Address, etc.) - Remove
mongodb_datavolume
6.2 docker-compose.production.yml
- Same: remove mongodb service, depends_on, volume
6.3 deployment/docker-compose.yml
- Same: remove mongodb service block
6.4 backend/package.json
- Remove
mongoosefrom dependencies - Remove
mongodb-memory-serverfrom devDependencies
6.5 .env.example / .env.development / .env.local
- Remove
MONGODB_URI,MONGO_CONNECT_MODE,AUTH_FALLBACK_MONGO,AUTH_MIRROR_MONGO - Remove
MONGO_INITDB_*vars
Phase 7 — Frontend ID Validation Cleanup (Day 3)
7.1 Remove ObjectId validation branch
frontend/src/sections/request-template/view/seller-shop-view.tsx:78- Remove the "legacy 24-hex Mongo ObjectId" validation path
- Keep only UUID validation
7.2 Audit frontend for other ObjectId references
grep -r 'ObjectId\|[0-9a-f]{24}' frontend/src/- Remove any other legacy ID format handling
Phase 8 — TypeScript Compilation Check (Day 3)
npm run tsc— fix all remaining type errors from the migration- Common issues:
.toString()on already-string IDs,_idvsidmismatches, missing UUID imports
Files to Delete (Complete List)
Mongoose Model Files (24)
backend/src/models/User.ts
backend/src/models/Category.ts
backend/src/models/PurchaseRequest.ts
backend/src/models/SellerOffer.ts
backend/src/models/Payment.ts
backend/src/models/Chat.ts
backend/src/models/Dispute.ts
backend/src/models/Review.ts
backend/src/models/Address.ts
backend/src/models/Notification.ts
backend/src/models/TelegramLink.ts
backend/src/models/TelegramSession.ts
backend/src/models/TempVerification.ts
backend/src/models/TrezorAccount.ts
backend/src/models/DerivedDestination.ts
backend/src/models/FundsLedgerEntry.ts
backend/src/models/PointTransaction.ts
backend/src/models/RequestTemplate.ts
backend/src/models/BlogPost.ts
backend/src/models/ConfigSetting.ts
backend/src/models/ConfigSettingHistory.ts
backend/src/models/LevelConfig.ts
backend/src/models/ShopSettings.ts
backend/src/models/index.ts
Mongo Repos (11+index)
backend/src/db/repositories/mongo/ (entire directory)
DualWrite Repos (9+index)
backend/src/db/repositories/dual/ (entire directory)
ID Migration Pattern
Every interface field that was Types.ObjectId or Schema.Types.ObjectId becomes string (UUID).
Before:
interface ISellerOffer {
_id: Types.ObjectId;
sellerId: Types.ObjectId | string;
purchaseRequestId: Types.ObjectId | string;
}
After:
interface ISellerOffer {
id: string; // UUID
sellerId: string;
purchaseRequestId: string;
}
Any code doing someDoc._id.toString() → someDoc.id (already a string).
Any code doing new mongoose.Types.ObjectId(value) → just use value as string.
Risk Register
| Risk | Mitigation |
|---|---|
| App breaks because Mongo isn't seeded in dev | Run npm run seed:pg before removing Mongo from docker-compose |
Type errors cascade from _id → id rename |
Fix systematically: models first, then services/routes |
| Backfill scripts break (they import mongoose) | Keep backfill dir outside tsconfig compilation scope |
| Auth fallback to Mongo breaks login | Auth already has PG path; remove fallback gate |
| Chat reads fail (JSONB shim) | JSONB shim already works; normalization is future work |
Acceptance Criteria
grep -r "mongoose" backend/src/ --include="*.ts"returns zero hits (excluding backfill archive)grep -r "Types.ObjectId\|Schema.Types.ObjectId" backend/src/returns zero hitsgrep -r "mongodb" backend/package.jsonreturns zero hitsgrep -r "MONGODB_URI\|MONGO_CONNECT_MODE" backend/src/returns zero hitsnpm run tscexits 0- Backend starts with
MONGO_CONNECT_MODE=never(or removed) andREPO_*=pg(or removed) - Seed scripts populate Postgres successfully
- All docker-compose files have no
mongodbservice