# ADR-028: Migration Architecture Refactor (Staging Queue & Post-Migration Cleanup) **Status:** Active **Date:** 2026-05-22 **Decision Makers:** Senior Full Stack Developer, Lead Architect **Related Documents:** - [Feature Specification (spec.md)](file:///e:/np-dms/lcbp3/specs/200-fullstacks/228-migration-arch-refactor/spec.md) - [ADR-019: Hybrid Identifier Strategy](./ADR-019-hybrid-identifier-strategy.md) - [ADR-023A: Unified AI Architecture (Model Revision)](./ADR-023A-unified-ai-architecture.md) --- ## ðŸŽŊ Gap Analysis & Purpose ### āļ›āļīāļ” Gap āļˆāļēāļāđ€āļ­āļāļŠāļēāļĢ: - **03-04 legacy-data-migration.md** - āļĢāļ°āļšāļšāļāļēāļĢāđ‚āļ­āļ™āļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļāļĢāļ°āļšāļšāđ€āļ”āļīāļĄ: - āđ€āļŦāļ•āļļāļœāļĨ: āļāļēāļĢāđ‚āļ­āļ™āļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆāļĄāļĩāļ„āļ§āļēāļĄāđ€āļŠāļĩāđˆāļĒāļ‡āļ—āļĩāđˆāļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļœāļīāļ”āļžāļĨāļēāļ” āļŦāļĢāļ·āļ­āļ‚āđ‰āļ­āļĄāļđāļĨāļ‹āđ‰āļģāļ‹āđ‰āļ­āļ™āđƒāļ™āļĢāļ°āļšāļšāļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļĢāļīāļ‡ (Production) āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ‚āļąāđ‰āļ™āļ•āļ­āļ™ Human-in-the-Loop āļœāđˆāļēāļ™ Staging Review Queue āđāļĨāļ°āļāļēāļĢāļ™āļģ UuidResolverService āļĄāļēāđāļāđ‰āļ›āļąāļāļŦāļēāļ„āļ§āļēāļĄāļ‚āļąāļ”āđāļĒāđ‰āļ‡āļ‚āļ­āļ‡ ID āļˆāļ°āļŠāđˆāļ§āļĒāļ„āļ§āļšāļ„āļļāļĄāļ„āļ§āļēāļĄāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļāđˆāļ­āļ™āļ™āļģāđ€āļ‚āđ‰āļēāļĢāļ°āļšāļšāļˆāļąāļ”āđ€āļāđ‡āļšāļ–āļēāļ§āļĢ ### āđāļāđ‰āđ„āļ‚āļ„āļ§āļēāļĄāļ‚āļąāļ”āđāļĒāđ‰āļ‡: - **ADR-019** vs **Frontend DTO**: DTO āļšāļ™ Frontend āļ—āļąāđˆāļ§āđ„āļ›āđƒāļŠāđ‰ UUID (`publicId`) āđāļ•āđˆāļāļēāļĢāļ™āļģāđ€āļ‚āđ‰āļēāļ‚āđ‰āļ­āļĄāļđāļĨāđƒāļ™āļĢāļ°āļšāļšāļŦāļĨāļąāļ‡āļšāđ‰āļēāļ™ (Backend) āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰ Internal AUTO_INCREMENT Primary Key āđƒāļ™āļāļēāļĢāļ—āļģ Foreign Key Constraints - āļāļēāļĢāļ•āļąāļ”āļŠāļīāļ™āđƒāļˆāļ™āļĩāđ‰āļŠāđˆāļ§āļĒāđāļāđ‰āđ„āļ‚āđ‚āļ”āļĒ: āļ­āļ­āļāđāļšāļšāđƒāļŦāđ‰ DTO āļ‚āļ­āļ‡āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ (`CommitMigrationReviewDto`) āļĢāļ­āļ‡āļĢāļąāļšāļ—āļąāđ‰āļ‡ `number | string` (Hybrid Type) āđāļĨāļ°āđƒāļŠāđ‰ `UuidResolverService` āļāļąāđˆāļ‡ Backend āđ€āļžāļ·āđˆāļ­āļ–āļ­āļ”āļĢāļŦāļąāļŠ UUID āđ€āļ›āđ‡āļ™ INT PK āđ‚āļ”āļĒāđ„āļĄāđˆāđ€āļ›āļīāļ”āđ€āļœāļĒāļ„āđˆāļē PK āļ āļēāļĒāđƒāļ™āļ­āļ­āļāļŠāļđāđˆāļ āļēāļĒāļ™āļ­āļ --- ## Context and Problem Statement āđƒāļ™āļāļēāļĢāđ‚āļ­āļ™āļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļāļĢāļ°āļšāļšāđ€āļ”āļīāļĄāļœāđˆāļēāļ™āļĢāļ°āļšāļšāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī (n8n + PaddleOCR + Gemma4) āļžāļšāļ„āļ§āļēāļĄāļ—āđ‰āļēāļ—āļēāļĒāļŦāļĨāļąāļ 3 āļ›āļĢāļ°āļāļēāļĢ: 1. āļ‚āđ‰āļ­āļĄāļđāļĨāļšāļēāļ‡āļŠāđˆāļ§āļ™āļ­āļēāļˆāļĄāļĩāļ„āđˆāļēāļ„āļ§āļēāļĄāđ€āļŠāļ·āđˆāļ­āļĄāļąāđˆāļ™āļ•āđˆāļģ (Low Confidence) āļŦāļĢāļ·āļ­āļĄāļĩāļ‚āđ‰āļ­āļĄāļđāļĨāđ‚āļ„āļĢāļ‡āļāļēāļĢāđāļĨāļ°āļ„āļđāđˆāļŠāļąāļāļāļēāđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡ āļ‹āļķāđˆāļ‡āļĢāļ°āļšāļšāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āļ™āļ•āļĢāļ§āļˆāļŠāļ­āļšāđāļāđ‰āđ„āļ‚āļāđˆāļ­āļ™āļšāļąāļ™āļ—āļķāļāļˆāļĢāļīāļ‡ (Human-in-the-Loop) 2. āļŠāļīāļ—āļ˜āļīāđŒāđƒāļ™āļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āđāļĨāļ°āļ™āļģāđ€āļ‚āđ‰āļēāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļĢāļīāļ‡āļ•āđ‰āļ­āļ‡āļˆāļģāļāļąāļ”āđƒāļŦāđ‰āđ€āļ‰āļžāļēāļ°āļœāļđāđ‰āļĄāļĩāļšāļ—āļšāļēāļ— `DOCUMENT_CONTROLLER` āļŦāļĢāļ·āļ­ `ADMIN` āđāļĨāļ°āļ•āđ‰āļ­āļ‡āđ„āļ”āđ‰āļĢāļąāļšāļāļēāļĢāļ›āđ‰āļ­āļ‡āļāļąāļ™āļāļēāļĢāļāļ”āļšāļąāļ™āļ—āļķāļāļ‹āđ‰āļģ (Double Commit / Race Condition) 3. āļ•āļēāļĢāļēāļ‡āļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāļāļēāļĢāļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨ (Staging Tables) āļĄāļĩāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆāđāļĨāļ°āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļĨāļšāļ­āļ­āļāļŦāļĨāļąāļ‡āđ€āļŠāļĢāđ‡āļˆāļŠāļīāđ‰āļ™āļāļĢāļ°āļšāļ§āļ™āļāļēāļĢāđ‚āļ­āļ™āļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļžāļ·āđˆāļ­āļ›āļĢāļ°āļŦāļĒāļąāļ”āļžāļ·āđ‰āļ™āļ—āļĩāđˆ āđ‚āļ”āļĒāļĒāļąāļ‡āļ„āļ‡āļ•āđ‰āļ­āļ‡āļĢāļąāļāļĐāļēāļ‚āđ‰āļ­āļĄāļđāļĨāļ›āļĢāļ°āļ§āļąāļ•āļīāđ€āļžāļ·āđˆāļ­āļ—āļģ Idempotency Guard āđ€āļŠāļĄāļ­ --- ## Decision Drivers - **Data Integrity & Security:** āļ•āđ‰āļ­āļ‡āđ€āļ›āđ‡āļ™āđ„āļ›āļ•āļēāļĄāļĄāļēāļ•āļĢāļāļēāļ™āļāļēāļĢāļāļĢāļ­āļ‡āļŠāļīāļ—āļ˜āļīāđŒ CASL Guard āđāļĨāļ°āļāļēāļĢāđāļĒāļ UUID (ADR-019) - **Zero Race Condition:** āļ›āđ‰āļ­āļ‡āļāļąāļ™āļāļēāļĢāļāļ”āļšāļąāļ™āļ—āļķāļāļ‹āđ‰āļģāļˆāļēāļāļāļēāļĢāđ€āļ›āļīāļ”āđāļ–āļ§āđāļāđ‰āđ„āļ‚āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āļ”āđ‰āļ§āļĒāļĢāļ°āļšāļš Optimistic Locking (`version`) āđāļĨāļ° `SELECT FOR UPDATE` āļŦāļĢāļ·āļ­ Pessimistic Writing - **Resource Cleanup:** āļĨāļ”āļ āļēāļĢāļ°āļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāđāļĨāļ°āļžāļ·āđ‰āļ™āļ—āļĩāđˆāđ€āļāđ‡āļšāļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĨāļąāļ‡āļ‡āļēāļ™ Migration āđ€āļŠāļĢāđ‡āļˆāļŠāļĄāļšāļđāļĢāļ“āđŒ --- ## Considered Options ### Option 1: Inline Direct Migration (āļ™āļģāđ€āļ‚āđ‰āļēāļ—āļąāļ™āļ—āļĩāđ„āļĄāđˆāļĄāļĩ Staging Queue) āļ™āļģāđ€āļ‚āđ‰āļēāđ€āļ­āļāļŠāļēāļĢāļ—āļļāļāļ•āļąāļ§āđ€āļ‚āđ‰āļēāļŠāļđāđˆāļĢāļ°āļšāļš Production āļ—āļąāļ™āļ—āļĩ āđ‚āļ”āļĒāđƒāļŦāđ‰ AI āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ 100% - **Pros:** āļĢāļ§āļ”āđ€āļĢāđ‡āļ§ āđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ‚āļĩāļĒāļ™āļŦāļ™āđ‰āļēāļˆāļ­ Frontend Review - **Cons:** ❌ āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļĒāļ°āļˆāļģāļ™āļ§āļ™āļĄāļēāļāļˆāļ°āļŦāļĨāļļāļ”āđ€āļ‚āđ‰āļēāļŠāļđāđˆ Production, āđ„āļĄāđˆāļŠāļēāļĄāļēāļĢāļ–āđāļāđ‰āđ„āļ‚āļ„āđˆāļē Tags āļŦāļĢāļ·āļ­āļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒāļ‚āđ‰āļ­āļĄāļđāļĨāđ‚āļ„āļĢāļ‡āļāļēāļĢāļ—āļĩāđˆ AI āļ”āļķāļ‡āļœāļīāļ”āđ„āļ”āđ‰ ### Option 2: Human-in-the-Loop Review Queue with Post-Migration Cleanups (āđ€āļĨāļ·āļ­āļāđāļ™āļ§āļ—āļēāļ‡āļ™āļĩāđ‰) āļ­āļ­āļāđāļšāļšāļ•āļēāļĢāļēāļ‡ Staging 5 āļ•āļēāļĢāļēāļ‡āđāļĨāļ° Review UI āļŠāļģāļŦāļĢāļąāļšāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ‚āđ‰āļ­āļĄāļđāļĨ āđ‚āļ”āļĒāļāļģāļŦāļ™āļ”āđƒāļŦāđ‰āļœāļđāđ‰āļ•āļĢāļ§āļˆāđāļāđ‰ Metadata āđ„āļ”āđ‰ āđāļĨāļ°āļĄāļĩāļ„āļģāļŠāļąāđˆāļ‡āļ—āļģāļ„āļ§āļēāļĄāļŠāļ°āļ­āļēāļ”āļŦāļĨāļąāļ‡āļˆāļšāđ‚āļ„āļĢāļ‡āļāļēāļĢ - **Pros:** ✅ āļ‚āđ‰āļ­āļĄāļđāļĨāļ–āļđāļāļ•āđ‰āļ­āļ‡ 100%, āđāļāđ‰āđ„āļ‚ tag āļ āļēāļĐāļēāđ„āļ—āļĒāđāļĨāļ° project ID āđ„āļ”āđ‰āļĢāļ§āļ”āđ€āļĢāđ‡āļ§, āļĢāļąāļāļĐāļēāļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāļ•āļēāļĄ ADR-019 āđāļĨāļ°āļ›āđ‰āļ­āļ‡āļāļąāļ™āļāļēāļĢāļšāļąāļ™āļ—āļķāļāļ‹āđ‰āļģāļ”āđ‰āļ§āļĒ `import_transactions` - **Cons:** ❌ āļ•āđ‰āļ­āļ‡āļŠāļĢāđ‰āļēāļ‡ Component āđāļĨāļ° SQL Delta āđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄ --- ## Decision Outcome **Chosen Option:** Option 2 ### Rationale āļāļēāļĢāđ€āļžāļīāđˆāļĄāļŠāļąāđ‰āļ™ Staging Queue āļĢāđˆāļ§āļĄāļāļąāļš UuidResolverService āļ›āđ‰āļ­āļ‡āļāļąāļ™āļ›āļąāļāļŦāļēāđ€āļĢāļ·āđˆāļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āļĒāļ°āļŦāļĨāļļāļ”āđ€āļ‚āđ‰āļēāļĢāļ°āļšāļšāđāļĨāļ°āļāļēāļĢāļĢāļąāđˆāļ§āđ„āļŦāļĨāļ‚āļ­āļ‡āļ„āđˆāļē INT PK āļ­āļ­āļāļŠāļđāđˆāļ āļēāļĒāļ™āļ­āļāđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļŠāļĄāļšāļđāļĢāļ“āđŒ --- ## 🔍 Impact Analysis ### Affected Components (āļŠāđˆāļ§āļ™āļ›āļĢāļ°āļāļ­āļšāļ—āļĩāđˆāđ„āļ”āđ‰āļĢāļąāļšāļœāļĨāļāļĢāļ°āļ—āļš) | Component | Level | Impact Description | Required Action | |-----------|-------|-------------------|-----------------| | **Backend** | ðŸ”ī High | āđ€āļžāļīāđˆāļĄ Service āđāļĨāļ° Controller āđƒāļ™āļāļēāļĢāļ–āļ­āļ”āļĢāļŦāļąāļŠ UUID āđ€āļ›āđ‡āļ™ ID āđƒāļ™āļĢāļ°āļšāļš āđāļĨāļ°āļšāļąāļ™āļ—āļķāļ Correspondence | āļ•āļīāļ”āļ•āļąāđ‰āļ‡ `UuidResolverService` āđāļĨāļ°āļ„āļ§āļšāļ„āļļāļĄ Transactional Commit | | **Frontend** | ðŸŸĄ Medium | āļžāļąāļ’āļ™āļēāļŦāļ™āđ‰āļēāļˆāļ­ `/migration/review` āđāļĨāļ° Custom Query Hooks | āļ­āļ­āļāđāļšāļš Sheet Panel āđāļĨāļ° components āļ•āļēāļĄ standard UI | | **Database** | ðŸ”ī High | āļŠāļĢāđ‰āļēāļ‡ SQL Delta āļĨāļšāļ•āļēāļĢāļēāļ‡āđāļĨāļ°āđ€āļ•āļĢāļĩāļĒāļĄāđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļ•āļēāļĢāļēāļ‡ Tags | āļˆāļąāļ”āļ—āļģ Delta āđāļĨāļ° Rollback SQL Script | ### Required Changes (āļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ) #### ðŸ”ī Critical Changes (āļ•āđ‰āļ­āļ‡āļ—āļģāļ—āļąāļ™āļ—āļĩ) - [x] **Commit DTO Refactoring** - `backend/src/modules/migration/dto/commit-migration-review.dto.ts`: āļĢāļ­āļ‡āļĢāļąāļš Hybrid Types (`number | string`) - [x] **Review Service Implementation** - `backend/src/modules/migration/migration-review.service.ts`: āđƒāļŠāđ‰ UuidResolverService āđāļĨāļ°āļˆāļąāļ”āļāļēāļĢ Recipients `TO` āđƒāļ™ transaction - [x] **Review Queue UI Page** - `frontend/app/(dashboard)/migration/review/page.tsx`: āļžāļąāļ’āļ™āļēāļŠāđˆāļ§āļ™āļ„āļ§āļšāļ„āļļāļĄāļŦāļ™āđ‰āļēāļŦāļĨāļąāļ, āđāļ—āđ‡āļšāļāļĢāļ­āļ‡āļŠāļ–āļēāļ™āļ° āđāļĨāļ°āļ›āļļāđˆāļĄāļ”āļēāļ§āļ™āđŒāđ‚āļŦāļĨāļ”āđƒāļŦāļĄāđˆ #### ðŸŸĄ Important Changes (āļ„āļ§āļĢāļ—āļģāļ āļēāļĒāđƒāļ™ 3 āļ§āļąāļ™) - [x] **Drop Staging SQL Delta** - `specs/03-Data-and-Storage/deltas/2026-05-22-drop-migration-tables.sql`: āļŠāļĢāđ‰āļēāļ‡āļ„āļģāļŠāļąāđˆāļ‡ Drop āļ•āļēāļĢāļēāļ‡ staging - [x] **Drop Staging SQL Rollback** - `specs/03-Data-and-Storage/deltas/2026-05-22-drop-migration-tables.rollback.sql`: āļŠāļ„āļĢāļīāļ›āļ•āđŒāļāļđāđ‰āļ„āļ·āļ™āļ•āļēāļĢāļēāļ‡āļĒāđ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨ --- ## 📋 Version Dependency Matrix | ADR | Version | Dependency Type | Affected Version(s) | Implementation Status | |-----|---------|-----------------|---------------------|----------------------| | **ADR-019** | 1.0 | Required | v1.9.0+ | ✅ Implemented | | **ADR-023A** | 2.0 | Required | v1.9.0+ | ✅ Implemented | | **ADR-028** | 1.0 | Core | v1.9.5+ | ✅ Implemented | ### Version Compatibility Rules - **Minimum Version:** v1.9.5 (ADR-028 āļĄāļĩāļœāļĨāļŠāļĄāļšāļđāļĢāļ“āđŒ) - **Deprecation Timeline:** āļ•āļēāļĢāļēāļ‡ staging āļ—āļąāđ‰āļ‡ 5 āļ•āļēāļĢāļēāļ‡āļˆāļ°āļ–āļđāļāļ”āļĢāļ­āļ›āļ­āļ­āļāļ āļēāļĒāđƒāļ™ 30 āļ§āļąāļ™āļŦāļĨāļąāļ‡āļŠāļīāđ‰āļ™āļŠāļļāļ”āļŠāđˆāļ§āļ‡āļĢāļ°āļĒāļ°āļāļēāļĢāļ™āļģāđ€āļ‚āđ‰āļēāļ‚āđ‰āļ­āļĄāļđāļĨ (Gate #3) āđ‚āļ”āļĒāļ•āļēāļĢāļēāļ‡ `import_transactions` āļˆāļ°āļ„āļ‡āļ­āļĒāļđāđˆāļ•āļĨāļ­āļ”āđ„āļ› --- ## References - specs/03-Data-and-Storage/lcbp3-v1.9.0-migration.sql - specs/03-Data-and-Storage/03-04-legacy-data-migration.md