The People Platform, end to end
Six pages. What the system is for and what it must do, what has been decided about how to build it and what was rejected on the way, how it is built, how it is set up once, and how it is operated. Written to be read before the technical conversation with the engineer, not after it.
What this page is, and what it is not
The repository holds the real documents — CONTEXT.md for the language, docs/adr/ for forty decisions with their reasoning, and three engineering manuals. Those are written for the person building or operating the thing, and they say what to do. They do not say what else was on the table.
This page adds that. The Decisions page is the one that does not exist in the repository: sixteen engineering choices, each with what was rejected, what the choice costs, and whether it is actually settled. That is the page to argue from.
Everything here is a snapshot of 6 August 2026. Where a page here and an ADR disagree, the ADR wins and this page is out of date.
Where it standsWritten, unrun, and missing
The design is far ahead of the code. Nothing in the database layer has ever been executed — Docker was not running when it was written, and app/ still has no package.json, so none of it can run yet.
Settled and written
- Forty ADRs, three grilling sessions
CONTEXT.md— the domain language- Technical design, setup, runbook
- Migrations
0001schema,0002RBAC - Three roles, permission catalogue
Written but never run
0003legal entity, account-link trigger0004_rls.sql— every policy0005departments and entitiesseed.sql— 32 real peopletests/rls/— matrix and suitescripts/import-employees.ts
Does not exist
app/package.json— no scaffold, so nothing above can execute.github/— no workflows, so the checks branch protection requires have nothing to run- RLS matrices for
hrms,org,leave, Storage - The golden payroll fixture table
The ordering that matters
Two rules in the ADRs say a document must exist before the code it governs: the RLS matrix before any policy (ADR-0003, amended) and the payroll fixture table before any payroll code (ADR-0039). Both exist for the same reason — tests derived from an implementation only prove the implementation does what it does.
The core matrix was written first and held the line. The fixture table has not been started, and it needs Finance and a calendar, so it is the longest lead item on the project.
What is openThree blocking, two undecided, seven to check
Nothing here blocks reading the rest of these pages. Two of the three blocking items block the first real work.
Blocking
- DataThe Indonesian entity’s registered name and registration number. Not in any document we hold. All 32 tracker rows say “KPI Media Pte Ltd” while 22 people are marked BPJS, which requires an Indonesian employer. These appear on statutory filings, so the importer must not run against production until they are real.
- ScaffoldNo
package.json. Until it exists, the RLS suite cannot run and the RLS policies are unproven prose. First ticket. - FixturesThe payroll fixture table. Twenty to thirty worked examples, authored with Finance. Payroll implementation is deliberately blocked on it (ADR-0039), and it takes calendar time rather than engineering time, so it should start now.
Two things only you can decide
- WorkflowPR review turnaround.
technical-design.md§13 says the senior reviews every PR; it does not say how fast. A full-time engineer blocked on review cannot merge, cannot start the next ticket, and will either idle or guess. Commit to a number — same working day is the usual one — and name where questions go between reviews. - PolicyQ1 and Q3 of the RLS matrix — may a person edit their own directory row, and may
finance_hrreadcore.account. Both were taken as recommendations rather than ruled on. They are written into0004_rls.sqleither way, so a different answer means a migration.
Facts to verify before Zeabur
Not decisions. But each one changes the plan if it comes back wrong, and all seven are cheap to check.
| Check | What it changes if the answer is no |
|---|---|
| Does the Supabase template deploy twice into one project? | The entire environment topology assumes it. Name and port collisions are the likely failure. Falling back means two projects and the dashboard argument returns. |
| Does Zeabur offer a disk alarm? | setup.md specifies 70%. If the feature does not exist, the shared-disk mitigation is imaginary and has to become a job of ours posting to Slack. |
| What image versions does the template pin? | config.toml must match and cannot be written until this is known. Version drift between local, dev and production is the failure this setup exists to prevent. |
Does the Node image carry pg_dump? | ADR-0037’s rejection of Cloudflare Workers rests on it, and postgresql-client is absent from most Node base images. No pg_dump, no backups. |
Which domain hosts Google Workspace — kpimedia.sg or kpimedia.co? | Staff addresses are @kpimedia.sg, but setup.md §5 says to merge Resend’s SPF into Workspace’s existing record on kpimedia.co. One of those is wrong. A second v=spf1 breaks mail on whichever domain it lands on, and the answer also decides what payslips are sent from. |
| Is the senior a Workspace admin? | The OAuth consent screen must be Internal. That is the real domain restriction — not a GoTrue setting. |
| Who holds GoDaddy DNS and Cloudflare billing? | Three CNAMEs and the Resend records go into GoDaddy. Not having that access on the day stops setup dead. |
Two inconsistencies found while assembling this page
Legal entity count. The Concept screen’s masthead says three legal entities. Migration 0005 creates two — KPI_SG and KPI_ID. One of them is wrong, and since statutory scheme derives from the legal entity (ADR-0023), it is not cosmetic.
A placeholder that does not look like one. 0005 leaves both registration numbers null on the stated principle that a null is visibly missing while a plausible-looking value reads as filled in. But the same row carries 'PT KPI Media Indonesia' as the registered name — which is a guess, held to a lower standard than the number beside it. Either it is confirmed or it should be null too.
Where to goThe other five pages
Concept
What the platform is for, the data model, the four modules, what each role can do, and the build order. Signed off by Yashwin; kept as approved.
02 · newDecisions
Sixteen engineering choices with what was rejected and what each costs. Plus three decisions that were made but never written down — the ones an engineer will want to reopen.
03 · referenceDesign
How it is built. Topology, the two request paths, repo layout, database, auth, secrets, TypeScript, errors, testing, workflow. Faithful to technical-design.md.
Setup
Seven steps, who does each, and the five places it goes wrong quietly. The literal commands stay in the repository, where they are actually run.
05 · foreverRunbook
First production bootstrap, the release loop, backups, restore, and what to check when something breaks. Written for the operator six months from now who has forgotten all of it.