Tier1 × Pannell Co · Time-Tracking Integration · Architecture Fork
One decision, made once, that quietly re-shapes five of the six lanes. This is the honest tradeoff — cost, ownership, risk, and exactly what changes where — laid out so the choice is obvious by the time you've read it, not before.
Your own words already point one direction. You said the thing you can't accept is being unable to fully service this client — and that a permanently-bolted-on Vue/Supabase module is exactly the 5% you'd never fully own.
Everything below is here to pressure-test that instinct, not decorate it. The credit cost of the rewrite is small — smaller than the buffer you were carrying. The one real risk is confirming that ported payroll and reconciliation logic still returns identical results — and that's automatable and local: a script runs the old function and its new port against the same real data and diffs the output. A risk named, then closed — not a reason to hesitate.
Same frontend either way. Login is Pannell's own existing auth in both cases — Cognito is no longer in scope. The fork is only about what lives behind the routes.
Path A · current locked plan
The Vue app's backend keeps running as-is — self-hosted Supabase edge functions inside a Fargate container. The new app reaches it through a gateway that proxies, mints a second token, and mirrors roles into it.
What you keep
What it costs you, forever
Path B · the pivot
Port the ~99 relevant backend functions into Next.js API routes. Retire Supabase entirely. One app, one database, one stack — the logic sits directly behind the same routes, no proxy in between.
What you gain
What it costs you, once
Where the money and effort actually go under each path. The credit numbers are the real scoped estimates — not the buffer you were carrying.
| Line item | Keep the module | Absorb into one app |
|---|---|---|
| Backend logic conversion (AI credits) | $0 nothing to convert |
$25–55 99 functions, ~21K lines |
| Backend verification & QA | Minimal logic runs as-is |
Automated bulk run every function, every input, diffed at once; a human classifies each distinct mismatch pattern once (a handful of calls), the harness auto-resolves every repeat |
| Frontend conversion (AI credits) | $35–80 | $35–80 — identical |
| Auth build · lane 02 | Gateway + token‑mint + Fargate module hosting | Pannell's existing login — no Cognito, no mint, no container |
| Roles sync · lane 03 | Build SQS + Lambda + nightly reconciliation | Deleted role checks happen in code |
| Data migration · lane 04 | Into the module's Postgres | Into one standalone Postgres (likely smaller — RLS drops) |
| Mass upload · lane 05 | Same | Same — untouched either way |
| Ongoing hosting (every month, forever) | Fargate + Supabase | Just the app's database |
| Codebases to maintain | 2 Next.js + Deno/Vue module | 1 |
| Share of the app Tier1 fully owns | ~95% module is foreign | 100% |
| Operational points of failure | More proxy · mint · mirror · container | Fewer |
On your $150–200 figure: that's a safe all-in buffer. The actual credit cost is smaller — roughly $25–55 backend plus $35–80 frontend. And the verification that used to look scary is mostly automated and local: Claude writes a harness that runs every old function and its new port against the same real data, all at once, and diffs the outputs — no Playwright, no browser, it's backend‑to‑backend. A human classifies each distinct pattern of mismatch once (timestamp field, generated ID, row order — a handful of calls total), and the harness auto-resolves every repeat of that pattern from then on. Price the decision on the ownership and ops savings, not on a QA ceremony that largely runs itself.
Relative build weight under each path — the taller the after-bar shrinks, the more work the rewrite removes. Two lanes don't move at all.
Same 47 routes, same Rosetta Stone, same cost. Only the word "gateway" is re-defined — cosmetic.
Cognito isn't needed at all — Pannell's own login already handles both field and admin sign-in. Token-mint, Fargate, and the proxy hop go with it. What's left: migrated users join the existing login.
The whole mirror — SQS, Lambda, reconciliation — is gone. Only the one-time role-mapping decision survives.
Still lift the live database — but into one plain Postgres the app queries directly. RLS likely doesn't migrate at all.
Already targets Pannell's own backend and rebuilds natively. Nothing here touches it.
Not a generic pros list. These are the things you said mattered, and which path each one points toward.
Choosing to absorb the backend still leaves one fork — and this, not Cognito, is what actually moves the verification risk. It comes down to one thing: do you keep the database's row-filtering, or rebuild it in code?
Next.js routes replace the old functions — but the database keeps the row-level-security policies it already has. Each route connects carrying the user's identity, so the database filters rows exactly as it does today.
You inherit
Battle-tested filtering, untouched — nothing to re-derive. The residual risk is one uniform thing: passing identity into the database session correctly, solved once in a connection helper and reused everywhere.
The tradeoff
You keep maintaining the database's policy code (a Postgres skill), and the database stays set up to read a per-request identity. Since lane 04 already copies the database with its policies intact, this is the less-work path there too.
Drop the database policies entirely; every row-filter the database used to do silently becomes explicit query logic written into each Next.js route.
You gain
No database-specific policy skill to keep; all logic in one place, one language. Cleaner if you ever want zero logic living inside the database.
The tradeoff
Every filter has to be re-derived — a larger surface, and exactly the case the automated old‑vs‑new diff harness in §06 is built to catch. Named here, closed there; it's why that harness exists.
Neither mode needs Cognito. Keeping the database policies just needs the app to carry the logged-in user's identity into the database connection — which your own Next.js server does directly, having already authenticated them through Pannell's existing login. Cognito was never part of this layer at all.
The place a ported function can go wrong isn't the arithmetic — that copies over verbatim, unchanged. It's how rows get filtered by who's asking. Keeping the database's own filtering leaves that risk small from the start. Rebuilding it in code carries more of that surface — so that path leans on this gate more, not less.
Either way the gate is the same: run every old function and its new port against the same real historical data, across each role, and diff the outputs. Claude writes that harness; it runs locally against a database copy; anything that doesn't match byte‑for‑byte gets flagged before go‑live. A real risk, named — with a concrete, mostly‑automated path straight through it. The debt you take on is debt you've actually retired, not just moved.