Repair Asset Management — Reverse Engineering & Rebuild
Project Progress
Remaining work breakdown
91% → 44 of 48 active weeks (Sprint 20 closed). Denominator: completed 39 + 3 (Sprint 19') + 1 (Sprint 19.5) + 1 (Sprint 20) = 44; remaining UAT (2w) + hyper-care (1.5w) = 3.5w; total 48 (rounded). 44/48 = 91.7% ≈ 91% conservative. Percentage advances at UAT close.
Blueprint
Architecture decisions
withTenant wrapper mandatory — no bare Prisma callsinvoice.status = sentnumbering_sequences + sequence_definitionsexpected_batches.session_count columndaily_metrics_snapshots tableconcurrency=1 (per-org upgrade → backlog B-001)'migrated' source enum on device_repair_codesfinalizeDispatch idempotency (FOR UPDATE + early return)sequence_definitions seed table (global, no RLS)$transaction callback form only (no array form)no-bare-prisma, no-withtenant-in-iteration, no-async-array-mapwithTenant must SET LOCAL ROLE ram_app — superusers bypass all RLS; role switch enforces isolation regardless of connection privilegeExecution
| Sprint | Scope | Status | Verification |
|---|---|---|---|
| S0 | Foundations (monorepo, Docker, CI skeleton) | ✓ Complete | Unit tests |
| S1 | Tenancy & Auth (JWT + RLS) | ✓ Complete | Integration ✓ |
| S2 | Master Data CRUD | ✓ Complete | Unit tests |
| S3 | Asset Receiving | ✓ Complete | Unit tests |
| S4 | QC Workbench (triage, BER review) | ✓ Complete | Unit tests |
| S5 | Inventory & Parts Issue | ✓ Complete | Unit tests |
| S6 | Worksheets & Team Build | ✓ Complete | Unit tests |
| S7 | Outbound Dispatch | ✓ Complete | Unit tests |
| S8 | Invoicing & Pricing | ✓ Complete | Unit tests |
| S9 | Reports & Owner Dashboard | ✓ Complete | Unit tests |
| S10 | TypeScript polish (19 errors resolved) | ✓ Complete | tsc clean |
| S11 | Stub pages (Repairs, Technicians, Settings) | ✓ Complete | Unit tests |
| S12 | Devices page + pagination retrofit | ✓ Complete | Unit tests |
| S13 | drfone-parse BullMQ processor | ✓ Complete | Unit tests |
| S14 | bulk-upload processor + Team page | ✓ Complete | Unit tests |
| S15 | Infra catch-up (PG16, Redis, RLS idempotent) | ✓ Complete | Integration ✓ |
| S16 | Idempotent RLS + BullMQ e2e + CI tracked | ✓ Complete | E2E verified |
| S17 B1 | DrfoneCodeMapping + unmapped queue + reports count + CI all-green | ✓ Complete | CI verified (4 jobs) |
Sprint 17 B1 — what shipped
repair_codes catalogue table + 24 canonical codes seededdrfone_code_mappings table + RLS + FORCE + UNIQUE(org_id, drfone_code)device_repair_codes.repair_code_id FK (nullable) addeddrfone_mapped, drfone_unmappeddrfone / drfone_auto rowsDrfoneCodeMappingService — TenantContext for CRUD, explicit orgId for BullMQ worker (Rule #18)DrfoneMappingsController — 7 routes including resolve endpointGET /initial-qc/unmapped-queue endpointGET /reports/drfone-unmapped-count endpointdrfone-parse.e2e.spec.ts and passingTest coverage
Deferred items
| ID | Item | Status | Blocking trigger |
|---|---|---|---|
| B-001 | BullMQ per-org concurrency upgrade | Deferred | Before second paying tenant |
| B-002 | reserveNumber first-call TOCTOU race | ✓ Resolved S16-1b | — |
| B-003 | Shared-packages tsconfig missing | Deferred | Second engineer onboarding |
| B-004 | Migration 0004 backfill performance (production scale) | Deferred | Sprint 19 production migration |
| B-005 | Remove --passWithNoTests from e2e CI step |
✅ Closed — 3/3 (runs 17–19) | Flag removed; e2e job now fails on zero specs discovered |
| B-006 | Build eslint-plugin-ram-custom as workspace package |
Deferred | Second engineer onboarding (same trigger as B-003) |
| B-007 | Consolidate 12 hand-rolled confirmation dialogs to @ram/ui ConfirmationDialog |
Deferred | On page touch or standalone cleanup sprint |
| B-008 | Extract proxyToApi() helper; migrate 63+ proxy routes |
Deferred | When proxy bug requires multi-file touch, or count crosses ~100 |
| B-009 | Consolidate duplicate repair-codes catalogue endpoints | Deferred | Before QC vs owner UI discrepancy appears |
| B-011 | Per-model colours column + 32-model count correction | Open | Before device intake UI ships |
| B-016 | Override notification upgrade (Postmark email/digest) | Open | > 3 override requests/week observed in production |
| B-017 | Extract shared ROLES constant to @ram/shared package (web + API unified) |
Deferred | Third mirrored constant added, or shared package needed for another reason |
| B-013 | Database backup/restore — B2 multipart export + FK-ordered restore (owner-only) | ✅ Closed — 2026-06-02 · commit 6540fae | — |
| B-018 | listPurchasePrices silent zero-rows (Prisma query-path errors) |
✅ Closed Sprint 19.5 | — |
| B-023 | JWT refresh token flow — replace 8h fixed expiry with refresh/access split | Deferred | Multi-shift warehouse use or token theft concern |
| B-024 | Radix Dialog migration — replace hand-rolled modals with @radix-ui/react-dialog |
Deferred | On page touch or standalone cleanup sprint |
| B-025 | Backup cron automation — scheduled daily B2 export via BullMQ | Open | After B-013 manual backup proven stable in production |
| B-026 | Fastify v5 upgrade — bump @nestjs/platform-fastify + @fastify/helmet v11→v13; remove @ts-expect-error in main.ts:44 |
Deferred | Sprint 21+ cleanup, or Fastify ecosystem forces v5 bump |
| B-029 | Resource monitoring on VPS — Netdata/Grafana; alert if RAM >60% sustained | Open | UAT Day 3 / post-launch operational baseline |
| B-031 | Pre-existing any type cleanup — proper Prisma types in batches/ber-reviews/clients/expected-batch (4 files, ~14 warnings) |
Deferred | Sprint 21+ cleanup; remove file-level eslint-disable |
Immediate actions
Road to completion