NERP-AI
Business Systems

Welcome. Sign in to continue.

⚠ Development environment. Access is by invitation only, and there's a button that attacks the database on purpose. Not validated — not for real batch records.
← All modules
Raw materialg / servingg / unitExcel Total kgExcel% of blend

This is TRG's real formula, scaled by the engine. The “Excel” columns are what the spreadsheet says. Change the unit count and watch the batch scale — fill weight and capsule count don't move, because they're properties of the recipe, not the batch.

Look at the % sum. Ours is exactly 1; the spreadsheet's is 0.999999999958937 — Excel just displays “1”. That's why we store grams and derive the percentage, never the reverse.

Capsules per serving = fill weight ÷ capsule capacity, rounded up. 40.0001022 ÷ 0.74 = 54.05 → 55. Rounding down would ship a serving under its label claim.

← All modules
Activity
Tenants
Access
Platform admins
Invitations
Logs
Services
Everything that has happened, newest first.
WhenWhoActionWhereDetail

Platform events (tenant created, admin granted) and every tenant's audit trail — memberships, assumes, and manufacturing (lots received/released, weigh-outs, runs) — merged and sorted. Read-only; the chains are append-only and hash-verified.

TenantNameKindTimezoneMembersAudit entries

Add a tenant — this is "add a customer"

Assume a tenant — written into their audit trail

Assuming a tenant shows exactly what they see, for support — and writes a READ entry into their audit trail with your identity and reason. It cannot sign anything.

EmailSubjectTenantRoleCan sign?Granted by

Grant access directly — for someone who already signed in

This is the screen that crosses tenant boundaries — the one place a bug could show one manufacturer another's formulations. So it's read-mostly, it shows counts rather than contents, and every grant is written into that tenant's own audit chain.

That last part is the point. When a customer asks “can you see our formulations?”, “we wouldn't do that” is worthless. “Yes — and it's in your audit trail, which you can read, and which we cannot alter” is a real answer, and it's only true because of this.

A platform admin is not a tenant admin. Todd is admin on TRG — he runs it, and he must never see Acme. This is a separate identity check, not a role flag, so the two can't drift into each other.

A grant requires a reason. And roles are per tenant — the same person can be admin on TRG and viewer on Acme, or absent from Acme entirely.

EmailSubjectGranted byReason

A platform admin sees every tenant. Revoking it demotes rather than deletes — it removes that view and leaves their own tenant memberships exactly as they were. Someone who was admin on TRG goes back to being admin on TRG, and nothing more.

Root cannot be removed. Not by another admin, not by the app, not by root. A Postgres trigger refuses the delete, so it holds even against the database owner — the only account that can repair a broken admin screen must not be deletable by a broken admin screen. Only root can add or remove other platform admins.

Invite someone — to a tenant, with a role

EmailTenantRoleInvited byReasonStatus

Access arrives exactly one way: an invitation, to a tenant, with a role. An uninvited account signs in fine and sees nothing until it is invited.

The last 24 hours of application logs from CloudWatch — read-only, in-app, so you never open the AWS console. Ephemeral operational telemetry (redacted; 14-day retention), not the Part 11 audit trail, which lives in Postgres and is immutable.

Live health of what we can reach, and a launchpad to the consoles this system runs on.

Health — live, from this deployment’s /health

The dependencies the running app can actually reach, server-side. Postgres is the Neon database this build is wired to; migrations checks the schema is the one this code was built against; Clerk is the auth provider (a soft check — if it’s out nobody can sign in, but the app still serves, so it shows amber, not red). Everything below is a link: the AWS, GitHub and Atlassian consoles can’t be probed from here.

Data & auth

AWS — account 020658506497 · us-east-1 · sign in via SSO first

Code & CI

Project

Live sites

← All modules
IdSeriesNameUoMPrice/kg

The 1000–8000 series is TRG's, not ours. Raw materials, components, labels, formulations, capsules, finished goods, jobs, shipments — the numbering Todd already uses.

Click a manufactured item (4000/5000/6000) to explode its bill of materials. ProBasic Choc (6023) is the real one: a bottle contains 770 capsules, each capsule is a blend plus an empty shell, and the blend is 52 raw materials.

A capsule is its own tier, independently stocked and lotted — not a step inside "make the finished good". Todd called that crucial, and it is why the tree has four levels rather than two.

Read only, deliberately. Editing an item or a formula needs the lot decision (NERPAI-17) and a signing story. This is here to be argued with, not typed into.

← All modules

Receive a raw material

Receiving mints the internal lot YY-NNNN and puts the material in quarantine. The supplier lot is captured verbatim — the CoA read IP110924 where TRG's own form recorded P110924, and keying on our lot is what keeps that mismatch visible instead of losing the receipt.

Quarantine — QC's queue

LotItemSupplier lotVendorQtyReceived

A lot cannot be released without a CoA and a named approver — and that is a database trigger, not just this screen. Approving records who released it and when; the DS-prefixed released form (DS26-0001) is a rendering of the internal lot plus the approved state, never a second identifier.

