A compliance portal that keeps the batch trail.

Texas regulates consumable hemp under DSHS Chapter 300, and the rule wants a paper trail for every batch: the lab report on each raw material, a signed recipe, a record of the run with actual weights, and a lab report the customer can reach from the label. I built a portal where each of those records is a page, and every page links to the one before it. A lot number on a box traces back to every lab report behind it in a few clicks.

Elevated Trading · 2026 · Laravel · Google sign-in · live at tct.elevatedtrading.com · ← all work

The problem

At a small hemp manufacturer, the batch trail lives in folders, email attachments, and somebody's memory. Each record exists somewhere. Nothing connects them. When the state asks about one lot, someone spends an afternoon rebuilding the chain by hand and hopes no lab report went missing along the way.

What I built

One web portal. Lab reports attach to ingredients. Ingredients go into master recipes. Each recipe spawns batches with real weights, and each batch is packed into runs with lot numbers and sales orders. The finished batch's lab report gets a public page for the label. Sign-in is by Google account, and each company gets its own workspace with roles.

What changed

"Show me this lot" means opening the run, clicking the batch, and one more click reaches any ingredient's lab report. The portal won't start a batch while an ingredient has no lab report on file, so the gap gets caught on the production floor instead of in an audit. The four core modules went from whiteboard photos to a running portal in two days.

The regulator's question, answered in clicks

Start where an inspector starts: the lot number on a box. It leads to the production run that packed it: how many units, what jar, which lot, against which sales order. The batch that filled those jars is a link on that page.

Screenshot of a production run page in the TCT portal. Run details on the left: run PR-2026-001, a link to individual batch IB-2026-001, a link to its master recipe, product CBD Tincture 1000mg, status Complete, who created it and when, retention until 2029. Packaged items on the right: two lines of 30ml dropper bottles, 240 and 120, with batch number, lot number L2026-001, and a sales order on each, totaling 360 units.
A production run: what was packed, under which lot, for which order. The batch and the recipe are links.

The batch page is where the trail lives. It names the recipe it was made from, shows the target and the actual weight of every ingredient with the difference, and pins the lab report for each ingredient as it stood when the batch started. Every production run packed from this batch is listed underneath.

Screenshot of an individual batch page in the TCT portal. Batch details on the left: batch IB-2026-001, a link to its master recipe, scale 1x, status Complete, created and completed dates, retention until 2029. On the right, Ingredients Used: CBD distillate, MCT oil, and a terpene blend, each with target weight, actual weight, variance, and a View COA link with its expiration date. Below, the production runs made from this batch.
An individual batch: actual weights against the recipe, a lab report pinned to every ingredient, and the runs it became.

The trail, end to end

Five kinds of record, each mapped to a section of the rule, each pointing at the one before it. Lab reports come in from two directions: one round of testing on raw materials, one on the finished product before it can be sold.

"Show me everything behind lot L2026-001." Every hop back is a link. SOURCE · §300.206 RECIPE · §300.204 BATCH · §300.205 PACKAGING LABEL · §300.402 Ingredient the source registry supplier · lot number made · received · expires delta-9 THC reading its lab report attached every raw material traced Master record the recipe, one per product ingredients, target weights instructions, versioned printed for two signatures signed scan uploaded ⚠ on any ingredient missing a lab report Individual batch one real run of the recipe scaled; targets frozen actual weights, variance every ingredient's lab report pinned no lab report on file → the batch can't start Production run packaging a finished batch count · jar size · strain batch number · lot number a sales order per line completed batches only The label what the customer holds batch and lot number a link or QR code to the pre-sale lab report public page, no login one scan to the COA The testing lab · §300.301 round 1, pre-processing: the raw material round 2, pre-sale: the finished batch each report is a PDF on file, held three years round 1 report round 2 report every login, upload, download, and change goes into an append-only audit log

Left to right is how a product gets made. Right to left, the dashed line, is how an inspector reads it back. The batch in the middle is the hub: it knows its recipe, its ingredients' lab reports, and every run it became.

Rules the software enforces, so nobody has to remember them

What the customer sees

The rule's labeling section requires a link on the package to the product's lab report. Mark a pre-sale report public and it gets its own page at a random, unguessable address, ready to print as a link or a QR code. No login, no account, and nothing else from the portal visible.

Screenshot of a public Certificate of Analysis page: the company name, then product, test type Pre-Sale COA, batch number, lot number, lab, test date, and expiration, with a Download COA PDF button and a note that the document is retained per DSHS Chapter 300.
The page a label's QR code opens: the batch's pre-sale lab report, with the PDF one click away.

Built for more than one company

The portal was built for Elevated Trading and designed from the start to be offered to its partners and customers too. A new company registers itself through Google sign-in and becomes its own workspace, and its admin invites people as admin, manager, or viewer. Every page checks that the record belongs to the signed-in user's company. Each workspace sets its own colors and logo, and the text flips between light and dark automatically so a brand color never makes a page unreadable.

Screenshot of the TCT sign-in page. Left: the headline Compliance, built for Texas hemp, a one-line description, and three feature notes. Right: a Sign in with Google button, a link to register a new organization, and a note for invited users.
The front door. Google sign-in only, so there are no passwords to store or reset.

Where it stands

Live at its own address. The four core modules (lab reports, products, production records, ingredients) and the settings behind them are done, and complaint intake followed a week later. Recall plans and the audit reports an inspector would download are the next two phases on the plan, and neither is built yet.

The screenshots on this page come from a copy of the portal running on my own machine, filled with a made-up company, made-up suppliers and labs, and made-up orders. No customer's records appear here.

Stack

Laravel 11 PHP 8.3 MySQL Blade Google sign-in (Socialite) Gmail API Cloudways · DigitalOcean Cloudflare

Laravel instead of something newer because the hosting the company already paid for runs PHP. The right stack is the one that fits the server you have.

Built in conversation

Same method as everything on this site. The hard part wasn't the code. It was reading Chapter 300 closely enough to know that a "master production record" and a "batch production record" are two different things, that one is a recipe and the other is Tuesday's run, and that the software should keep them apart. That reading, the data model it produced, and the portal itself came out of dialogue with Claude, starting from photos of a whiteboard.

The philosophy, or what I'm building right now.