drop-monorepo-refactor-plan
Plan: Drop Monorepo Refactor (src/ → apps/+packages/)
MC: #10051
Owner: John (orchestrator) + CodeCraft + Proveo + Skillforge
Estimated total: ~15h CodeCraft + 2h validation + 1h docs = ~18h fleet time
Strategy: 4-PR staged migration (NOT atomic) per Petter's research
Research: /tmp/drop-monorepo-research-10051.md (347 lines, Petter Graff)
Research Summary
Drop monorepo currently uses npm workspaces under src/ (3 registered: src/shared, src/drop-api, src/drop-app; src/drop-mobile is on separate release cycle, NOT in workspace config but referenced in 3 mobile workflows). Migrating to apps/+packages/ requires touching 80+ hardcoded paths across 8 GitHub Actions workflows, 2 root Dockerfiles, buildspec.yml (just merged in PR #3), 2 docker-compose files, and root package.json lint-staged.
Top 3 production risks
Dockerfile.drop-app:59,67—WORKDIR /app/src/drop-appbaked into Next.js standalone runner stage. Silent build success / runtime fail on App Runner cold start.ci.yml:49-53paths-filter must update atomically with rename. Wrong order = silent CI skip = unreviewed code reaches main.Dockerfile.apiuses raw source-copy to/shared/(not workspace symlinks) — structurally inconsistent withDockerfile.drop-app. Audit separately.
Why multi-PR (NOT atomic)
- Each PR is reviewable, revertable, testable independently
- CI workflow update (PR 3) is highest-risk single change → its own PR
- Pre-Finanstilsynet: every CI/security-gate change deserves explicit review
- 4 conflict-able PRs > 1 monster PR with 80+ touched paths
Objective
Restructure Drop monorepo to industry-standard Turborepo/pnpm convention (apps/ for deployables, packages/ for shared libs) WITHOUT introducing behavior changes, downtime, or production deploys breaking. Land in 4 staged PRs over 2-3 days, with staging validation before prod merge.
Team Orchestration
Team Members
| ID | Name | Role | Agent Type |
|---|---|---|---|
| B1 | codecraft-pkg | PR 1: workspace config + packages/ rename | codecraft |
| B2 | codecraft-apps | PR 2: apps/ rename + Dockerfiles + buildspec | codecraft |
| B3 | codecraft-ci | PR 3: 8 GitHub workflow files update | codecraft |
| B4 | codecraft-cleanup | PR 4: delete old src/ + final validation | codecraft |
| V1 | proveo-staging | Staging validation pre-PR-4 merge | proveo |
| V2 | proveo-prod | Production validation post-PR-4 merge | proveo |
| V3 | securion-fintech | Pre-Finanstilsynet security audit | securion |
| D1 | skillforge-docs | BookStack page + memory entries | skillforge |
| R1 | gemini-reviewer | Review every PR before merge | gemini-reviewer |
Step-by-Step Tasks
Phase 1 — Internal packages rename (low risk, isolated)
Task 1: PR 1 — Rename src/shared → packages/shared
- Owner: B1 (codecraft)
- BlockedBy: none (research deliverable already done)
- Branch:
feat/monorepo-pr1-packages-shared - Scope:
git mv src/shared packages/shared(preserves history)- Root
package.jsonworkspaces array:"src/shared"→"packages/shared" npm installregenerate lockfile (in Linux container per ZAKON LOCKFILE PORTABILITY)- Verify
apps/drop-app/node_modules/@drop/sharedsymlink resolves (post-PR-2; for PR 1 verify rootnode_modules/@drop/sharedresolves) - Update lint-staged glob if
src/shared/referenced
- Acceptance:
-
npm install --ignore-scripts --no-auditexit 0 -
cd src/drop-app && npx tsc --noEmitexit 0 (shared resolves via root workspace) -
cd src/drop-api && npx tsc --noEmitexit 0 - CI Quality Gate REQUIRED green on PR
- No file outside
packages/shared/andpackage.json+package-lock.jsonmodified
-
Task 2: Gemini review PR 1
- Owner: R1
- BlockedBy: 1
- Acceptance: VERDICT: APPROVE
Task 3: Squash merge PR 1 to main
- Owner: John
- BlockedBy: 2
- Post-merge: verify main CI green
Phase 2 — Apps rename + Docker (highest production risk)
Task 4: PR 2 — Rename src/drop-* → apps/drop-* + Dockerfile + buildspec updates
- Owner: B2 (codecraft)
- BlockedBy: 3 (PR 1 merged)
- Branch:
feat/monorepo-pr2-apps-docker - Scope:
git mv src/drop-app apps/drop-app,src/drop-api apps/drop-api,src/drop-mobile apps/drop-mobile- Update root
package.jsonworkspaces:"src/drop-api"→"apps/drop-api","src/drop-app"→"apps/drop-app" - Update lint-staged globs (3 patterns) +
cd src/drop-*commands - Update
Dockerfile.drop-app: ALLsrc/drop-app→apps/drop-app,src/shared→packages/shared. CRITICAL: bothWORKDIR /app/src/drop-applines (59 + 67) →/app/apps/drop-app - Update
Dockerfile.api:src/drop-api→apps/drop-api,src/shared→packages/sharedAND/monorepo/src/shared/→/monorepo/packages/shared/(the absolute-path hack) - Update
buildspec.yml: 7 occurrences ofsrc/drop-app→apps/drop-app,src/shared→packages/shared - Update
docker-compose.yml+docker-compose.dev.ymlbuild contexts + bind mounts - Verify
next.config.tsoutputFileTracingRoot: ../../still resolves to repo root fromapps/drop-app/(it does — same depth) - Local Docker build MANDATORY (ZAKON LOCAL DOCKER BUILD):
docker buildx build --platform linux/amd64 -f Dockerfile.drop-app .exit 0
- Acceptance:
-
npm install --ignore-scripts --no-auditexit 0 -
cd apps/drop-app && npx eslint .0 errors -
cd apps/drop-app && npx tsc --noEmitexit 0 -
docker buildx build --platform linux/amd64 -f Dockerfile.drop-app .exit 0 (LOCAL evidence required) -
docker buildx build --platform linux/amd64 -f Dockerfile.api .exit 0 - CI Quality Gate REQUIRED green on PR
- No CI workflow file modified in this PR (saved for PR 3)
- No
src/directory deleted yet (saved for PR 4)
-
Task 5: Gemini review PR 2
- Owner: R1
- BlockedBy: 4
- Acceptance: VERDICT: APPROVE
- Special review focus: Dockerfile WORKDIR lines, Dockerfile.api absolute path, lockfile linux-x64 variants
Task 6: Squash merge PR 2 to main — CAUTION
- Owner: John
- BlockedBy: 5
- Note: This DOES trigger
deploy.ymlauto-deploy. Production App Runner will build with new paths. Monitoraws apprunner describe-serviceuntil RUNNING status. If deploy fails, immediate rollback via CF CNAME flip + previous SHA redeploy per DEPLOY-MAP.md. - Pre-merge mandatory: external
curl -sI https://app.getdrop.noshows current production health - Post-merge mandatory: external
curl -sI https://app.getdrop.noshows healthy within 10min of CF CNAME flip
Phase 3 — CI workflows update (silent skip risk)
Task 7: PR 3 — Update 8 GitHub Actions workflows
- Owner: B3 (codecraft)
- BlockedBy: 6 (PR 2 merged + production verified RUNNING)
- Branch:
feat/monorepo-pr3-ci-workflows - Scope:
ci.yml: paths-filter (5 lines), working-directory, cache-dependency-path, cd commands, artifact pathsdeploy.yml: docker build context pathdeploy-staging.yml: paths, working-directory, cache-dependency-path, playwright report pathhotfix.yml: working-directory x2, cache-dependency-pathdeploy-aws.yml: working-directory, docker build contextmobile-ci.yml: paths-filter, working-directory x3, cache-dependency-path, artifact pathmobile-deploy.yml: paths-filter, working-directory, git add pathmobile-release.yml: working-directory, cache-dependency-path, VERSION_FILE path, git add path
- Acceptance:
- All 8 workflow files modified, no other code changes
- CI Quality Gate REQUIRED green on PR
-
gh workflow view "CI — Quality Gate"runs against new paths -
mobile-ci.ymltriggers onapps/drop-mobile/**paths-filter when mobile code changed (test by including 1-line mobile change in PR)
Task 8: Gemini review PR 3
- Owner: R1
- BlockedBy: 7
- Acceptance: VERDICT: APPROVE
- Special review focus: paths-filter glob accuracy (silent CI skip is the danger)
Task 9: Squash merge PR 3
- Owner: John
- BlockedBy: 8
- Note: deploy-staging.yml manual workflow_dispatch test BEFORE merge, against PR HEAD SHA, to confirm staging path resolution
Phase 4 — Cleanup + production validation
Task 10: PR 4 — Delete legacy src/ directory + ALAI memory updates
- Owner: B4 (codecraft)
- BlockedBy: 9 (PR 3 merged + main CI green)
- Branch:
feat/monorepo-pr4-cleanup - Scope:
git rm -r src/(now empty after PR 1 + PR 2 moves)- Update
BUILD-BLUEPRINT.mdrepo structure section + build commands - Update
DEPLOY-MAP.mdpaths - Update
RUNBOOK.mdif any path references - Update
project/architecture/*.mdreferences - Update
~/.claude/projects/-Users-makinja/memory/MEMORY-products.mdDrop entry - Update any
~/.claude/projects/-Users-makinja/memory/project_drop_*.mdreferring to old paths
- Acceptance:
-
find . -path "./src" -type dempty -
grep -r "src/drop-" --include="*.md" --include="*.yml" --include="*.json"0 hits in repo (excluding old git history) - CI Quality Gate REQUIRED green on PR
-
Task 11: Proveo validation — STAGING (pre-merge)
- Owner: V1 (proveo)
- BlockedBy: 10 (PR 4 ready, but NOT merged yet)
- Action: trigger
deploy-staging.ymlworkflow_dispatch against PR 4 head SHA - Acceptance:
- Staging App Runner reaches RUNNING state within 15min
-
curl -s https://staging.getdrop.no/api/health | jq .status== "ok" - Playwright smoke test (login + dashboard + send-money flow) passes
- No new Sentry errors in staging post-deploy
- Evidence written to
/tmp/proveo-monorepo-staging-10051.json
Task 12: Gemini review PR 4
- Owner: R1
- BlockedBy: 11
- Acceptance: VERDICT: APPROVE
Task 13: Securion fintech security audit (pre-prod merge)
- Owner: V3 (securion / Parisa Tabriz)
- BlockedBy: 11
- Scope: monorepo path rename security implications — secrets accidentally exposed via different paths, .gitignore coverage, JWT/auth boundary integrity, OWASP Top 10 quick check
- Acceptance:
- No secret leaks introduced by path changes
- Auth middleware paths still correct
- No new attack surface introduced
- Report at
/tmp/securion-monorepo-10051.md
Task 14: Squash merge PR 4 to main
- Owner: John
- BlockedBy: 12, 13
- Triggers:
deploy.ymlauto-deploy to production - Pre-merge mandatory: external curl baseline, gh run list main shows green
- Post-merge mandatory: monitor App Runner deploy
Task 15: Proveo validation — PRODUCTION
- Owner: V2 (proveo)
- BlockedBy: 14
- Action: post-deploy verification per DEPLOY-MAP.md ZAKON PI2 protocol
- Acceptance:
-
curl -s https://app.getdrop.no/api/health | jq .status== "ok" - Playwright screenshot of dashboard (live data load)
- No CI deploy.yml errors
- No Sentry error spike in 30min post-deploy
- App Runner blue/green flip verified
- Evidence at
/tmp/proveo-monorepo-prod-10051.json+ screenshot
-
Task 16: Skillforge documentation
- Owner: D1 (skillforge)
- BlockedBy: 15
- Scope:
- BookStack page "Drop Monorepo Architecture" — apps/+packages/ structure, deploy paths, conventions
- Memory entry
project_drop_monorepo_refactor_2026-XX-XX.mdwith lessons learned + path migration patterns - Update
~/system/rules/zakon-local-docker-build.mdif monorepo-specific gotchas surfaced
- Acceptance:
- BookStack page exists and synced
- Memory entry created
- MEMORY.md index updated
Risk Register
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Dockerfile WORKDIR baked path miss (E1) | MED | HIGH (prod cold start fail) | Mandatory local Docker build in PR 2 |
| paths-filter wrong = silent CI skip (E4) | LOW | CRITICAL (unreviewed code in main) | PR 3 has explicit paths-filter glob review by R1 |
| Lockfile platform variants missing (E6) | MED | MED (CodeBuild fail) | Regenerate in Linux container per ZAKON LOCKFILE PORTABILITY |
| @drop/shared symlink resolution fails (E5) | MED | HIGH (build fail) | PR 1 isolated test before PR 2 starts |
| Sentry source maps un-symbolicate (E8) | LOW | LOW (debug noise only) | Verify post-deploy Sentry dashboard |
| Dockerfile.api absolute path break (E3) | MED | HIGH (drop-api fail) | Local docker build evidence MANDATORY in PR 2 |
| AWS App Runner deploy fails post-merge | LOW | CRITICAL (prod outage) | CF CNAME rollback < 10s + previous SHA redeploy |
| backend/ legacy dir confusion (E9) | LOW | LOW | Document as legacy, do not rename in this MC |
| Mobile workflow paths-filter coupling (E7) | LOW | MED | Tested in PR 3 with 1-line mobile change |
Rollback Plan (per PR)
| PR | Rollback action |
|---|---|
| PR 1 | git revert <merge-commit> — pure rename, no behavior change. < 5min recovery. |
| PR 2 | git revert <merge-commit> + ECR previous-SHA redeploy via apprunner start-deployment + CF CNAME flip. < 15min recovery. |
| PR 3 | git revert <merge-commit> — workflows revert. CI may briefly run against wrong paths during revert window (acceptable). < 5min. |
| PR 4 | git revert <merge-commit> — restores src/ from history. Same as PR 2 if production-affecting deploy triggers. |
Validation Checkpoints (cumulative across phases)
After EACH PR merge to main:
gh run list --branch main --limit 1last run = SUCCESS for "CI — Quality Gate"curl -sI https://app.getdrop.noreturns HTTP 200aws apprunner describe-service --service-arn <drop-web-arn>Status: RUNNING- No new Sentry errors in 15min after deploy
git log --oneline mainshows clean linear history (squash merges)
After PR 4 (final cleanup):
6. find /Users/makinja/ALAI/products/Drop -type d -name "src" returns 0 results
7. Repo size reduced (lockfile + node_modules can re-regenerate in fresh clone)
8. Skillforge BookStack page accessible at https://docs.alai.no
Estimate of Total Time
| Phase | CodeCraft hours | Calendar days |
|---|---|---|
| PR 1 (packages/) | 1.5h | Day 1 |
| PR 2 (apps/ + Docker) | 5h | Day 1-2 |
| PR 3 (CI workflows) | 2.5h | Day 2 |
| PR 4 (cleanup) | 2h | Day 2-3 |
| Proveo + Securion validation | 2h | Day 2-3 |
| Skillforge docs | 1h | Day 3 |
| Total | ~14h | 3 days |
Add 30% buffer for failure recovery iterations = ~18h fleet, 3 calendar days.
Required Follow-ups
backend/legacy directory at repo root — confirm dead code in separate MC, then either rename or delete. NOT in scope of this MC.mobile-release.ymlcross-referencessrc/drop-app/src/config/app-versions.jsonfrom within mobile workflow — clarify ownership boundary in followup.- Migration to true Turborepo (turbo.json) or pnpm — separate MC. This refactor only renames paths, does NOT change tooling.
- Sentry post-deploy verification — if source maps un-symbolicate, separate MC for Sentry config update.
Per ZAKON PLAN compliance
- Validation task — Tasks 11 (Proveo staging) + 15 (Proveo prod) — end-to-end Playwright + curl + Sentry monitoring (NOT dry-run)
- Documentation task — Task 16 (Skillforge) — BookStack page + memory entry
Approval
Plan ready for CEO review. To execute:
/build-plan ~/system/specs/drop-monorepo-refactor-plan.md
Or dispatch first phase manually:
/mehanik "Drop monorepo PR 1: packages/shared rename + workspace config" /Users/makinja/ALAI/products/Drop <new_MC_id>
No comments to display
No comments to display