π Executive Summary & Overall Assessment
π Executive Summary & Overall Assessment
Key
| Rating | Severity | Status |
|---|---|---|
| π’ Green β 4 to 5 | π΄ Critical | β Yes |
| π‘ Amber β 3 | π High | β No |
| π΄ Red β 1 to 2 | π‘ Medium | β Partial |
| βββββ β score out of 5 | βͺ Low |
π Summary
Midshift is a well-conceived, carefully engineered campaign-production tool for retail marketing teams and their agencies. Its code is cleaner, better documented and more thoroughly self-checked than is typical for a young, single-owner product, and its most distinctive features β reading copywriters' Word decks, matching designers' files to adverts by name, and building tracking links from one template β are well tested. As delivered, however, it carries two critical security exposures that are cheap to fix but must be fixed before any acquisition completes: database permission rules that, as written in the repository, let any signed-in user make themselves an administrator, and a web-framework version with published critical vulnerabilities. Beyond those, the largest risk is not technical but human: the code, the decisions, the operation of each client deployment and the intellectual property all sit with one person, and the git history has been squashed so that how the product was built cannot be inspected. A buyer is acquiring a sound foundation with a short, well-defined list of urgent repairs and a significant dependency on the founder's transition.
π― Rating
π΄ βββββ Overall: 2 / 5 β Red (as delivered). The asset's underlying engineering would merit an Amber 3; it is held at Red by a Critical privilege-escalation path, a critically vulnerable framework pin and a bus factor of one. The first two are small (S-effort) fixes; with them made and verified on every live deployment, the overall position moves to 3 / 5 Amber within about 30 days.
π Findings
βοΈ Verdict
Technically, Midshift is a coherent modular monolith on a mainstream stack (Next.js, React, TypeScript, Supabase, Vercel, Resend) that a competent web team could take over. Domain logic is centralised in small, tested functions; type-checking and linting are strict and clean; the team has turned its own lessons into automated guard rails. The weaknesses cluster in one place β the path by which data is written and permissions are checked β which is the least tested part of the system and where every serious security finding sits. Operationally, each client is a separate, hand-configured deployment with hand-applied database migrations, which suits a small number of high-touch clients but not a scalable SaaS thesis. Commercially, the code is owned by an individual, and there is no history to verify authorship or delivery pace.
π Scorecard
| # | Module | Rating | RAG | Headline finding |
|---|---|---|---|---|
| 01 | Product & Domain Overview | βββββ 4 | π’ Green | Clear, opinionated product; ad name as the join key; distinctive deck parser and file matcher; single-tenant, English-only |
| 02 | Technology Stack & Complexity | βββββ 3 | π‘ Amber | Modern, narrow stack; moderate complexity (5/10); Next.js exact-pinned at a vulnerable release; two unused dependencies |
| 03 | Architecture & Design | βββββ 3 | π‘ Amber | Sensible modular monolith; inconsistent write paths (some browser-side writes bypass server rules); no transactions; unbounded queries |
| 04 | Domain Model & Business Rules | βββββ 3 | π‘ Amber | 75 rules catalogued, mostly in tested pure functions; contradictions around approval reset and member management; 29 rules untested |
| 05 | Code Quality & Standards | βββββ 4 | π’ Green | Strict TS, clean lint, 2.3% duplication, self-enforcing gates; complex core handlers; no error tracking |
| 06 | Technical Debt & Maintainability | βββββ 3 | π‘ Amber | ~33% of source files touched by measurable debt, severe debt concentrated in ~15β20 files; debt tracked in prose, zero TODO markers |
| 07 | Testing & QA | βββββ 3 | π‘ Amber | 687/687 unit tests pass; journeys 467 passed / 7 failed (an expired-date test and a layout check) / 1 file unfinished; domain logic 67% covered; API routes 0.9%; browser suite runs against a mock, not the real routes |
| 08 | Dependencies & Licensing | βββββ 2 | π΄ Red | 24 known vulns (11 in production) incl. critical Next.js RCE on a used code path; abandoned xlsx; licences clean; IP held by an individual |
| 09 | Security & DevSecOps | βββββ 2 | π΄ Red | Route code careful, but DB policy allows self-promotion to admin; stored XSS; in-job approval self-grant; no CSP, rate limiting or security scanning |
| 10 | Source Control, CI/CD & Practices | βββββ 3 | π‘ Amber | Strong CI gates; no evidenced code review; direct pushes to main; manual migrations; history squashed |
| 11 | Delivery Metrics & Key-Person Risk | βββββ 1 | π΄ Red | Bus factor of one; no DORA metric measurable |
| 12 | Documentation | βββββ 3 | π‘ Amber | ~46k words, API reference near-complete; 9 of 16 sampled claims drifted, incl. fresh-install and security facts |
| 13 | Integrations | βββββ 3 | π‘ Amber | Only Supabase, Vercel, Resend; deep Supabase coupling; no monitoring; e-mail failures largely invisible |
Unweighted mean of module ratings: 2.8. The overall rating is set below the mean deliberately, because Critical security findings and key-person risk dominate a buyer's exposure regardless of average quality.
π© Top 5 risks
| # | Risk | Severity | Business impact | Effort |
|---|---|---|---|---|
| 1 | Self-promotion to administrator. The users update policy (supabase/baseline.sql:1044β1046) has no column restriction, and admin checks read users.role; sign-up also trusts a client-supplied role (baseline.sql:947). (Module 9) | π΄ Critical | Any client user could gain full control of their organisation's data, approvals and user accounts. Whether live databases match the repository is unverified. | S |
| 2 | Vulnerable framework pinned in production. Next.js 16.2.0 is affected by ~26 advisories including critical RCE in next/og (used by the tab icons) and middleware-bypass issues; no automated dependency scanning. (Modules 8, 9) | π΄ Critical | Remote compromise of the hosting environment; exposure persists until someone manually upgrades every client deployment. | S |
| 3 | Key-person and IP concentration. One individual owns the code, holds the operational knowledge and access for every deployment, and directs an AI-assisted build process; history is squashed. (Modules 8, 10, 11) | π΄ Critical (transactional) | Loss of the founder would stall development and operations; ownership and provenance cannot be verified from the material supplied. | MβL |
| 4 | Sign-off integrity can be undermined. A project manager can make themselves the approver; any editor can remove the approver; a deck re-import can change carousel wording without reopening approval; stored XSS via the brief can act in an admin's browser. (Modules 4, 9) | π High | Undermines the product's core promise β that an approval means someone accountable signed off exactly this wording. | SβM |
| 5 | Untested write path and invisible failures. Route handlers have 0.9% unit coverage and are emulated, not exercised, by the browser suite; no error tracking or integration monitoring; missing CRON_SECRET silently disables file purge and overdue alerts. (Modules 5, 7, 13) | π High | Defects and outages surface only when customers report them; regressions likely when the riskiest code is changed. | M |
π Top 5 strengths worth paying for
- Distinctive, well-tested domain IP. The copy-deck parser (85% covered against a 22-unit regression deck), the shared filename-to-unit matcher (98%), and the single UTM builder (100%) encode hard-won workflow knowledge competitors would have to rediscover. (Modules 1, 4, 7)
- Engineering discipline turned into automation. Strict TypeScript, zero lint warnings, low duplication, and bespoke guard-rail tests (every write's result must be read; every queried column must exist; every route must have a harness twin; no client identity may be committed). (Modules 5, 10)
- Exceptional written rationale. Architecture, API reference (82 of 83 routes) and a decision log explain why things are as they are β rare for a product of this size, and the main mitigation for the key-person risk once corrected for drift. (Module 12)
- Clean, low-cost stack and licensing. Mainstream, easily staffed technologies; only three runtime vendors; no strong-copyleft licences in the dependency tree; no AI-provider dependency or cost. (Modules 2, 8, 13)
- Data isolation by design. One database per client means no cross-tenant leakage risk and a straightforward story for enterprise data-protection reviews; white-labelling is built in as data. (Modules 1, 3)
β What could not be assessed β follow-up questions and access requests
| # | Question / request | Needed for | Module(s) |
|---|---|---|---|
| 1 | Provide the full, unsquashed git history and GitHub organisation access (PRs, issues, Actions run history, branch protection settings) | Hotspots, contributor/bus-factor analysis, commit hygiene, code-review evidence, lead time, change failure rate | 2, 6, 8, 10, 11 |
| 2 | Read access to every production Supabase project: confirm pg_policies and column privileges on users, whether public sign-up is disabled, which migrations have run (incl. 040, 061, 065, 088, 091), schema parity with baseline.sql | Confirm/clear the Critical self-promotion finding; environment parity | 3, 7, 9, 12 |
| 3 | Read access to every Vercel project: deployed Next.js version, env vars set (incl. CRON_SECRET, OWNER_EMAIL, GHOST_EMAIL), deployment and rollback history, function metrics, response headers (HSTS) | Confirm Critical framework exposure; DORA deployment frequency, lead time, MTTR; performance | 2, 8, 9, 11, 13 |
| 4 | Incident log, monitoring/alerting setup and any post-mortems | Change failure rate, MTTR, operational maturity | 11, 13 |
| 5 | Number of live deployments / customers, contracts, revenue, pricing, and product roadmap | Commercial context; scale of remediation roll-out | 1 |
| 6 | IP chain of title: contributor list, assignment deeds, use of AI coding tools and their terms, and access to the related FS002-dev/campaign-studio repository | Ownership and provenance warranties | 8, 11 |
| 7 | Resend account and DNS (SPF/DKIM/DMARC) for sending domains | E-mail deliverability and spoofing protection | 13 |
| 8 | A staging deployment with test credentials for the five personas | Run live e2e specs and the acceptance walk | 7 |
| 9 | Data-protection documents: privacy notice, sub-processor list, DPA with clients, backup and restore evidence | GDPR/POPIA exposure; recoverability | 9, 12 |
| 10 | Market and customer evidence (interviews, competitor positioning) | Differentiation claims | 1 |
πΊοΈ Recommended next steps for a buyer
π Before signing (conditions precedent)
- Owner to fix and deploy, to every client: restrict
usersupdates to non-privileged columns (and stop trusting sign-up metadata for role); upgrade Next.js to β₯ 16.4; evidence both on live systems. - Obtain items 1β3 and 6 above; obtain a deed of IP assignment and originality warranties.
- Agree a paid founder transition and retention period.
1οΈβ£ First 30 days
- Close the High security findings: approval self-grant and approver removal, stored XSS in the brief, open redirect, unescaped e-mail HTML, QA harness routes in production builds; add rate limiting to auth endpoints.
- Add Dependabot/Renovate,
npm audit, CodeQL/Semgrep and secret scanning to CI; require PR review onmain. - Add error tracking (e.g. Sentry) and alerts for cron failures and e-mail errors.
- Second engineer completes a shadowed deploy, migration and incident drill.
2οΈβ£ 31β60 days
- Route-level integration tests against a local Supabase for authorisation and the six most complex handlers; RLS tests for every user-writable table.
- Move all browser-side writes behind API routes (or prove RLS enforces the same rules); introduce transactions (Postgres functions) for multi-row writes.
- Automate migrations and record per-deployment schema state; correct the fresh-install documentation; replace
xlsx.
3οΈβ£ 61β90 days
- Run the journey suite in CI; stand up a shared staging environment.
- Refactor the fat route handlers behind tests; paginate the capped queries; replace persisted long-lived signed URLs.
- Decide the tenancy strategy: if the thesis is SaaS scale, scope the move to multi-tenant or to automated per-tenant provisioning (infrastructure-as-code).
- Rewrite handover and process documentation for a human team; move the debt register into an issue tracker; delete dead code and orphaned schema.
π§Ύ Evidence
Synthesised from module files 01β13 in this folder. The highest-severity findings were independently re-verified while compiling this summary:
supabase/baseline.sql:1044β1046(usersupdate policy, no column restriction),:940β950(handle_new_userreads role from metadata);src/lib/api-auth.ts:50, 123(admin check readsusers.role); no trigger or column grant onusersfound inbaseline.sqlorsupabase/migrations/.npm audit/npm audit --omit=dev(24 / 11 vulnerabilities);src/app/icon.tsx:1,16,src/app/apple-icon.tsx:1,14(ImageResponse).src/app/api/campaigns/[id]/members/[memberId]/route.ts:25β48withsrc/lib/discipline.ts:58(self-grant of approver discipline).src/lib/brief.ts:187β195returns HTML-looking text unescaped;brief-view.tsx:557renders it; campaign PATCH acceptsbrief_textwithoutsanitizeBriefHtml.src/app/qa/layout.tsx:11gates pages only;src/app/qa/{api,state,reset}/route.tshave no environment check.git log --allβ one commit;LICENSEline 1.
β οΈ Risks
See Top 5 risks above; full registers are in each module's Risks section.
β Recommendations
See Recommended next steps above. Priority order: conditions precedent β 30 β 60 β 90 days.