🧱 Technology Stack & Codebase Complexity

πŸ“‹ Summary

Midshift is built on a modern, mainstream and deliberately narrow stack: a Next.js 16 / React 19 web application written entirely in TypeScript, hosted on Vercel, with Supabase (managed Postgres, file storage and authentication) as its only data platform and Resend as its only e-mail provider. That narrowness is a strength: a new team needs familiarity with one framework and one backend platform, and hiring for these skills is straightforward. The codebase is medium-sized (about 44,000 lines of application TypeScript, roughly 92,000 lines across everything including tests and tooling) and most functions are simple; complexity is concentrated in a small number of large request handlers and in the in-repository test harness. The main currency concern is that the core framework is pinned to an exact version (Next.js 16.2.0) that carries published critical security advisories, and two declared dependencies are not used at all. Composite complexity: 5 / 10 (moderate).

🎯 Rating

🟑 ●●●○○ 3 / 5 β€” Amber. The stack is current, coherent and easy to staff, but the framework is pinned to a vulnerable release with no upgrade mechanism in place, which a buyer must budget to address immediately.

πŸ” Findings

1. Languages, frameworks and major libraries

ComponentVersion in useLatest (npm, 2026-10-07)StatusEvidence
Node.js runtime22 (.nvmrc; engines: >=22)22 LTSCurrent (LTS)[Observed] .nvmrc, package.json
TypeScript5.9.37.0.2Ageing (one major behind)[Observed] npm outdated
Next.js (App Router, RSC)16.2.0, exact pin16.4.0Current major, but vulnerable minor β€” see Module 8/9[Observed] package.json, npm audit
React / React DOM19.2.4 (exact pin)19.3.0Current[Observed]
Tailwind CSS4.2.24.3.3Current[Observed]
@supabase/supabase-js2.99.32.117.2Current major, ~18 minors behind[Observed]
@supabase/ssr0.9.00.12.7Pre-1.0, behind[Observed]
Resend SDK6.20.0 (installed)6.32.1Current[Observed]
mammoth (.docx reading)1.12.01.13.0Current[Observed]
xlsx (SheetJS)0.18.50.18.5 on npm (published 2022-03-24)Unmaintained on npm; vendor now distributes outside npm; known unfixed vulnerabilities[Observed] npm view xlsx 'time[0.18.5]'
ag-psd (Photoshop reading)31.0.231.0.2Current[Observed]
fflate (zip)0.8.20.8.3Current (patch has a fix)[Observed]
lucide-react (icons)0.577.01.52.0Pre-1.0 line, behind a major[Observed]
date-fns4.1.04.4.0Declared but not imported anywhere[Observed] grep across src, scripts, e2e: 0 imports
google-auth-library10.6.211.1.0Declared but not imported anywhere[Observed] same grep: 0 imports
Vitest3.2.75.0.3Two majors behind; critical advisory (dev only)[Observed]
Playwright1.62.11.63.0Current[Observed]
ESLint9.39.410.12.0One major behind[Observed]

2. Runtime, build, infrastructure and hosting

ConcernTechnologyEvidence
HostingVercel (serverless functions + static assets)[Observed] vercel.json, README "Architecture"
Scheduled jobsVercel Cron: /api/cron/purge-review 03:00, /api/cron/overdue 07:00[Observed] vercel.json
Buildnext build (Turbopack-era Next 16)[Observed] package.json scripts
CIGitHub Actions ci.yml (typecheck, unit tests, scrub, harness contract, lint, build); walk.yml manual[Observed] .github/workflows/
Infrastructure-as-codeNone. Vercel project, Supabase project, storage buckets, env vars and cron secret are configured by hand per deployment (docs/NEW_DEPLOYMENT.md)[Observed] no Terraform/Pulumi/supabase config.toml present
Database migrations92 hand-applied SQL files + supabase/baseline.sql for fresh installs; no migration runner[Observed] supabase/migrations/, CLAUDE.md "Migrations"
Deployment modelOne Vercel project + one Supabase project per client ("one codebase, never a fork")[Observed] README "Architecture"

3. Data stores, queues, caches and third-party services

TypeServiceNotes
Relational DBSupabase Postgres with row-level securityPrimary and only data store
Object storageSupabase Storage (campaign-assets, review bucket)Signed URLs served to the browser
AuthSupabase AuthSession cookies via @supabase/ssr
E-mailResendInvites, password resets, notifications, feedback
Queue / cacheNoneBackground work is Vercel Cron only; no queue, no Redis [Observed]
AI / LLMNone β€” the "Ask" feature is rule-based (src/lib/ask-intent.ts)[Observed] no model SDK in package.json

4. Measured size (cloc 2.06)

Whole repository (excluding node_modules, .next):

LanguageFilesBlankCommentCode
TypeScript5205,22420,05767,123
JSON7009,476
SQL1057421,9314,674
Markdown2160824,234
CSS51642,4273,402
JavaScript14867721,196
Python12132919929
Shell1454231523
Other (YAML, text, SVG)1115824506
Total7097,16826,36392,063

src/ only: 465 TypeScript files, 44,380 code lines, 9,934 comment lines (plus CSS). Of src/, the QA harness (src/app/qa) is 38 files / 4,482 code lines and test files are 70. [Observed]

Comment density is unusually high (β‰ˆ22% of TypeScript lines in src are comments), most of it narrative "why" commentary. cloc timed out on four very large spec/script files on the first pass; their lines are therefore slightly under-counted in the whole-repo total. [Observed]

5. Measured complexity (lizard, TypeScript, src/)

2,621 functions; mean cyclomatic complexity (CCN) 2.82.

