Skip to main content

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

  1. Dockerfile.drop-app:59,67WORKDIR /app/src/drop-app baked into Next.js standalone runner stage. Silent build success / runtime fail on App Runner cold start.
  2. ci.yml:49-53 paths-filter must update atomically with rename. Wrong order = silent CI skip = unreviewed code reaches main.
  3. Dockerfile.api uses raw source-copy to /shared/ (not workspace symlinks) — structurally inconsistent with Dockerfile.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/sharedpackages/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.json workspaces array: "src/shared""packages/shared"
    • npm install regenerate lockfile (in Linux container per ZAKON LOCKFILE PORTABILITY)
    • Verify apps/drop-app/node_modules/@drop/shared symlink resolves (post-PR-2; for PR 1 verify root node_modules/@drop/shared resolves)
    • Update lint-staged glob if src/shared/ referenced
  • Acceptance:
    • npm install --ignore-scripts --no-audit exit 0
    • cd src/drop-app && npx tsc --noEmit exit 0 (shared resolves via root workspace)
    • cd src/drop-api && npx tsc --noEmit exit 0
    • CI Quality Gate REQUIRED green on PR
    • No file outside packages/shared/ and package.json + package-lock.json modified

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.json workspaces: "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: ALL src/drop-appapps/drop-app, src/sharedpackages/shared. CRITICAL: both WORKDIR /app/src/drop-app lines (59 + 67) → /app/apps/drop-app
    • Update Dockerfile.api: src/drop-apiapps/drop-api, src/sharedpackages/shared AND /monorepo/src/shared//monorepo/packages/shared/ (the absolute-path hack)
    • Update buildspec.yml: 7 occurrences of src/drop-appapps/drop-app, src/sharedpackages/shared
    • Update docker-compose.yml + docker-compose.dev.yml build contexts + bind mounts
    • Verify next.config.ts outputFileTracingRoot: ../../ still resolves to repo root from apps/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-audit exit 0
    • cd apps/drop-app && npx eslint . 0 errors
    • cd apps/drop-app && npx tsc --noEmit exit 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.yml auto-deploy. Production App Runner will build with new paths. Monitor aws apprunner describe-service until 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.no shows current production health
  • Post-merge mandatory: external curl -sI https://app.getdrop.no shows 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 paths
    • deploy.yml: docker build context path
    • deploy-staging.yml: paths, working-directory, cache-dependency-path, playwright report path
    • hotfix.yml: working-directory x2, cache-dependency-path
    • deploy-aws.yml: working-directory, docker build context
    • mobile-ci.yml: paths-filter, working-directory x3, cache-dependency-path, artifact path
    • mobile-deploy.yml: paths-filter, working-directory, git add path
    • mobile-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.yml triggers on apps/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.md repo structure section + build commands
    • Update DEPLOY-MAP.md paths
    • Update RUNBOOK.md if any path references
    • Update project/architecture/*.md references
    • Update ~/.claude/projects/-Users-makinja/memory/MEMORY-products.md Drop entry
    • Update any ~/.claude/projects/-Users-makinja/memory/project_drop_*.md referring to old paths
  • Acceptance:
    • find . -path "./src" -type d empty
    • 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.yml workflow_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.yml auto-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.md with lessons learned + path migration patterns
    • Update ~/system/rules/zakon-local-docker-build.md if 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:

  1. gh run list --branch main --limit 1 last run = SUCCESS for "CI — Quality Gate"
  2. curl -sI https://app.getdrop.no returns HTTP 200
  3. aws apprunner describe-service --service-arn <drop-web-arn> Status: RUNNING
  4. No new Sentry errors in 15min after deploy
  5. git log --oneline main shows 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

  1. backend/ legacy directory at repo root — confirm dead code in separate MC, then either rename or delete. NOT in scope of this MC.
  2. mobile-release.yml cross-references src/drop-app/src/config/app-versions.json from within mobile workflow — clarify ownership boundary in followup.
  3. Migration to true Turborepo (turbo.json) or pnpm — separate MC. This refactor only renames paths, does NOT change tooling.
  4. 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>