Receiving is an operator action; releasing is QC's. A viewer sees the queue and can do neither — the server enforces the role, this screen only reflects it.

Rejected is terminal. A rejected lot can never be approved, and the material does not enter production.

← All modules
Raw materialRequired (kg)Released on hand (kg)StatusReleased lots

This is the build sheet, not the run. It scales the blend to your batch size — the same engine, the same maths proven to the gram — and checks it against the lots QC has released. Green means you can weigh it; red means you cannot, and says which ingredient is short.

Only released (DS) lots count. A quarantined or rejected lot is not weighable, so it does not close a shortfall — the same SOP-042 gate as intake, one tier up.

What this does not do yet, on purpose: it commits nothing — no blend lot is minted, no quantity deducted, no BPR generated. That step needs two decisions (does a blend lot carry the job number or its own lot, and the consumption ledger), which are Todd's to make. Until then, “on hand” is the approved received quantity.

← All modules

Open a run

Runs

Job / blend lotProductUnitsState

A run is a job, and the job number IS the blend lot. Weigh released (DS) lots into it by the exact kilograms taken — a bag is opened, drawn from, resealed and reused on the next job, so each lot carries a running balance. The database refuses weighing a quarantined lot, or more than a lot has left.

Both directions. A run shows the lots that went into its blend; a lot shows the jobs that drew it down. That is the recall spine — raw material to blend, and blend back to raw material.

Next: packaging the blend into capsules and finished goods (the next consumption step), and the BPR document + wiring the run into the audit trail (NERPAI-19).

← All modules

Open a capsule run

Capsule runs

Job / capsule lotCapsuleTargetState

Stage 2: the intermediate. A capsule run draws a completed blend (4000) through the encapsulator and yields a counted 5000 capsule lot — the job number IS the capsule lot. The blend is drawn by exact kilograms and carries a running balance, the same model as a raw-material lot one tier down. The database refuses drawing an uncompleted blend, or more than a blend produced.

Recall crosses the tier both ways: a capsule lot shows the blend it came from (and thus its raw materials); a blend shows the capsule runs that drew it. Open the Traceability module on any job to walk the whole chain.

Not yet: deducting the empty vegetable capsule shells (a count) — waiting on how they are received/counted at intake (question posted to Todd) — and the packaging tier (5000 → 6000, Stage 3) plus the IMR/BPR document (NERPAI-19).

← All modules

Open a finished-good run

Finished-good runs

Job / FG lotFinished goodTargetState

Stage 3: the finished good. A finished-good run bottles a completed capsule lot (5000) — drawn by the each against the capsule lot's running count — and yields a counted 6000 finished-good lot, the job number being the FG lot. The database refuses bottling an uncompleted capsule lot, or more capsules than the lot produced.

The chain is whole now: raw material → blend → capsule → finished good, every tier its own job/lot and its own consumption ledger, traceable in both directions. Open Traceability on any job to walk it end to end.

Not yet: deducting the packaging components — bottles, lids, labels, neck bands (a count) — on the same NERPAI-41 intake-count question as the capsule shells; and the MMR/IMR/BPR documents (NERPAI-19).

← All modules

Recent receipts

LotItemVendorReceivedState

Recent runs

JobProductStateProduced

A live snapshot over what's recorded — stock, the QC queue, production, and lots needing attention. Click any receipt or run to open it in Traceability. Numbers come straight from the append-only ledger.

← All modules
ItemSeriesReleased (kg)Quarantine (kg)LotsNearest expiry

Released is what a batch can be weighed from — received minus everything the ledger has consumed, summed across a lot's approved receipts. Quarantine is received but not yet passed by QC, so it is on hand but not weighable. A rejected lot is not stock at all.

To trace any single lot — where it came from, where it went, its mass balance — open it in Traceability. QR labels and camera scanning at intake are still to come (NERPAI-3).

← All modules

Recall, both directions. From a raw-material lot: every job that weighed from it. From a job (blend lot): every raw-material lot that went in, with the vendor's lot and CoA. Click any lot or job in the result to pivot to it — that is the recall walk.

The genealogy sits next to the record. Each result carries the audit history of the thing — received, released, weighed, completed, and by whom — read from the append-only chain.

The key flips at the make step: a received lot is a DS lot, a made batch is its job number. The chain today spans raw material ↔ blend, and extends through capsule and finished good as packaging lands.

← All modules
SeqActionEntityActorReason VerPrev hashHash

Try the red button. It runs UPDATE audit_entries… as the database owner — the most privileged role there is. Postgres refuses: a trigger binds every role, so history cannot be rewritten even with full database access. The hash chain proves a tamper; this prevents one.

“UPDATE with no reason” is refused — §11.10(e) says a changed record must say why, enforced in code and as a database constraint.

Switch tenants (top right): same page, same code, different data. Postgres row-level security enforces it — a query that forgot its WHERE clause still cannot leak.