CCN bandFunctionsShare
1–52,35589.9%
6–101515.8%
11–20632.4%
21–50431.6%
> 5090.3%

Top 10 most complex functions:

CCNNLOCLocationFunction
138269src/app/qa/store.ts:343matches (test harness)
109142src/lib/for-you.ts:94forYouItems ("what needs me" feed)
102135src/app/qa/store.ts:1279attachJob (test harness)
66154src/app/api/campaigns/[id]/ad-units/[unitId]/route.ts:26PATCH (ad-unit edit)
64118src/app/api/campaigns/[id]/brief/route.ts:27PATCH (brief edit)
59141src/app/api/review/files/[fileId]/route.ts:43PATCH (review decision)
53105src/app/api/campaigns/[id]/ad-units/[unitId]/render-push/route.ts:68POST
5388src/app/qa/api/[...path]/route.ts:226handle (test harness)
5291src/app/api/campaigns/[id]/jobs/route.ts:31POST (create job)
4491src/app/api/cron/purge-review/route.ts:29GET (file purge)

Files by summed CCN: src/app/qa/store.ts 1,074; src/app/qa/api/[...path]/route.ts 298; src/lib/schedule-sheet.ts 182; src/lib/for-you.ts 141; src/app/api/campaigns/[id]/plan/route.ts 107. Largest files by lines: src/app/qa/store.ts 3,349; review-view.tsx 1,373; ad-unit-panel.tsx 1,218; src/types/database.ts 1,150; admin-view.tsx 970; copy-deck-parser.ts 828. [Observed]

6. Hotspots

The standard hotspot method (complexity Γ— change frequency) cannot be applied: the repository contains a single squashed commit (3789df6, "Midshift source for audit", 2026-10-06), so there is no churn data. [Unavailable β€” requires the original, unsquashed git history.]

As a proxy (complexity Γ— size only, not churn), the candidates a new team would touch most cautiously are: the ad-unit PATCH route, the brief PATCH route, the review-file PATCH route, src/lib/for-you.ts, src/lib/copy-deck-parser.ts (self-described as "the most subtle code in the repo") and src/app/qa/store.ts, which must mirror every API route (see coupling below). [Inferred]

7. Coupling indicators

IndicatorMeasurementEvidence
Supabase server/service clientsimported 114 / 98 times[Observed] grep -rhoE "from '@/lib/..."
Auth helpers api-authimported 67 times[Observed]
Activity loggingimported 53 times[Observed]
Files touching a Supabase client154[Observed]
QA harness mirror125 route handlers must have a harness twin (scripts/harness-contract.js enforces it)[Observed]

There is no repository/data-access layer between route handlers and Supabase; routes and server components query Supabase directly. [Observed]

8. Composite Complexity Score: 5 / 10

DimensionWeightScore (1–10)Basis
Size25%5~44k app LOC, ~92k total β€” medium for a SaaS product
Structural complexity30%5Low mean CCN (2.82) but 52 functions over 20 and 9 over 50, concentrated in route handlers and the harness
Stack breadth20%3One framework, one backend platform, one e-mail provider; no queues, caches or microservices
Coupling25%6Direct Supabase access in 154 files with no abstraction; harness must mirror every route; fat route handlers mix validation, authorisation and persistence
Weighted4.85 β†’ 5

🧾 Evidence

  • cloc --exclude-dir=node_modules,.next --quiet . and cloc --quiet src (outputs above).
  • lizard src -l typescript --csv β†’ 2,621 functions; distribution and top-N computed from the CSV.
  • npm outdated (table in Β§1); npm view xlsx 'time[0.18.5]' β†’ 2022-03-24T14:23:09.623Z.
  • grep -rn "date-fns\|google-auth-library" over all source, script and test files β†’ no imports.
  • grep -rhoE "from '@/lib/[a-z0-9/-]+'" src | sort | uniq -c for fan-in.
  • git log β†’ one commit; git rev-parse --is-shallow-repository β†’ false (history genuinely squashed, not a shallow clone).
  • Files read: package.json, .nvmrc, vercel.json, README.md, .github/workflows/ci.yml.
  • Mermaid diagram validated with the Mermaid validator (valid: true).

⚠️ Risks

RiskSeverityEffort
Next.js exact-pinned at 16.2.0, a release covered by critical advisories (see Modules 8, 9); exact pins mean no automatic patch uptakeπŸ”΄ CriticalS
xlsx (SheetJS) is frozen on npm since 2022 with unfixed advisories and is used to parse uploaded spreadsheets🟠 HighS–M
No infrastructure-as-code; every client deployment is configured by hand, so environments can drift silently (the docs record migrations found missing in production)🟑 MediumM
No hotspot analysis possible β€” squashed history hides where change and defects concentrate🟑 Mediumβ€” (access request)
Unused dependencies (date-fns, google-auth-library) enlarge the supply-chain surface for no benefitβšͺ LowS
Several libraries a major behind (TypeScript, Vitest, ESLint, lucide-react, @supabase/ssr pre-1.0)βšͺ LowM

βœ… Recommendations

RecommendationPriorityEffort
Upgrade Next.js to β‰₯ 16.4 (and eslint-config-next with it) and switch to caret ranges with a lockfile, so patch releases flow inP1 (immediate)S
Replace xlsx with the vendor's maintained distribution or an alternative (e.g. exceljs), or move parsing fully client-sideP1S–M
Remove date-fns and google-auth-libraryP2S
Introduce infrastructure-as-code (Supabase CLI config + Vercel project config) and an automated migration runnerP2M
Schedule a dependency-currency pass (Vitest, TypeScript, Supabase SDKs) with Renovate/DependabotP2M
Obtain the unsquashed git history to complete hotspot analysisP1 (diligence)β€”