14 KiB
title, tags, aliases, created, updated, source
| title | tags | aliases | created | updated | source | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Postgres Runtime Cutover Status |
|
|
2026-05-31 | 2026-06-06 | backend integrate-main-into-development@41087c7 + deployment main@8764fdf |
Postgres Runtime Cutover Status
Current branch: backend
integrate-main-into-development, version2.9.12.Bottom line: Migration complete as of 2026-06-06, backend v2.9.12. MongoDB and Mongoose have been fully removed from the runtime. PostgreSQL (Drizzle ORM) is the sole database. All 11 repository domains use DrizzleXxxRepo exclusively. No dual-write wrappers are active. TypeScript compilation: 0 errors.
Migration Status
| Phase | Status |
|---|---|
| Schema design | Complete — 32 tables, 19 migrations (0000–0019) |
| Drizzle repos | Complete — all 11 factory domains have a DrizzleXxxRepo |
| Dual-write wrappers | Decommissioned — removed from runtime as of v2.9.12 |
| Write cutover | Complete — all writes go to PostgreSQL only |
| Read cutover | Complete — all reads from PostgreSQL |
| Mongoose removal | Complete — no Mongoose imports in runtime src/ |
| TypeScript compilation | 0 errors |
Schema and Repository Coverage
Tables with Full Drizzle Schema
All tables below have a .ts schema file in src/db/schema/ and are covered by at least one migration:
Infrastructure: id_map, pg_dualwrite_gaps
Auth/Users: users, user_passkeys, user_refresh_tokens, telegram_links, telegram_sessions
Marketplace: categories, purchase_requests, purchase_request_delivery_info, purchase_request_delivery_address, purchase_request_seller_delivery_info, purchase_request_service_info, purchase_request_specifications, purchase_request_preferred_sellers, delivery_attempts, seller_offers, request_templates
Payments: payments, payment_quotes, funds_ledger_entries, derived_destinations, derived_destination_sweeps
Points/Wallet: point_transactions, trezor_accounts, trezor_derived_addresses
Config/Ops: config_settings, config_setting_history, shop_settings, addresses, reviews
Content/Social: blog_posts, notifications, disputes, chats
Total: 32 tables across 19 migrations (0000–0019).
Tables with a Drizzle Repository
| Drizzle Repo | Domain |
|---|---|
DrizzleUserRepo |
Users, passkeys, refresh tokens |
DrizzlePaymentRepo |
Payments, funds ledger |
DrizzleMarketplaceRepo |
Categories, purchase requests, seller offers, request templates |
DrizzleDerivedDestinationRepo |
Derived destinations, sweeps |
DrizzleTrezorAccountRepo |
Trezor accounts, derived addresses |
DrizzlePointsRepo |
Point transactions |
DrizzleNotificationRepo |
Notifications |
DrizzleDisputeRepo |
Disputes |
DrizzleBlogRepo |
Blog posts |
DrizzleChatRepo |
Chats (JSONB shim; Chat normalization is an optional future improvement) |
DrizzleReleaseHoldRepo |
Release holds (bridges payments + purchase_requests) |
Tables with schema but no dedicated Drizzle repo (handled via store facades): addresses, shop_settings, config_settings / config_setting_history, telegram_links / telegram_sessions, reviews.
Migration Count
19 migrations landed: 0000 through 0019.
| Migration | Key change |
|---|---|
| 0000 | Core enums + id_map + categories |
| 0001 | trezor_accounts + trezor_derived_addresses |
| 0002 | Schema reset (drops 0000/0001 tables, adds category self-FK) |
| 0003 | Full rebuild: all core domain tables (users, payments, marketplace, funds ledger, derived destinations, points, trezor) |
| 0004 (×2) | Funds ledger immutability trigger; seller_offer physical FKs |
| 0005 | pg_dualwrite_gaps; payment FKs; legacy_object_id uniques; pending payment index fix |
| 0006 | budget_currency crypto-only CHECK on purchase_requests |
| 0007 | Drops 0006 constraint; sets USDT default |
| 0008 | offer_currency adds TRY; creates payment_quotes |
| 0009 | Active category deduplication; categories_active_name_norm_uq |
| 0010 | request_templates; purchase_request_specifications unique constraint |
| 0011 | chats + chat enums |
| 0012 | disputes |
| 0013 | Money-integrity CHECK constraints; ledger TRUNCATE guard; id_map composite PK |
| 0014 | Physical NOT VALID FKs across schema; validates all |
| 0015 | Ledger immutability extended: UPDATE + DELETE triggers |
| 0016 | address_type enum + addresses table |
| 0017 | guard value added to user_role enum |
| 0018 | AI request fields |
| 0019 | payment_provider enum: added escrow |
What Uses Postgres Now
All domains are PostgreSQL-only. The table below summarises the runtime topology for reference.
| Area | Runtime status | Notes |
|---|---|---|
| Postgres connection | Required — PG_URL must be set |
Store facades use src/infrastructure/postgres/client.ts; the broader src/db/ Drizzle layer and repository factory are fully populated. |
| Runtime schema bootstrap | Implemented for auth, config, address, and reference stores | Auth tables bootstrapped from src/services/auth/postgresAuthSchema.ts; store facades bootstrap their own tables at startup. |
| Health observability | Implemented in /api/health |
checks.postgres reports configured, required, storeModes, enabledStores, and enabledStoreCount. Mongoose health check is no longer present. |
| Auth-owned user store | PG-backed | Auth, passkey, Telegram auth/link/session/temp-verification, and /api/user profile paths use the auth-store facade pointing at Postgres. legacy_object_id column retained for id-map compatibility. |
| Confirmation-threshold runtime config | PG-backed | ConfigSetting / ConfigSettingHistory access routes through the config-store facade. |
| User addresses | PG-backed | /api/addresses CRUD uses the address-store facade. |
| Marketplace categories | PG-backed | CategoryService and the default General category path use the category-store facade. categories_active_name_norm_uq enforced. |
| Level configuration | PG-backed | PointsService level reads use the level-config facade. LEVEL_STORE=postgres accepted as compatibility alias. |
| Shop settings | PG-backed | Shop settings controller, seller payment rail resolution, and review enable/disable checks use the shop-settings facade. Seller shop lookup handles both uuid and legacy id formats. |
| Marketplace reviews | PG-backed | Review list/summary/create routes use the review-store facade. |
| Notifications | PG-backed | NotificationService uses getNotificationRepo() for create/list/read/delete/count paths. |
| Oracle quote persistence | PG write when ORACLE_QUOTING_ENABLED=true |
/api/payment/request-network/intents writes payment_quotes to PG. Mongo mirror path removed. |
| Funds ledger | PG-backed | appendFundsLedgerEntry and getFundsBalanceBy* call getPaymentRepo() which resolves to DrizzlePaymentRepo. |
| Payments and escrow state | PG-backed | All payment services use Drizzle repos; Mongoose Payment model removed. |
| Derived destinations and sweeps | PG-backed | getDerivedDestinationRepo() resolves to DrizzleDerivedDestinationRepo. |
| Points/referrals/transactions | PG-backed | getPointsRepo() resolves to DrizzlePointsRepo. |
| Chat/messages | PG-backed (JSONB shim) | getChatRepo() resolves to DrizzleChatRepo. Participants/messages are stored as JSONB blobs; normalization into relational child tables is an optional future improvement. |
| Disputes/blog | PG-backed | Both resolve to Drizzle repos. |
| ReleaseHold | PG-backed | getReleaseHoldRepo() resolves to DrizzleReleaseHoldRepo. |
| Backfill/verify scripts | Available as operator tooling | MIGRATION_PG_URL drives all backfill scripts. Not run automatically at startup. |
| Guard user role | PG schema-ready | Migration 0017 adds guard to the user_role enum. |
| Seeds | Postgres-capable | Seeds in src/seeds/* are store-aware and idempotent under MONGO_CONNECT_MODE=never. |
What Was Mongo-Backed (Historical)
All domains are now PostgreSQL-only as of v2.9.12. The following were the remaining Mongo-backed areas prior to the final cutover:
- User reads — Auth-owned users were PG-backed for writes but reads remained Mongo-authoritative until the full auth cutover.
- Marketplace requests/offers/templates reads —
REPO_MARKETPLACEdefaulted to Mongo; read cutover required smoke coverage. - Payments and escrow state reads — Payment services called Mongoose documents directly for reads until the final payment-domain wiring was completed.
- Derived destinations and sweeps —
REPO_DERIVED_DESTINATIONdefaulted to Mongo. - Points/referrals/transactions —
REPO_POINTSdefaulted to Mongo. - Chat/messages —
getChatRepo()defaulted to Mongo; JSONB shim was the Drizzle path. No dual-write wrapper existed. - Disputes/blog — Defaulted to Mongo until
REPO_DISPUTE/BLOG_STOREwere flipped. - ReleaseHold — No dual-write wrapper; required explicit flip.
All of the above are now fully PostgreSQL-backed. MongoDB and Mongoose have been removed from the runtime.
Env Flag Reality
All *_STORE=mongo and REPO_*=mongo env flags are obsolete — the repository factory only supports postgres/pg mode. MONGO_URI and MONGO_CONNECT_MODE have been removed from the runtime.
| Flag | Current meaning |
|---|---|
MONGO_URI |
REMOVED — MongoDB has been removed from the runtime. |
MONGO_CONNECT_MODE |
REMOVED — MongoDB has been removed from the runtime. |
AUTH_STORE |
OBSOLETE — only postgres is valid. Setting to mongo has no effect. |
CONFIG_STORE |
OBSOLETE — only postgres is valid. |
ADDRESS_STORE |
OBSOLETE — only postgres is valid. |
CATEGORY_STORE |
OBSOLETE — only postgres is valid. |
LEVEL_CONFIG_STORE |
OBSOLETE — only postgres is valid. LEVEL_STORE=postgres accepted as alias. |
SHOP_SETTINGS_STORE |
OBSOLETE — only postgres is valid. |
REVIEW_STORE |
OBSOLETE — only postgres is valid. |
NOTIFICATION_STORE / REPO_NOTIFICATION |
OBSOLETE — only postgres/pg is valid. |
PG_URL |
REQUIRED — PostgreSQL is the sole database. All store facades and repos require this. |
MIGRATION_PG_URL |
Used by backfill scripts and migration runbooks; not part of normal request handling. |
REPO_PAYMENT |
OBSOLETE — only postgres is valid. All payment services use DrizzlePaymentRepo. |
REPO_MARKETPLACE |
OBSOLETE — only postgres is valid. All marketplace writes and reads route through DrizzleMarketplaceRepo. |
REPO_USER, REPO_POINTS, REPO_DERIVED_DESTINATION, REPO_TREZOR |
OBSOLETE — only postgres is valid. All resolve to their respective Drizzle repos. |
REPO_DISPUTE / DISPUTE_STORE, REPO_BLOG / BLOG_STORE |
OBSOLETE — only postgres is valid. |
REPO_CHAT / CHAT_STORE |
OBSOLETE — only postgres is valid. DrizzleChatRepo is the sole chat repo. |
REPO_RELEASE_HOLD / RELEASE_HOLD_STORE |
OBSOLETE — only postgres is valid. |
ORACLE_QUOTING_ENABLED |
Enables server-side quote computation and the payment_quotes PG write in checkout. |
What's Next (Post-Migration)
- Prod backfill — If the production instance was running Mongo-backed data before the cutover, a one-time backfill from Mongo to Postgres under a maintenance window is required. Use
MIGRATION_PG_URL+MIGRATION_MONGO_URLwith the existing backfill scripts. Validate row counts before switching prod traffic. - Chat normalization — The
DrizzleChatRepocurrently stores participants and messages as JSONB blobs rather than normalized relational child tables. This is an optional future improvement; it does not block current operation but would enable richer querying and FK integrity on chat data. payment_providerenumescrowvalue — Confirm migration 0019 has been applied on all target databases (addsescrowto thepayment_providerenum). If not already run, apply it before using escrow-provider payment records.
Recent Progress Since Last Update (2.8.37 → 2.9.12)
- 2.8.38–2.8.46: Complete dual-write repos for all remaining domains; Drizzle migrations pipeline finalized; TTL scheduler added; shop lookup bug-fixed.
- 2.8.47: Seeds made Postgres-capable and idempotent for PG-only boot (
MONGO_CONNECT_MODE=never). - 2.8.48–2.8.49: Fresh-DB PG migrate + seed path corrected; 0013/0014 migrations made valid for a fresh
drizzle-kit migraterun. - 2.8.50: Admin user counts routed through postgres-capable stores; admin user management works end-to-end under PG.
- 2.8.51–2.8.53: PG response serialization and id resolution in marketplace purchase-request paths corrected; user creation and purchase request unblocked.
- 2.8.54: Guard user role added across auth and user management; migration 0017 adds guard to user_role enum.
- 2.8.55: Chat routes fixed and notifications deliver in real time.
- 2.8.56: Seller shop lookup made tolerant of uuid/legacy id formats.
- 2.8.57–2.8.60: Telegram Mini App in-shell shop, account tab parity, shopping cart.
- 2.8.61: Direct-transfer checkout option for non-web3 users.
- 2.8.62–2.8.64: Points level boundary fixes, legacy 24-hex user id support, seller ratings from real published reviews.
- 2.8.65: Chat participant names populated on Postgres path, participant canonicalization.
- 2.8.66–2.8.69: Telegram: product-style template cards, in-shell template detail, web-app-parity templates, settings/addresses in-shell, theme/dark mode, solar-style icons, avatar upload, achievements.
- 2.8.70: Telegram in-shell settings and addresses, theme from central config.
- 2.8.71–2.8.73: Telegram: solar-style icons, avatar URL fixes, inline email verify, web links keep app alive, remove escrow-states.
- 2.8.74: Telegram chat own-message detection, read-only email field.
- 2.8.75: Self-contained email-change flow with visible code entry.
- 2.8.76: Telegram send-code always reveals verify panel.
- 2.8.77: Telegram keep email code panel mounted after sending.
- 2.8.78: Telegram system messages neutral + post-delivery seller review.
- 2.8.79: Request template maxUsage made truly optional; template creation 500 fix.
- 2.9.x: Full MongoDB/Mongoose removal — all Mongoose models replaced by Drizzle repos, dual-write decommissioned, TypeScript compiles with 0 errors (2026-06-06).