diff --git a/frontend/src/app/docs/sdks/page.tsx b/frontend/src/app/docs/sdks/page.tsx
index 6e2f00732..8b0bec2af 100644
--- a/frontend/src/app/docs/sdks/page.tsx
+++ b/frontend/src/app/docs/sdks/page.tsx
@@ -21,7 +21,7 @@ const SDKS = [
{ title: 'Python SDK', badge: 'Planned', planned: true },
{ title: 'Node.js SDK', badge: 'Planned', planned: true },
{ title: 'Go SDK', badge: 'Planned', planned: true },
- { title: 'REST Client', badge: 'Available now — OpenAPI 3.0 spec', planned: false },
+ { title: 'REST Client', badge: 'Available now (OpenAPI 3.0 spec)', planned: false },
];
const CHROME_LINK =
diff --git a/frontend/src/app/docs/walkthrough/page.tsx b/frontend/src/app/docs/walkthrough/page.tsx
index 186eeb59e..d527f77d2 100644
--- a/frontend/src/app/docs/walkthrough/page.tsx
+++ b/frontend/src/app/docs/walkthrough/page.tsx
@@ -16,10 +16,10 @@ import {
export const metadata: Metadata = {
title: 'End-to-End Walkthrough | RegEngine',
description:
- 'A 15-minute hands-on walkthrough — post a complete FSMA 204 supplier-to-shipping flow, see it on your dashboard, and produce a review-ready export.',
+ 'A 15-minute hands-on walkthrough: post a complete FSMA 204 supplier-to-shipping flow, see it on your dashboard, and produce a review-ready export.',
openGraph: {
title: 'End-to-End Walkthrough',
- description: 'A 15-minute hands-on walkthrough — post a complete FSMA 204 supplier-to-shipping flow, see it on your dashboard, and produce a review-ready export.',
+ description: 'A 15-minute hands-on walkthrough: post a complete FSMA 204 supplier-to-shipping flow, see it on your dashboard, and produce a review-ready export.',
url: 'https://regengine.co/docs/walkthrough',
type: 'website',
},
@@ -79,7 +79,7 @@ export default function WalkthroughPage() {
You receive lot {WALKTHROUGH_RECEIVED_LOT} from
- Supplier A. This is a Receiving CTE — the starting anchor for the chain.
+ Supplier A. This is a Receiving CTE, the starting anchor for the chain.
@@ -94,25 +94,25 @@ export default function WalkthroughPage() {
- 503 with "Document storage is not configured" — this endpoint doesn't
+ 503 with "Document storage is not configured" : this endpoint doesn't
need object storage; you shouldn't hit this. If you do, the 503 is from a different
path; ping support.
- 401 — the key is missing or not recognized, or{' '}
+ 401 : the key is missing or not recognized, or{' '}
X-Webhook-Signature is missing or wrong. The key header is{' '}
X-RegEngine-API-Key (not Authorization). Sign the exact bytes
you send, which is why the sample uses --data-binary.{' '}
- 403 — the key lacks the{' '}
+ 403 : the key lacks the{' '}
webhooks.ingest scope.
- 200 with status: "rejected" — read{' '}
+ 200 with status: "rejected" : read{' '}
errors on that event, for example a missing KDE. Fix it and resend with a new{' '}
Idempotency-Key.
- 422 — the whole request failed validation and nothing was stored.{' '}
+ 422 : the whole request failed validation and nothing was stored.{' '}
error.details names the field, for example a missing quantity or a timestamp more than 24 hours ahead.
@@ -121,7 +121,7 @@ export default function WalkthroughPage() {
{/* Step 2 */}
- You wash and bag the lot — that's a Transformation CTE. The input lot is the
+ You wash and bag the lot. That's a Transformation CTE. The input lot is the
Receiving lot from Step 1; the output lot is new.
@@ -184,7 +184,7 @@ head -20 lot-export.csv`}
You should see header rows mapping to FDA's 1.1455(c) requirements, with one row per
- CTE event for the lot. Production records, not legal advice — your operation remains
+ CTE event for the lot. Production records, not legal advice. Your operation remains
responsible for compliance.
diff --git a/frontend/src/app/dpa/page.tsx b/frontend/src/app/dpa/page.tsx
index b8997d845..bd4da5cf2 100644
--- a/frontend/src/app/dpa/page.tsx
+++ b/frontend/src/app/dpa/page.tsx
@@ -36,11 +36,11 @@ import {
export const metadata: Metadata = {
title: 'Data Processing Agreement | RegEngine',
description:
- 'RegEngine Data Processing Agreement — covering processor obligations, sub-processors, data subject rights, breach notification, and data deletion under GDPR and applicable law.',
+ 'RegEngine Data Processing Agreement covering processor obligations, sub-processors, data subject rights, breach notification, and data deletion under GDPR and applicable law.',
openGraph: {
title: 'Data Processing Agreement | RegEngine',
description:
- 'RegEngine DPA — data processor obligations for food safety traceability data.',
+ 'RegEngine DPA: data processor obligations for food safety traceability data.',
url: 'https://regengine.co/dpa',
type: 'website',
},
@@ -103,7 +103,7 @@ const SECURITY_MEASURES = [
{
Icon: Server,
title: 'Access Controls',
- text: 'Access to production systems requires multi-factor authentication. Production credentials are stored in secret management systems — never in source control — and rotated on a defined schedule and immediately on any suspicion of exposure.',
+ text: 'Access to production systems requires multi-factor authentication. Production credentials are stored in secret management systems (never in source control) and rotated on a defined schedule and immediately on any suspicion of exposure.',
},
{
Icon: Users,
@@ -238,8 +238,8 @@ export default function DpaPage() {
“Controller” {' '}
means the natural or legal person, public authority, agency, or other body that
- determines the purposes and means of processing personal data — in this context,
- the RegEngine customer.
+ determines the purposes and means of processing personal data (in this context,
+ the RegEngine customer).
“Processor” {' '}
diff --git a/frontend/src/app/fsma-204/page.tsx b/frontend/src/app/fsma-204/page.tsx
index eb144f70a..042db8e8a 100644
--- a/frontend/src/app/fsma-204/page.tsx
+++ b/frontend/src/app/fsma-204/page.tsx
@@ -9,11 +9,11 @@ import { Callout } from "@/components/ui/callout";
import { Card } from "@/components/ui/card";
export const metadata: Metadata = {
- title: "FSMA 204 Compliance Guide — What Your Farm Needs to Know | RegEngine",
+ title: "FSMA 204 Compliance Guide: What Your Farm Needs to Know | RegEngine",
description:
- "Plain-English guide to the FDA Food Traceability Rule. Learn what FSMA 204 requires, whether your products are covered, and how to get compliant — no developer needed.",
+ "Plain-English guide to the FDA Food Traceability Rule. Learn what FSMA 204 requires, whether your products are covered, and how to get compliant. No developer needed.",
openGraph: {
- title: 'FSMA 204 Compliance Guide — What Your Farm Needs to Know',
+ title: 'FSMA 204 Compliance Guide: What Your Farm Needs to Know',
description: 'Plain-English guide to the FDA Food Traceability Rule: what it requires, whether your products are covered, and how to comply.',
url: 'https://regengine.co/fsma-204',
type: 'article',
@@ -57,7 +57,7 @@ const CTES_PLAIN = [
name: "First Land-Based Receiving",
icon: Anchor,
who: "Receivers of seafood from a fishing vessel",
- what: "Per §1.1330: record when seafood was received from a fishing vessel, the lot code, the harvest and landing location, and the receiving facility — distinct from generic imported-food entry.",
+ what: "Per §1.1330: record when seafood was received from a fishing vessel, the lot code, the harvest and landing location, and the receiving facility. This is distinct from generic imported-food entry.",
},
{
name: "Shipping",
@@ -88,19 +88,19 @@ const STEPS = [
{
num: "2",
title: "Upload your data",
- desc: "Download our CSV or Excel template, fill in your lot codes, locations, and dates. Upload it to RegEngine. No code, no API — just a spreadsheet.",
+ desc: "Download our CSV or Excel template, fill in your lot codes, locations, and dates. Upload it to RegEngine. No code, no API, just a spreadsheet.",
cta: { label: "Download Templates", href: "/onboarding/bulk-upload" },
},
{
num: "3",
title: "RegEngine maps your events",
- desc: "We map your data to the 7 Critical Tracking Events defined in the FSMA 204 rule — harvesting, cooling, initial packing, first land-based receiving, shipping, receiving, and transformation. You only record the events that occur at your operation. The dashboard shows what’s covered and what’s missing.",
+ desc: "We map your data to the 7 Critical Tracking Events defined in the FSMA 204 rule: harvesting, cooling, initial packing, first land-based receiving, shipping, receiving, and transformation. You only record the events that occur at your operation. The dashboard shows what’s covered and what’s missing.",
cta: null,
},
{
num: "4",
title: "Be ready when they ask",
- desc: "When the FDA or a retailer requests traceability records, RegEngine produces a sortable electronic spreadsheet structured to FDA's §1.1455 format — populated from the lot codes, dates, and locations you've uploaded. Compliance remains your operation's legal responsibility.",
+ desc: "When the FDA or a retailer requests traceability records, RegEngine produces a sortable electronic spreadsheet structured to FDA's §1.1455 format, populated from the lot codes, dates, and locations you've uploaded. Compliance remains your operation's legal responsibility.",
cta: null,
},
];
@@ -118,7 +118,7 @@ const FAQS = [
},
{
q: "I don’t have a developer or IT person. Can I still use RegEngine?",
- a: "Yes. You can upload your data using our CSV or Excel templates — no code required. Download the template, fill in your lot codes and dates, and upload. RegEngine handles the rest.",
+ a: "Yes. You can upload your data using our CSV or Excel templates, with no code required. Download the template, fill in your lot codes and dates, and upload. RegEngine handles the rest.",
},
{
q: "What if I already track this in spreadsheets?",
@@ -130,7 +130,7 @@ const FAQS = [
},
{
q: "What happens if I’m not compliant by July 2028?",
- a: "FDA enforcement under §1.1455 focuses on producing the required records on request. Beyond direct enforcement, major retailers may drop non-compliant suppliers — the bigger risk for most farms is losing a key retail customer over missing traceability data.",
+ a: "FDA enforcement under §1.1455 focuses on producing the required records on request. Beyond direct enforcement, major retailers may drop non-compliant suppliers. The bigger risk for most farms is losing a key retail customer over missing traceability data.",
},
{
q: "How much does this cost?",
@@ -150,7 +150,7 @@ export default function FSMA204BusinessGuidePage() {
@@ -192,7 +192,7 @@ export default function FSMA204BusinessGuidePage() {
- The FDA's Food Safety Modernization Act Section 204 — commonly called “FSMA 204” or the “Food Traceability Rule” — requires anyone who grows, receives, ships, or transforms certain high-risk foods to keep detailed traceability records.
+ The FDA's Food Safety Modernization Act Section 204 (commonly called “FSMA 204” or the “Food Traceability Rule”) requires anyone who grows, receives, ships, or transforms certain high-risk foods to keep detailed traceability records.
The goal is simple: when a foodborne illness outbreak happens, FDA can request your traceability records and you must produce a sortable electronic spreadsheet within 24 hours . Before this rule, that process could take weeks.
@@ -204,9 +204,9 @@ export default function FSMA204BusinessGuidePage() {
{/* Enforcement callout */}
- The deadline moved — the rule didn't.
+ The deadline moved. The rule didn't.
- Congress directed FDA not to enforce before July 2028, but major retailers have published supplier traceability programs that pre-date the federal enforcement date. If you sell to a major retailer, check your supplier portal — your effective deadline may already have passed.
+ Congress directed FDA not to enforce before July 2028, but major retailers have published supplier traceability programs that pre-date the federal enforcement date. If you sell to a major retailer, check your supplier portal: your effective deadline may already have passed.
@@ -233,7 +233,7 @@ export default function FSMA204BusinessGuidePage() {
- Free FTL Checker — takes 30 seconds
+ Free FTL Checker (takes 30 seconds)
@@ -350,7 +350,7 @@ export default function FSMA204BusinessGuidePage() {
Don't wait for the deadline.
- Start with a free tool. See where you stand. Get compliant on your schedule — not the FDA's.
+ Start with a free tool. See where you stand. Get compliant on your schedule, not the FDA's.
diff --git a/frontend/src/app/integrations/opengraph-image.tsx b/frontend/src/app/integrations/opengraph-image.tsx
index a9efc0922..49bfe147e 100644
--- a/frontend/src/app/integrations/opengraph-image.tsx
+++ b/frontend/src/app/integrations/opengraph-image.tsx
@@ -1,10 +1,10 @@
import { renderOgCard, OG_SIZE, OG_CONTENT_TYPE } from '@/lib/og-image';
export const runtime = 'edge';
-export const alt = 'CSV, API, webhook, EPCIS, and SFTP supplier data intake';
+export const alt = 'CSV upload and JSON events API supplier data intake';
export const size = OG_SIZE;
export const contentType = OG_CONTENT_TYPE;
export default function Image() {
- return renderOgCard({ eyebrow: 'Integrations', title: 'CSV, API, webhook, EPCIS, and SFTP supplier data intake' });
+ return renderOgCard({ eyebrow: 'Integrations', title: 'CSV upload and JSON events API supplier data intake' });
}
diff --git a/frontend/src/app/integrations/page.tsx b/frontend/src/app/integrations/page.tsx
index 173dcdf13..f3a93bd04 100644
--- a/frontend/src/app/integrations/page.tsx
+++ b/frontend/src/app/integrations/page.tsx
@@ -29,12 +29,12 @@ import { Container } from "@/components/layout/container";
import { cn } from "@/lib/utils";
export const metadata: Metadata = {
- title: "Integrations - Supplier Data Intake | RegEngine",
+ title: "Integrations: Supplier Data Intake | RegEngine",
description:
- "RegEngine accepts supplier data via CSV, API, webhook, EPCIS, and SFTP, with custom-scoped connectors for ERP, food-safety, and retailer systems.",
+ "RegEngine accepts supplier data via CSV upload and the JSON events API, with custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS, EDI, and SFTP intake are on the roadmap.",
openGraph: {
- title: 'Integrations — Supplier Data Intake | RegEngine',
- description: 'CSV, API, webhook, EPCIS, and SFTP intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems.',
+ title: 'Integrations: Supplier Data Intake | RegEngine',
+ description: 'CSV upload and JSON events API intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS, EDI, and SFTP intake are on the roadmap.',
url: 'https://regengine.co/integrations',
type: 'website',
},
@@ -52,7 +52,7 @@ const CATEGORY_META: Record<
CapabilityCategory,
{ title: string; eyebrow: string; icon: typeof Shield }
> = {
- developer_api: { title: "Developer APIs", eyebrow: "Webhook, REST, EPCIS", icon: Code },
+ developer_api: { title: "Developer APIs", eyebrow: "REST, JSON events, EPCIS export", icon: Code },
erp_warehouse: { title: "ERP & warehouse", eyebrow: "Files, extracts, mapping", icon: FileSpreadsheet },
food_safety_iot: { title: "Food safety & IoT", eyebrow: "Audits, sensors, cold chain", icon: Thermometer },
retailer_network: { title: "Retailer exports", eyebrow: "Outbound packages", icon: ShoppingCart },
@@ -77,7 +77,7 @@ const proofStats = [
const inflowPath = [
["Simulator", "Generates FSMA 204 CTE batches"],
- ["Signed webhook", "POST /api/v1/webhooks/ingest"],
+ ["JSON events API", "POST /api/v1/webhooks/ingest"],
["Registry alias", "inflow-lab -> inflow_lab"],
["RegEngine", "Validates, stores, and tags events"],
];
@@ -119,7 +119,7 @@ export default function IntegrationsPage() {
Know which sources are ready, guided, or custom scoped.
- A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Inflow Lab is the live simulator path for webhook demos and contract CI.
+ A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Live intake today is CSV upload and the JSON events API; EPCIS, EDI, and SFTP intake are on the roadmap. Inflow Lab is the simulator path for JSON events API demos and contract CI.
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 56c7c4a5c..8d7f86d10 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -70,7 +70,7 @@ const supplierChecklistExamples = [
const evidenceCards = [
{
title: "Ingest workspace",
- description: "CTE/KDE records arrive through webhooks, CSV, EPCIS, or EDI and enter the inflow workbench for coverage checking.",
+ description: "CTE/KDE records arrive through CSV upload or the JSON events API and enter the inflow workbench for coverage checking.",
state: "needs-correction" as const,
meta: "Inflow workbench",
icon: Gauge,
@@ -92,7 +92,7 @@ const evidenceCards = [
];
const workflow = [
- { label: "Ingest", detail: "Webhooks, CSV, EPCIS, or EDI files enter the workbench.", icon: ScanLine },
+ { label: "Ingest", detail: "CSV uploads and JSON events API submissions enter the workbench.", icon: ScanLine },
{ label: "Check", detail: "CTE/KDE coverage and completeness are flagged in the inflow workbench.", icon: Database },
{ label: "Fix", detail: "Every gap gets a reason, owner, and recovery path.", icon: ClipboardCheck },
{ label: "Commit", detail: "Commit is our append-only step. After the checks you configure, accepted records enter the evidence ledger. Commit is not a certification, not an FDA gate, and not a retailer gate.", icon: ShieldCheck },
@@ -155,7 +155,7 @@ function ChecklistRadar() {
- Export checklist (advisory) — checks configured in the workspace, not FDA certification, not retailer approval.
+ Export checklist (advisory): checks configured in the workspace, not FDA certification, not retailer approval.
@@ -204,7 +204,7 @@ export default function HomePage() {
FSMA 204 recordkeeping for the Food Traceability Rule.
- Ingest supply-chain data through webhooks, CSV, EPCIS, or EDI. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
+ Ingest supply-chain data through CSV upload or the JSON events API. EPCIS, EDI, and SFTP intake are on the roadmap. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
diff --git a/frontend/src/app/pricing/page.tsx b/frontend/src/app/pricing/page.tsx
index eb55d3925..ba2adca9a 100644
--- a/frontend/src/app/pricing/page.tsx
+++ b/frontend/src/app/pricing/page.tsx
@@ -85,7 +85,7 @@ const PRICING_TIERS = [
id: 'standard',
name: 'Standard',
icon: 'rocket' as const,
- description: '2–3 facilities, scaling up',
+ description: '2 to 3 facilities, scaling up',
gaMonthly: 1299,
gaAnnual: 1099,
partnerMonthly: 649,
@@ -93,12 +93,12 @@ const PRICING_TIERS = [
highlighted: true,
cta: 'Apply for Standard',
features: [
- '2–3 facilities',
+ '2 to 3 facilities',
'No per-CTE caps (fair use)',
'Everything in Base',
'Multi-facility operations',
'Retailer-specific readiness benchmarks',
- 'FDA-oriented sortable export + EPCIS 2.0 support',
+ 'FDA-oriented sortable export + EPCIS 2.0 export',
'Priority email support',
],
},
@@ -136,13 +136,13 @@ const COMPETITOR_COMPARISON: PricingComparisonRow[] = [
];
const FAQ: PricingFaqItem[] = [
- { q: 'How do I choose between Base, Standard, and Premium?', a: 'It comes down to facility count. Base covers 1 facility with up to 500 CTEs/month. Standard handles 2–3 facilities with unlimited CTEs. Premium is for 4+ facilities with dedicated support and quarterly compliance reviews.' },
+ { q: 'How do I choose between Base, Standard, and Premium?', a: 'It comes down to facility count. Base covers 1 facility with up to 500 CTEs/month. Standard handles 2 to 3 facilities with unlimited CTEs. Premium is for 4+ facilities with dedicated support and quarterly compliance reviews.' },
{ q: 'What does the Founding rate include?', a: 'Founding rate discounts are documented in the executed order form or design-partner agreement, including term, scope, renewal, taxes, add-ons, plan-change treatment, onboarding, and integration support.' },
{ q: 'Can I switch plans anytime?', a: 'Plan changes are handled under your executed order form or design-partner agreement. We scope upgrades, downgrades, facility count, and billing changes before applying them.' },
{ q: 'Do you offer annual billing?', a: 'Annual and monthly billing can be scoped during procurement. Pricing shown is indicative; the executed agreement controls final plan, billing period, and checkout availability.' },
{ q: 'Does my Founding rate ever change?', a: 'Your Founding rate is controlled by the executed order form or design-partner agreement, including renewal, scope, add-ons, taxes, and plan changes.' },
- { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: native API, webhook, CSV/SFTP import, or custom-scoped implementation.' },
- { q: 'What if the FDA delays enforcement again?', a: 'Major retailers are already requiring traceability data from suppliers regardless of the FDA timeline. RegEngine gives you the tooling and records to support either trigger — the FDA rule or a retailer mandate.' },
+ { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: CSV upload, the JSON events API, or custom-scoped implementation. EPCIS, EDI, and SFTP intake are on the roadmap.' },
+ { q: 'What if the FDA delays enforcement again?', a: 'Major retailers are already requiring traceability data from suppliers regardless of the FDA timeline. RegEngine gives you the tooling and records to support either trigger: the FDA rule or a retailer mandate.' },
{ q: 'Do I need this if I\'m a small farm?', a: 'FSMA 204 applies to entities on the Food Traceability List handling specific foods. Use our free FTL Checker to see if your products are covered.' },
{ q: 'Can I integrate with my existing ERP?', a: 'RegEngine accepts data via API, CSV upload, or scoped ERP integration. Guided onboarding is available for approved design-partner workspaces. Timeline, support, and commercial terms are confirmed during scoping.' },
{ q: 'What happens to my data?', a: 'Data is encrypted in transit. Encryption at rest is provided by our managed database and storage providers (see the Trust Center subprocessor list). Tenant data is isolated via PostgreSQL row-level policies; tenant-trust hardening is in active rollout. We do not share or sell your data.' },
diff --git a/frontend/src/app/privacy/page.tsx b/frontend/src/app/privacy/page.tsx
index 9eb3431d3..5e91fd2a7 100644
--- a/frontend/src/app/privacy/page.tsx
+++ b/frontend/src/app/privacy/page.tsx
@@ -71,7 +71,7 @@ const collectItems = [
{
Icon: Database,
subtitle: 'Compliance Data',
- text: 'When you use RegEngine to manage FSMA 204 compliance, we process and store the traceability data you submit — including Critical Tracking Events (CTEs), Key Data Elements (KDEs), and Traceability Lot Codes (TLCs). This data belongs to you. We store it to provide the service.',
+ text: 'When you use RegEngine to manage FSMA 204 compliance, we process and store the traceability data you submit, including Critical Tracking Events (CTEs), Key Data Elements (KDEs), and Traceability Lot Codes (TLCs). This data belongs to you. We store it to provide the service.',
},
{
Icon: MonitorSmartphone,
@@ -111,7 +111,7 @@ const storageItems = [
{
Icon: Lock,
subtitle: 'Isolation',
- text: "Tenant data is scoped by PostgreSQL row-level policies and authenticated tenant context, designed and tested to restrict cross-tenant access on core PostgreSQL-backed paths. Identity-resolution and graph-layer hardening is in active rollout — see the DPA for the full subprocessor list.",
+ text: "Tenant data is scoped by PostgreSQL row-level policies and authenticated tenant context, designed and tested to restrict cross-tenant access on core PostgreSQL-backed paths. Identity-resolution and graph-layer hardening is in active rollout. See the DPA for the full subprocessor list.",
},
{
Icon: Hash,
@@ -424,8 +424,8 @@ export default function PrivacyPage() {
className={PROSE_LINK}
>
privacy@regengine.co
- {' '}
- — you'll hear from the founder directly, not a legal department.
+
+ . You'll hear from the founder directly, not a legal department.
@@ -437,7 +437,7 @@ export default function PrivacyPage() {
- Your data belongs to you — always
+ Your data belongs to you, always
Become a Founding Design Partner to review the current tenant-isolation posture and
diff --git a/frontend/src/app/proof/page.tsx b/frontend/src/app/proof/page.tsx
index 6837687a5..63e5bfbbf 100644
--- a/frontend/src/app/proof/page.tsx
+++ b/frontend/src/app/proof/page.tsx
@@ -10,7 +10,7 @@ import { Card, CardHeader } from "@/components/ui/card";
export const metadata: Metadata = {
title: "Proof | RegEngine",
description:
- "Download three verifiable sample artifacts generated by production code — FSMA 204 sortable spreadsheet, EPCIS 2.0 JSON-LD export, and a Merkle-rooted audit bundle — without signing up.",
+ "Download three verifiable sample artifacts generated by production code (FSMA 204 sortable spreadsheet, EPCIS 2.0 JSON-LD export, and a Merkle-rooted audit bundle) without signing up.",
openGraph: {
title: "Verify RegEngine without signing up",
description:
@@ -102,7 +102,7 @@ export default function ProofPage() {
size="hero"
eyebrow={Proof }
title="Verify RegEngine without signing up."
- description="Three artifacts. No email gate, no demo call. Download the files, open them in your tools, and check the hashes yourself. If the output does not match the claim, the product fails — and you have the receipts."
+ description="Three artifacts. No email gate, no demo call. Download the files, open them in your tools, and check the hashes yourself. If the output does not match the claim, the product fails, and you have the receipts."
className="mb-0 border-b-0 pb-0"
/>
@@ -222,15 +222,15 @@ export default function ProofPage() {
Changelog}>
- 2026-05-09 — verifier mismatch found and fixed
+ 2026-05-09: verifier mismatch found and fixed
- A reader running the recipe on this page got an argparse error instead of a verification. The verifier we'd shipped didn't match the bundle we'd shipped — the hashes were correct, but the script next to them read JSON, not the zip the page describes.
+ A reader running the recipe on this page got an argparse error instead of a verification. The verifier we'd shipped didn't match the bundle we'd shipped. The hashes were correct, but the script next to them read JSON, not the zip the page describes.
Replaced with a verifier that opens the zip, recomputes every per-file SHA-256, and rebuilds the Merkle root using the same algorithm RegEngine ships in services/shared/merkle_tree.py. Added the EPCIS payload to manifest.json, added a build block (commit, generated_at, release), and published audit-bundle-tampered.zip so anyone can watch the new verifier fail closed.
- If you found the original bug before we did — thank you. That's the system working.
+ If you found the original bug before we did, thank you. That's the system working.
diff --git a/frontend/src/app/proof/transformation/page.tsx b/frontend/src/app/proof/transformation/page.tsx
index f2b58580c..5d75c480e 100644
--- a/frontend/src/app/proof/transformation/page.tsx
+++ b/frontend/src/app/proof/transformation/page.tsx
@@ -81,7 +81,7 @@ const STEPS: Step[] = [
"chain_hash": "f0a2b5c8d1e4f7a0b3c6d9e2f5a8b1c4d7e0f3a6b9c2d5e8f1a4b7c0d3e6f9a2"
}`,
canonicalAnnotation:
- "KDE validation against §1.1330 (a)(1)–(7). Hash chained to previous event.",
+ "KDE validation against §1.1330 (a)(1) through (a)(7). Hash chained to previous event.",
fdaRow: [
["Traceability Lot Code (TLC)", "LOT-ROM-2026-0312A"],
["Product Description", "Organic Romaine Hearts"],
@@ -175,7 +175,7 @@ const STEPS: Step[] = [
cte: "§1.1340",
title: "Shipping",
subtitle:
- "Transfer event. Adds Ship-From / Ship-To facilities with GLN identifiers — the FDA's expected join keys.",
+ "Transfer event. Adds Ship-From / Ship-To facilities with GLN identifiers, the FDA's expected join keys.",
csvHeader:
"traceability_lot_code,product_description,quantity,unit_of_measure,ship_date,ship_from_location,ship_to_location,ship_from_gln,ship_to_gln,carrier_name,po_number,reference_document",
csvRows: [
diff --git a/frontend/src/app/supplier-compliance/page.tsx b/frontend/src/app/supplier-compliance/page.tsx
index 6b99c78a8..6d9af9f93 100644
--- a/frontend/src/app/supplier-compliance/page.tsx
+++ b/frontend/src/app/supplier-compliance/page.tsx
@@ -11,7 +11,7 @@ import { Container } from '@/components/layout/container';
export const metadata: Metadata = {
title: 'Your Buyer Asked About FSMA 204 Traceability | RegEngine',
- description: 'Major retailers are increasingly asking suppliers for FSMA 204 traceability data. Start submitting in minutes — full FSMA 204 program coverage takes longer. No rip-and-replace required.',
+ description: 'Major retailers are increasingly asking suppliers for FSMA 204 traceability data. Start submitting in minutes; full FSMA 204 program coverage takes longer. No rip-and-replace required.',
openGraph: {
title: 'Your Buyer Asked About FSMA 204 Traceability | RegEngine',
description: 'Major retailers are asking suppliers for traceability data. Start submitting in minutes with RegEngine.',
@@ -48,7 +48,7 @@ const COMPLIANCE_STEPS = [
// retailer contracting terms. If a buyer mandate is publicly cited, link
// to the source rather than asserting it here.
const RETAILERS_ENFORCING = [
- { name: 'Major retailers', detail: 'Multiple top-10 grocers have publicly signaled supplier traceability expectations ahead of the 2028 deadline. Specific requirements vary by buyer — confirm directly with your buyer.' },
+ { name: 'Major retailers', detail: 'Multiple top-10 grocers have publicly signaled supplier traceability expectations ahead of the 2028 deadline. Specific requirements vary by buyer, so confirm directly with your buyer.' },
];
const FAQ = [
@@ -183,7 +183,7 @@ export default function SupplierCompliancePage() {
{
icon: FileCheck,
title: 'Who it applies to',
- body: 'Any business that manufactures, processes, packs, or holds foods on the Food Traceability List (FTL) — including fresh produce, seafood, dairy, eggs, deli salads, nut butters, and more. This includes domestic and foreign suppliers.',
+ body: 'Any business that manufactures, processes, packs, or holds foods on the Food Traceability List (FTL), including fresh produce, seafood, dairy, eggs, deli salads, nut butters, and more. This includes domestic and foreign suppliers.',
},
{
icon: Truck,
@@ -224,7 +224,7 @@ export default function SupplierCompliancePage() {
Need your suppliers to submit traceability data?
- Generate portal links from your RegEngine dashboard and share them with suppliers. They submit data directly — no account needed, no training required. Data flows into your workspace automatically.
+ Generate portal links from your RegEngine dashboard and share them with suppliers. They submit data directly, with no account needed and no training required. Data flows into your workspace automatically.
diff --git a/frontend/src/app/terms/TermsClient.tsx b/frontend/src/app/terms/TermsClient.tsx
index 987d44927..b945eb3da 100644
--- a/frontend/src/app/terms/TermsClient.tsx
+++ b/frontend/src/app/terms/TermsClient.tsx
@@ -14,7 +14,7 @@ const sections = [
Features may change without notice, and we may suspend or modify access during staged rollouts, maintenance windows, or broader service updates.
-We are a software tool. We are not a law firm, compliance consultancy, or government agency. Our tools help you organize and manage compliance data — they do not constitute legal advice or promise regulatory compliance. You are responsible for your own compliance decisions.`,
+We are a software tool. We are not a law firm, compliance consultancy, or government agency. Our tools help you organize and manage compliance data. They do not constitute legal advice or promise regulatory compliance. You are responsible for your own compliance decisions.`,
},
{
id: 'accounts',
@@ -53,7 +53,7 @@ Free tools may be modified, updated, or discontinued at any time.`,
title: '5. Paid Services',
content: `Unless otherwise stated in a signed order form or customer agreement, paid plans are billed monthly or annually as selected. Prices are listed on our pricing page and may change with reasonable advance notice.
-You can upgrade at any time (prorated). You can downgrade at the end of your current billing cycle. You can cancel at any time — no cancellation fees.
+You can upgrade at any time (prorated). You can downgrade at the end of your current billing cycle. You can cancel at any time, with no cancellation fees.
Unless your signed order form or customer agreement states otherwise, if you exceed your CTE limit, we charge $0.002 per additional CTE. We will notify you by email before any overage charges are applied.
diff --git a/frontend/src/app/trust/architecture/page.tsx b/frontend/src/app/trust/architecture/page.tsx
index ec7d43a18..fc1f6e855 100644
--- a/frontend/src/app/trust/architecture/page.tsx
+++ b/frontend/src/app/trust/architecture/page.tsx
@@ -47,7 +47,7 @@ const STACK_LAYERS = [
layer: 'Backend',
technology: 'FastAPI monolith on Railway',
detail:
- 'Single consolidated Python service for CTE ingestion, webhook validation, CSV parsing, compliance coverage and completeness checking, exports, and alert generation. The services directories are code-organization boundaries, not separate default deploys.',
+ 'Single consolidated Python service for CTE ingestion, JSON events API validation, CSV parsing, compliance coverage and completeness checking, exports, and alert generation. The services directories are code-organization boundaries, not separate default deploys.',
},
{
Icon: Database,
@@ -69,7 +69,7 @@ const DATA_FLOW_STEPS = [
{
step: '1',
title: 'Ingest',
- description: 'CTE events arrive via CSV upload, webhook, or EPCIS. CSV and webhook paths run validation synchronously; EPCIS validation runs asynchronously. All paths persist before coverage checks.',
+ description: 'CTE events arrive via CSV upload or the JSON events API. Both paths run validation synchronously and persist before coverage checks. EPCIS, EDI, and SFTP intake are on the roadmap.',
},
{
step: '2',
@@ -79,7 +79,7 @@ const DATA_FLOW_STEPS = [
{
step: '3',
title: 'Hash & Chain',
- description: 'Validated events are SHA-256 hashed and chain-linked at ingest, scoped per tenant. Commit means accepted records are appended after checks you configure — not a certification. Independent verification of exported bundles is offered at /verify. Default deployments use PostgreSQL-backed task processing rather than a managed message bus.',
+ description: 'Validated events are SHA-256 hashed and chain-linked at ingest, scoped per tenant. Commit means accepted records are appended after checks you configure; this is not a certification. Independent verification of exported bundles is offered at /verify. Default deployments use PostgreSQL-backed task processing rather than a managed message bus.',
},
{
step: '4',
@@ -120,7 +120,7 @@ const SYSTEM_FLOW = [
{
Icon: Globe,
title: 'Source systems',
- detail: 'ERP, WMS, supplier files, webhooks, or EPCIS feeds',
+ detail: 'ERP, WMS, and supplier data sent as CSV uploads or JSON events API calls',
boundary: 'Customer-owned data quality',
},
{
diff --git a/frontend/src/app/trust/page.tsx b/frontend/src/app/trust/page.tsx
index 8f95f6880..bf240fca6 100644
--- a/frontend/src/app/trust/page.tsx
+++ b/frontend/src/app/trust/page.tsx
@@ -63,7 +63,7 @@ const STATUS_SUMMARY = [
},
{
label: 'File Import Supported',
- detail: 'Customer data can be onboarded through CSV or SFTP with mapping review and exception handling.',
+ detail: 'Customer data can be onboarded through CSV upload with mapping review and exception handling. SFTP delivery is on the roadmap.',
},
{
label: 'Custom Scoped',
@@ -250,7 +250,7 @@ export default function TrustCenterPage() {
diff --git a/frontend/src/app/trust/retention/page.tsx b/frontend/src/app/trust/retention/page.tsx
index d428160c6..298d1a22c 100644
--- a/frontend/src/app/trust/retention/page.tsx
+++ b/frontend/src/app/trust/retention/page.tsx
@@ -217,7 +217,7 @@ export default function RetentionPage() {
Our recommendation
Set up weekly automated exports to your own object storage within the first week of onboarding.
- Use the audit evidence bundle format — it ships with a SHA-256 manifest so records can be verified out-of-band. Default deployments use PostgreSQL-backed task processing rather than a managed message bus.
+ Use the audit evidence bundle format. It ships with a SHA-256 manifest so records can be verified out-of-band. Default deployments use PostgreSQL-backed task processing rather than a managed message bus.
This supports FSMA 204's two-year retention requirement regardless of your RegEngine subscription status.
diff --git a/frontend/src/app/trust/support/page.tsx b/frontend/src/app/trust/support/page.tsx
index 34881be47..0c8b31f31 100644
--- a/frontend/src/app/trust/support/page.tsx
+++ b/frontend/src/app/trust/support/page.tsx
@@ -47,7 +47,7 @@ const ESCALATION_PATH = [
{
step: '3',
title: 'Priority queue',
- description: 'Faster response for production issues affecting compliance workflows — ingestion failures, scoring errors, export failures, or integration breakages.',
+ description: 'Faster response for production issues affecting compliance workflows, such as ingestion failures, scoring errors, export failures, or integration breakages.',
icon: Zap,
availability: 'Standard and Premium',
},
@@ -159,7 +159,7 @@ export default function SupportPage() {
What RegEngine does during a recall
diff --git a/frontend/src/app/walkthrough/page.tsx b/frontend/src/app/walkthrough/page.tsx
index 9383f7d00..88e484afb 100644
--- a/frontend/src/app/walkthrough/page.tsx
+++ b/frontend/src/app/walkthrough/page.tsx
@@ -56,7 +56,7 @@ const TIMELINE = [
color: 'red',
defects: [
{ lot: 'R-2026-0312', issue: 'Missing required KDE: cooling_date', severity: 'critical' },
- { lot: 'R-2026-0312', issue: 'Identity conflict: "Valley Fresh Farms LLC" vs "Valley Fresh" — >=85% match, unresolved', severity: 'critical' },
+ { lot: 'R-2026-0312', issue: 'Identity conflict: "Valley Fresh Farms LLC" vs "Valley Fresh" (>=85% match, unresolved)', severity: 'critical' },
{ lot: 'R-2026-0314', issue: 'Invalid unit_of_measure: "bushels" not in FSMA standard units', severity: 'critical' },
],
},
@@ -65,7 +65,7 @@ const TIMELINE = [
title: 'Exception cases created',
icon: AlertTriangle,
description: 'Each blocking defect becomes an Exception Case with severity, owner assignment, and remediation guidance. The operator sees exactly what needs fixing and why.',
- detail: 'Exception cases track resolution status, signoffs, and waiver history. Nothing gets swept under the rug — every decision is recorded in the audit trail.',
+ detail: 'Exception cases track resolution status, signoffs, and waiver history. Nothing gets swept under the rug: every decision is recorded in the audit trail.',
color: 'amber',
},
{
@@ -78,7 +78,7 @@ const TIMELINE = [
},
{
time: 'T+1:30',
- title: 'All defects resolved — submission unblocked',
+ title: 'All defects resolved, submission unblocked',
icon: Shield,
description: 'The blocking defect check runs again: 0 blocking defects remain. The package can now be assembled.',
detail: 'RegEngine checks 7 blocker categories: critical rule failures, unresolved exceptions, unevaluated events, missing signoffs, identity ambiguity, stale evaluations, and deadline monitoring.',
@@ -126,7 +126,7 @@ export default function WalkthroughPage() {
Here's how you respond in 2.
>
}
- description="A step-by-step walkthrough of an illustrative FDA records-request scenario — from messy supplier data to a hash-manifested response package anyone can re-check."
+ description="A step-by-step walkthrough of an illustrative FDA records-request scenario, from messy supplier data to a hash-manifested response package anyone can re-check."
className="border-b-0 pb-0"
/>
@@ -222,7 +222,7 @@ export default function WalkthroughPage() {
You cannot submit if:
- RegEngine surfaces these checks at package assembly time. Rule enforcement is configurable per workflow — in production today, rule failures are recorded as exceptions and surfaced in the dashboard rather than blocking ingest.
+ RegEngine surfaces these checks at package assembly time. Rule enforcement is configurable per workflow. In production today, rule failures are recorded as exceptions and surfaced in the dashboard rather than blocking ingest.
{[
diff --git a/frontend/src/app/why-regengine/page.tsx b/frontend/src/app/why-regengine/page.tsx
index b7cff09ea..157ae2363 100644
--- a/frontend/src/app/why-regengine/page.tsx
+++ b/frontend/src/app/why-regengine/page.tsx
@@ -146,7 +146,7 @@ const DIFFERENTIATORS = [
icon: Zap,
title: 'Self-serve, days not months',
description:
- 'Get from signup to a first FSMA 204 export in days. CSV upload or API payload → validation → export. No 3–6 month enterprise implementation.',
+ 'Get from signup to a first FSMA 204 export in days. CSV upload or API payload → validation → export. No 3 to 6 month enterprise implementation.',
detail: 'Major retailers and FDA enforcement deadlines arrive on calendar dates; teams ship sooner when the platform is self-serve.',
},
{
@@ -444,7 +444,7 @@ HTTP 201
Standard Plan
$549/mo $1,099/mo
- Founding rate, billed annually ($649/mo monthly) • 2–3 facilities • Unlimited CTEs
+ Founding rate, billed annually ($649/mo monthly) • 2 to 3 facilities • Unlimited CTEs
Premium Plan
@@ -465,7 +465,7 @@ HTTP 201
{[
- 'Simple design-partner agreements — no multi-year lock-in',
+ 'Simple design-partner agreements with no multi-year lock-in',
'API access for contracted workspaces',
'Founding Design Partner rate never increases',
].map((item, idx) => (
@@ -633,7 +633,7 @@ HTTP 201
RegEngine is built for companies like:
{[
- 'Regional produce distributors ($5M–$50M annual revenue)',
+ 'Regional produce distributors ($5M to $50M annual revenue)',
'Specialty food brands and co-packers',
'Organic/specialty retailers and wholesalers',
'Small farms and grower cooperatives',
@@ -700,7 +700,7 @@ HTTP 201
},
{
title: 'We do NOT lock you in',
- detail: 'Simple design-partner agreements — no multi-year lock-in. Export all your data anytime. Your data is yours.',
+ detail: 'Simple design-partner agreements with no multi-year lock-in. Export all your data anytime. Your data is yours.',
},
].map((item, idx) => (
@@ -767,7 +767,7 @@ HTTP 201
Ready to Get Compliant?
- Request access in minutes. Start with the onboarding path that fits your team. Simple design-partner agreements — no multi-year lock-in.
+ Request access in minutes. Start with the onboarding path that fits your team. Simple design-partner agreements with no multi-year lock-in.
diff --git a/frontend/src/components/control-plane/demo-banner.tsx b/frontend/src/components/control-plane/demo-banner.tsx
index 5551d535d..42cca6b3a 100644
--- a/frontend/src/components/control-plane/demo-banner.tsx
+++ b/frontend/src/components/control-plane/demo-banner.tsx
@@ -7,7 +7,7 @@ export function DemoBanner({ visible }: { visible: boolean }) {
return (
- Sample Data — Backend unavailable.
+ Sample Data : Backend unavailable.
Data will appear once services are connected.
diff --git a/frontend/src/lib/customer-readiness.ts b/frontend/src/lib/customer-readiness.ts
index d04f75b5e..645cf7aa4 100644
--- a/frontend/src/lib/customer-readiness.ts
+++ b/frontend/src/lib/customer-readiness.ts
@@ -37,7 +37,7 @@ export const INTEGRATION_TYPE_LABELS: Record = {
export const INTEGRATION_TYPE_DESCRIPTIONS: Record = {
standards_based: 'Standards-oriented ingest and export support without a claim of managed two-way sync or source-system write-back.',
api_based_custom: 'Customer-managed integration via RegEngine API and implementation guidance. The customer builds and maintains the workflow unless otherwise scoped.',
- file_based_import: 'Scheduled or manual CSV/XLSX ingestion with field mapping and exception handling.',
+ file_based_import: 'Manual CSV/XLSX upload with field mapping and exception handling. Scheduled file delivery is on the roadmap.',
one_way_export: 'RegEngine prepares outbound packages. No write-back to source system.',
};
@@ -132,7 +132,7 @@ export const STATUS_LABELS: Record = {
export const DELIVERY_MODE_LABELS: Record = {
native_api: 'Native API',
webhook: 'Webhook',
- csv_sftp_import: 'CSV / SFTP Import',
+ csv_sftp_import: 'CSV Import',
export_only: 'Export Only',
custom_scoped: 'Custom Scoped',
};
@@ -190,12 +190,12 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
},
{
id: 'csv-sftp',
- name: 'CSV / SFTP Import',
+ name: 'CSV Import',
category: 'erp_warehouse',
status: 'file_import_supported',
delivery_mode: 'csv_sftp_import',
integration_type: 'file_based_import',
- customer_copy: 'Use CSV or scheduled file delivery for ERP and warehouse data that is not available over API.',
+ customer_copy: 'Upload CSV files for ERP and warehouse data that is not available over API. Scheduled SFTP delivery is on the roadmap.',
evidence_url: '/tools/data-import',
},
{
@@ -215,7 +215,7 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
status: 'custom_scoped',
delivery_mode: 'csv_sftp_import',
integration_type: 'file_based_import',
- customer_copy: 'NetSuite data can be onboarded via CSV or SFTP export with RegEngine mapping review.',
+ customer_copy: 'NetSuite data can be onboarded via CSV export with RegEngine mapping review.',
evidence_url: '/trust',
},
{
@@ -290,12 +290,12 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
},
{
id: 'webhooks',
- name: 'Webhook ingestion (inbound)',
+ name: 'JSON events API (inbound)',
category: 'developer_api',
status: 'implemented',
- delivery_mode: 'webhook',
+ delivery_mode: 'native_api',
integration_type: 'api_based_custom',
- customer_copy: 'Webhook ingestion is available for inbound event submission and downstream normalization (one-way inbound).',
+ customer_copy: 'Submit CTE events as JSON to POST /api/v1/webhooks/ingest for validation and downstream normalization (one-way inbound).',
evidence_url: '/docs/api',
},
{
@@ -303,29 +303,29 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
name: 'Inflow Lab',
category: 'developer_api',
status: 'pilot',
- delivery_mode: 'webhook',
+ delivery_mode: 'native_api',
integration_type: 'api_based_custom',
- customer_copy: 'RegEngine-owned FSMA 204 simulator for webhook demos, contract tests, and developer validation.',
+ customer_copy: 'RegEngine-owned FSMA 204 simulator that posts events to the JSON events API for demos, contract tests, and developer validation.',
evidence_url: '/docs/connectors/inflow-lab',
},
{
id: 'epcis',
name: 'GS1 EPCIS 2.0',
category: 'developer_api',
- status: 'implemented',
- delivery_mode: 'native_api',
- integration_type: 'standards_based',
- customer_copy: 'JSON-LD EPCIS ingest and export are supported. Default deployments use PostgreSQL-backed task processing; legacy Kafka-compatible signing is opt-in.',
+ status: 'export_supported',
+ delivery_mode: 'export_only',
+ integration_type: 'one_way_export',
+ customer_copy: 'JSON-LD EPCIS export is supported. EPCIS ingest is on the roadmap. Default deployments use PostgreSQL-backed task processing; legacy Kafka-compatible signing is opt-in.',
evidence_url: '/developers',
},
{
id: 'edi-856',
name: 'EDI 856',
category: 'developer_api',
- status: 'pilot',
+ status: 'preparation',
delivery_mode: 'custom_scoped',
integration_type: 'file_based_import',
- customer_copy: 'ASN inbound processing exists, but production rollout should be treated as guided integration work.',
+ customer_copy: 'EDI 856 (ASN) inbound processing is on the roadmap. It is not available as a live intake channel.',
evidence_url: '/trust',
},
{
@@ -402,7 +402,7 @@ export const SUPPORT_CHANNELS: SupportChannel[] = [
tier: 'Premium',
responseWindow: 'Per contract',
escalation: 'Named contacts, negotiated escalation tree, and security review support',
- notes: 'All commitments — response time, named escalations, security obligations — live in the executed agreement.',
+ notes: 'All commitments (response time, named escalations, security obligations) live in the executed agreement.',
},
];
@@ -415,7 +415,7 @@ export const SUPPORT_CHANNELS: SupportChannel[] = [
export const ARCHIVE_EXPORT_JOBS: ArchiveExportJob[] = [
{
id: 'job_fda_daily',
- name: 'Sample — Daily FDA package archive',
+ name: 'Sample: Daily FDA package archive',
format: 'FDA Package',
cadence: 'Daily',
destination: 'Object storage archive',
@@ -427,7 +427,7 @@ export const ARCHIVE_EXPORT_JOBS: ArchiveExportJob[] = [
},
{
id: 'job_epcis_weekly',
- name: 'Sample — Weekly EPCIS outbound bundle',
+ name: 'Sample: Weekly EPCIS outbound bundle',
format: 'GS1 EPCIS 2.0',
cadence: 'Weekly',
destination: 'Downloadable bundle',
@@ -439,7 +439,7 @@ export const ARCHIVE_EXPORT_JOBS: ArchiveExportJob[] = [
},
{
id: 'job_audit_monthly',
- name: 'Sample — Monthly audit evidence bundle',
+ name: 'Sample: Monthly audit evidence bundle',
format: 'Audit Bundle',
cadence: 'Monthly',
destination: 'Object storage archive',
From bf15a06a3853a8b731569750996e30bea5f94947 Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:21:00 -0700
Subject: [PATCH 2/8] docs(frontend): drop remaining live-channel claims and
dashes from public copy
Signed-off-by: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
---
frontend/src/app/about/page.tsx | 10 +--
.../app/accept-invite/AcceptInviteClient.tsx | 4 +-
frontend/src/app/api/admin/[...path]/route.ts | 2 +-
.../src/app/api/compliance/[...path]/route.ts | 2 +-
.../src/app/api/controls/[...path]/route.ts | 2 +-
frontend/src/app/api/fsma/[...path]/route.ts | 4 +-
frontend/src/app/api/graph/[...path]/route.ts | 2 +-
.../src/app/api/ingestion/[...path]/route.ts | 2 +-
.../src/app/api/review/[...path]/route.ts | 2 +-
frontend/src/app/api/tools/verify/route.ts | 4 +-
.../[tenantId]/[snapshotId]/attest/route.ts | 6 +-
.../[snapshotId]/audit-pack/route.ts | 4 +-
.../[tenantId]/[snapshotId]/export/route.ts | 4 +-
.../[snapshotId]/fda-response/route.ts | 4 +-
.../[tenantId]/[snapshotId]/refreeze/route.ts | 4 +-
.../[tenantId]/[snapshotId]/verify/route.ts | 4 +-
.../snapshots/[tenantId]/diff/route.ts | 4 +-
.../compliance/snapshots/[tenantId]/route.ts | 6 +-
.../v1/compliance/status/[tenantId]/route.ts | 4 +-
frontend/src/app/audit/page.tsx | 2 +-
frontend/src/app/auth/verify/page.tsx | 2 +-
frontend/src/app/buyer-programs/page.tsx | 4 +-
frontend/src/app/compare/foodlogiq/page.tsx | 2 +-
frontend/src/app/compare/repositrak/page.tsx | 6 +-
frontend/src/app/compare/tracegains/page.tsx | 8 +--
frontend/src/app/compliance/page.tsx | 2 +-
frontend/src/app/compliance/profile/page.tsx | 2 +-
.../app/compliance/traceability-plan/page.tsx | 2 +-
frontend/src/app/dashboard/alerts/page.tsx | 4 +-
.../src/app/dashboard/compliance/page.tsx | 6 +-
.../src/app/dashboard/export-jobs/page.tsx | 4 +-
frontend/src/app/dashboard/heartbeat/page.tsx | 2 +-
.../src/app/dashboard/inflow-lab/page.tsx | 2 +-
frontend/src/app/dashboard/issues/page.tsx | 8 +--
frontend/src/app/dashboard/layout.tsx | 2 +-
.../src/app/dashboard/notifications/page.tsx | 2 +-
frontend/src/app/dashboard/page.tsx | 2 +-
frontend/src/app/dashboard/products/page.tsx | 12 ++--
.../src/app/dashboard/recall-drills/page.tsx | 2 +-
.../src/app/dashboard/recall-report/page.tsx | 8 +--
frontend/src/app/dashboard/receiving/page.tsx | 4 +-
frontend/src/app/dashboard/scan/page.tsx | 6 +-
frontend/src/app/dashboard/settings/page.tsx | 2 +-
frontend/src/app/demo/page.tsx | 2 +-
frontend/src/app/design-system/page.tsx | 2 +-
.../developers/compliance-verticals/page.tsx | 2 +-
frontend/src/app/developers/page.tsx | 14 ++---
frontend/src/app/docs/authentication/page.tsx | 4 +-
frontend/src/app/docs/walkthrough/page.tsx | 2 +-
frontend/src/app/exceptions/page.tsx | 2 +-
frontend/src/app/fsma-204/[cte]/page.tsx | 62 +++++++++----------
frontend/src/app/fsma-204/page.tsx | 2 +-
frontend/src/app/fsma/integration/page.tsx | 4 +-
frontend/src/app/fsma/layout.tsx | 2 +-
frontend/src/app/identity/page.tsx | 2 +-
.../results/[id]/AnalysisResultClient.tsx | 2 +-
frontend/src/app/login/layout.tsx | 2 +-
.../src/app/onboarding/bulk-upload/page.tsx | 2 +-
.../app/onboarding/setup/facility/page.tsx | 6 +-
.../app/onboarding/setup/ftl-check/page.tsx | 2 +-
.../src/app/onboarding/setup/welcome/page.tsx | 4 +-
frontend/src/app/portal/[portalId]/page.tsx | 4 +-
frontend/src/app/privacy/page.tsx | 3 +-
frontend/src/app/proof/recall-drill/page.tsx | 14 ++---
frontend/src/app/remediation/page.tsx | 16 ++---
frontend/src/app/requests/[id]/page.tsx | 2 +-
frontend/src/app/requests/page.tsx | 2 +-
.../src/app/retailer-readiness/layout.tsx | 4 +-
frontend/src/app/rules/page.tsx | 2 +-
frontend/src/app/sandbox/SandboxClient.tsx | 8 +--
frontend/src/app/sandbox/page.tsx | 6 +-
frontend/src/app/settings/profile/page.tsx | 2 +-
frontend/src/app/settings/security/page.tsx | 2 +-
frontend/src/app/trace/page.tsx | 2 +-
frontend/src/app/verify/page.tsx | 16 ++---
frontend/src/app/why-regengine/page.tsx | 12 ++--
.../dashboard/metrics-overview-widget.tsx | 2 +-
frontend/src/components/fsma-checklist.tsx | 4 +-
.../components/fsma/readiness-assessment.tsx | 10 +--
.../sandbox-grid/SandboxPdfReport.ts | 4 +-
.../sandbox-grid/SandboxResultView.tsx | 4 +-
.../src/components/mobile/BarcodeScanner.tsx | 2 +-
.../components/mobile/FieldCaptureClient.tsx | 4 +-
frontend/src/components/ui/data-table.tsx | 2 +-
frontend/src/lib/api-config.ts | 2 +-
frontend/src/lib/api-proxy.ts | 12 ++--
frontend/src/lib/auth-context.tsx | 2 +-
frontend/src/lib/csrf.ts | 4 +-
frontend/src/lib/customer-readiness.ts | 2 +-
frontend/src/lib/fsma-enforcement.ts | 2 +-
frontend/src/lib/ftl-data.ts | 6 +-
frontend/src/lib/proxy-factory.ts | 14 ++---
frontend/src/lib/roi-calculator-data.ts | 2 +-
93 files changed, 230 insertions(+), 231 deletions(-)
diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx
index 94c23dce0..f6cbf25ed 100644
--- a/frontend/src/app/about/page.tsx
+++ b/frontend/src/app/about/page.tsx
@@ -103,7 +103,7 @@ export default function AboutPage() {
description={
<>
RegEngine is FSMA 204 compliance infrastructure built for mid-market
- food companies—by someone who saw the gap from inside government,
+ food companies, by someone who saw the gap from inside government,
enterprise sales, and the regulatory stack itself.
>
}
@@ -135,8 +135,8 @@ export default function AboutPage() {
204 compliance tools priced for enterprises, sold through
six-month procurement cycles, and designed for teams with
dedicated compliance departments. The companies that actually
- needed help—regional distributors, mid-size processors,
- growing food brands—were stuck choosing between
+ needed help (regional distributors, mid-size processors,
+ growing food brands) were stuck choosing between
spreadsheets and software they couldn't afford.
@@ -186,7 +186,7 @@ export default function AboutPage() {
RegEngine is built by one person leveraging modern AI tooling as
- a development multiplier. This isn't a limitation—it's
+ a development multiplier. This isn't a limitation; it's
a feature.
@@ -258,7 +258,7 @@ export default function AboutPage() {
Book a free gap analysis call. We'll review your current FSMA 204
posture, identify coverage gaps, and show you exactly what RegEngine
- handles—no commitment required.
+ handles. No commitment required.
diff --git a/frontend/src/app/accept-invite/AcceptInviteClient.tsx b/frontend/src/app/accept-invite/AcceptInviteClient.tsx
index 2798e250c..dfdf67cce 100644
--- a/frontend/src/app/accept-invite/AcceptInviteClient.tsx
+++ b/frontend/src/app/accept-invite/AcceptInviteClient.tsx
@@ -111,12 +111,12 @@ export default function AcceptInvitePage() {
return (
Your account is ready. We'll email you a sign-in code when you
- log in — no password needed.
+ log in. No password needed.
{
const url = process.env.ADMIN_SERVICE_URL || getServerServiceURL('admin');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/controls] ADMIN_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/controls] ADMIN_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('admin');
}
return url;
diff --git a/frontend/src/app/api/fsma/[...path]/route.ts b/frontend/src/app/api/fsma/[...path]/route.ts
index 69ef44d13..cd1cab4c5 100644
--- a/frontend/src/app/api/fsma/[...path]/route.ts
+++ b/frontend/src/app/api/fsma/[...path]/route.ts
@@ -46,13 +46,13 @@ function guardUrl(envVar: string, fallback: string): string {
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (url) {
if (onVercel && url.includes('.railway.internal')) {
- console.warn(`[proxy/fsma] ${envVar} points to internal Railway URL — unreachable from Vercel.`);
+ console.warn(`[proxy/fsma] ${envVar} points to internal Railway URL; unreachable from Vercel.`);
return '';
}
return url;
}
if (onVercel) {
- console.error(`[proxy/fsma] ${envVar} not configured — localhost is unreachable from Vercel`);
+ console.error(`[proxy/fsma] ${envVar} not configured; localhost is unreachable from Vercel`);
return '';
}
return fallback;
diff --git a/frontend/src/app/api/graph/[...path]/route.ts b/frontend/src/app/api/graph/[...path]/route.ts
index 464a4b0c4..db85f9417 100644
--- a/frontend/src/app/api/graph/[...path]/route.ts
+++ b/frontend/src/app/api/graph/[...path]/route.ts
@@ -16,7 +16,7 @@ function getGraphUrl(): string {
// Guard: *.railway.internal URLs are unreachable from Vercel serverless
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/graph] GRAPH_SERVICE_URL points to internal Railway URL — unreachable from Vercel. Set a public Railway URL.');
+ console.warn('[proxy/graph] GRAPH_SERVICE_URL points to internal Railway URL; unreachable from Vercel. Set a public Railway URL.');
return getServerServiceURL('graph');
}
return url;
diff --git a/frontend/src/app/api/ingestion/[...path]/route.ts b/frontend/src/app/api/ingestion/[...path]/route.ts
index d09b6ffac..3bf8c5375 100644
--- a/frontend/src/app/api/ingestion/[...path]/route.ts
+++ b/frontend/src/app/api/ingestion/[...path]/route.ts
@@ -40,7 +40,7 @@ function getIngestionTargets(): string[] {
candidates.push(productionUrl);
} else if (runningOnVercel) {
console.error(
- '[proxy/ingestion] No ingestion backend URL configured — set NEXT_PUBLIC_INGESTION_URL, INGESTION_SERVICE_URL, or INGESTION_PRODUCTION_URL',
+ '[proxy/ingestion] No ingestion backend URL configured; set NEXT_PUBLIC_INGESTION_URL, INGESTION_SERVICE_URL, or INGESTION_PRODUCTION_URL',
);
} else {
candidates.push(DEFAULT_INGESTION_URL);
diff --git a/frontend/src/app/api/review/[...path]/route.ts b/frontend/src/app/api/review/[...path]/route.ts
index 6b0b816b2..c823c62b2 100644
--- a/frontend/src/app/api/review/[...path]/route.ts
+++ b/frontend/src/app/api/review/[...path]/route.ts
@@ -18,7 +18,7 @@ const ADMIN_URL = (() => {
const url = process.env.ADMIN_SERVICE_URL || getServerServiceURL('admin');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/review] ADMIN_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/review] ADMIN_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('admin');
}
return url;
diff --git a/frontend/src/app/api/tools/verify/route.ts b/frontend/src/app/api/tools/verify/route.ts
index e06379d56..c74810892 100644
--- a/frontend/src/app/api/tools/verify/route.ts
+++ b/frontend/src/app/api/tools/verify/route.ts
@@ -36,10 +36,10 @@ export async function POST(request: NextRequest) {
const backendUrl = getBackendUrl();
if (process.env.VERCEL && !backendUrl) {
console.error(
- '[api/tools/verify] ADMIN_SERVICE_URL or NEXT_PUBLIC_API_BASE_URL must be set on Vercel — cannot reach localhost from serverless functions',
+ '[api/tools/verify] ADMIN_SERVICE_URL or NEXT_PUBLIC_API_BASE_URL must be set on Vercel; cannot reach localhost from serverless functions',
);
return NextResponse.json(
- { error: 'Backend not configured — contact support' },
+ { error: 'Backend not configured. Contact support' },
{ status: 503 },
);
}
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/attest/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/attest/route.ts
index 98ae100ad..21891f802 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/attest/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/attest/route.ts
@@ -16,13 +16,13 @@ function getComplianceUrl(): string {
if (url) {
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/attest] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/attest] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return process.env.NEXT_PUBLIC_API_BASE_URL || url;
}
return url;
}
if (process.env.VERCEL) {
- console.error('[api/attest] COMPLIANCE_SERVICE_URL not configured — localhost is unreachable from Vercel');
+ console.error('[api/attest] COMPLIANCE_SERVICE_URL not configured; localhost is unreachable from Vercel');
return '';
}
return 'http://localhost:8500';
@@ -49,7 +49,7 @@ export async function POST(
const COMPLIANCE_URL = getComplianceUrl();
const allowFallback = allowDevComplianceSnapshotFallback();
if (!COMPLIANCE_URL && !allowFallback) {
- console.error('[proxy/attest] 503 — compliance backend not configured');
+ console.error('[proxy/attest] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/audit-pack/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/audit-pack/route.ts
index 33d4bc10a..66ba4f8d3 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/audit-pack/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/audit-pack/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/audit-pack] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/audit-pack] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -73,7 +73,7 @@ export async function GET(
});
}
}
- console.error('[proxy/audit-pack] 503 — compliance backend not configured');
+ console.error('[proxy/audit-pack] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
index c70bbb1e6..3126a9d92 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/export] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/export] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -73,7 +73,7 @@ export async function GET(
return NextResponse.json(exportPayload);
}
}
- console.error('[proxy/export] 503 — compliance backend not configured');
+ console.error('[proxy/export] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/fda-response/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/fda-response/route.ts
index 5c0bd34ac..0d4588aed 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/fda-response/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/fda-response/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/fda-response] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/fda-response] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -66,7 +66,7 @@ export async function GET(
return NextResponse.json(fdaResponse);
}
}
- console.error('[proxy/fda-response] 503 — compliance backend not configured');
+ console.error('[proxy/fda-response] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/refreeze/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/refreeze/route.ts
index 3bcaab937..dd79f4ac9 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/refreeze/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/refreeze/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/refreeze] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/refreeze] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -79,7 +79,7 @@ export async function POST(
return NextResponse.json(result);
}
}
- console.error('[proxy/refreeze] 503 — compliance backend not configured');
+ console.error('[proxy/refreeze] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/verify/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/verify/route.ts
index de31ee2ba..d51593796 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/verify/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/verify/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/verify] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/verify] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -76,7 +76,7 @@ export async function GET(
return NextResponse.json(result);
}
}
- console.error('[proxy/verify] 503 — compliance backend not configured');
+ console.error('[proxy/verify] 503: compliance backend not configured');
return NextResponse.json(
{ is_valid: false, error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/diff/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/diff/route.ts
index e3632fa9b..7ee4aea1c 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/diff/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/diff/route.ts
@@ -18,7 +18,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/snapshot-diff] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/snapshot-diff] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -69,7 +69,7 @@ export async function GET(
return NextResponse.json(result);
}
}
- console.error('[proxy/snapshot-diff] 503 — compliance backend not configured');
+ console.error('[proxy/snapshot-diff] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/route.ts
index 2b9baa032..371ab05b7 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/route.ts
@@ -17,7 +17,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/snapshots] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/snapshots] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -67,7 +67,7 @@ export async function GET(
if (allowFallback) {
return NextResponse.json({ items: listDevComplianceSnapshots(tenantId) });
}
- console.error('[proxy/snapshots] 503 — compliance backend not configured');
+ console.error('[proxy/snapshots] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured', items: [] },
{ status: 503 },
@@ -152,7 +152,7 @@ export async function POST(
});
return NextResponse.json(snapshot);
}
- console.error('[proxy/snapshots] 503 — compliance backend not configured');
+ console.error('[proxy/snapshots] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/api/v1/compliance/status/[tenantId]/route.ts b/frontend/src/app/api/v1/compliance/status/[tenantId]/route.ts
index 6a3749fd1..4e8b2ad0a 100644
--- a/frontend/src/app/api/v1/compliance/status/[tenantId]/route.ts
+++ b/frontend/src/app/api/v1/compliance/status/[tenantId]/route.ts
@@ -12,7 +12,7 @@ function getComplianceUrl(): string {
const url = process.env.COMPLIANCE_SERVICE_URL || getServerServiceURL('compliance');
const onVercel = Boolean(process.env.VERCEL || process.env.VERCEL_URL);
if (onVercel && url.includes('.railway.internal')) {
- console.warn('[proxy/compliance-status] COMPLIANCE_SERVICE_URL points to internal Railway URL — unreachable from Vercel.');
+ console.warn('[proxy/compliance-status] COMPLIANCE_SERVICE_URL points to internal Railway URL; unreachable from Vercel.');
return getServerServiceURL('compliance');
}
return url;
@@ -50,7 +50,7 @@ export async function GET(
const COMPLIANCE_URL = getComplianceUrl();
if (!COMPLIANCE_URL) {
- console.error('[proxy/compliance-status] 503 — compliance backend not configured');
+ console.error('[proxy/compliance-status] 503: compliance backend not configured');
return NextResponse.json(
{ error: 'backend_not_configured', message: 'Compliance backend is not configured' },
{ status: 503 },
diff --git a/frontend/src/app/audit/page.tsx b/frontend/src/app/audit/page.tsx
index bfbd3715d..7e14b433a 100644
--- a/frontend/src/app/audit/page.tsx
+++ b/frontend/src/app/audit/page.tsx
@@ -156,7 +156,7 @@ function AuditReviewContent() {
diff --git a/frontend/src/app/auth/verify/page.tsx b/frontend/src/app/auth/verify/page.tsx
index 344990faf..bfe7feb43 100644
--- a/frontend/src/app/auth/verify/page.tsx
+++ b/frontend/src/app/auth/verify/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from 'next';
import VerifyClient from './VerifyClient';
export const metadata: Metadata = {
- title: 'Verify your sign-in code — RegEngine',
+ title: 'Verify your sign-in code | RegEngine',
};
export default async function VerifyPage({
diff --git a/frontend/src/app/buyer-programs/page.tsx b/frontend/src/app/buyer-programs/page.tsx
index 2b7dda7a7..14719d720 100644
--- a/frontend/src/app/buyer-programs/page.tsx
+++ b/frontend/src/app/buyer-programs/page.tsx
@@ -86,7 +86,7 @@ export default function BuyerProgramsPage() {
• FTL by that date; other products ASAP
- We do not make you Walmart-ready, transmit ASN on Retail Link, certify labels, or assess chargebacks. EDI 856 / ASN mapping is scoped work.
+ We do not make you Walmart-ready, transmit ASN on Retail Link, certify labels, or assess chargebacks. EDI 856 / ASN mapping is on the roadmap.
@@ -137,7 +137,7 @@ export default function BuyerProgramsPage() {
• Advisory coverage/completeness checklist
• Append-only commit
• FDA-oriented sortable spreadsheet
- • EPCIS/CSV where enabled
+ • CSV upload, JSON events API (EPCIS export)
• Hash manifest re-checkable at /verify
diff --git a/frontend/src/app/compare/foodlogiq/page.tsx b/frontend/src/app/compare/foodlogiq/page.tsx
index e76826193..9266b842a 100644
--- a/frontend/src/app/compare/foodlogiq/page.tsx
+++ b/frontend/src/app/compare/foodlogiq/page.tsx
@@ -25,7 +25,7 @@ const FEATURES = [
{ feature: "Public API + OpenAPI docs", regengine: "check", competitor: "partial", note: "Full REST API with interactive docs; verify FoodLogiQ's current API surface" },
{ feature: "FSMA 204 rule engine (KDE + relational)", regengine: "check", competitor: "partial", note: "36 FSMA 204 validation rules (33 stateless + 3 cross-event); rule enforcement is configurable per workflow" },
{ feature: "Per-event compliance scoring", regengine: "check", competitor: "partial", note: "Advisory readiness signal computed per event vs batch reporting" },
- { feature: "CSV / API / webhook ingestion", regengine: "check", competitor: "partial", note: "All three; verify FoodLogiQ's current ingestion surface" },
+ { feature: "CSV upload and JSON events API", regengine: "check", competitor: "partial", note: "Both; verify FoodLogiQ's current ingestion surface" },
{ feature: "Supplier portal with compliance scoring", regengine: "check", competitor: "check", note: "Both offer supplier management" },
{ feature: "Recall simulation drills", regengine: "check", competitor: "check", note: "FoodLogiQ's original strength" },
{ feature: "Published pricing on website", regengine: "check", competitor: "x", note: "List price from $849/mo (Founding rates from $425/mo, billed annually) vs custom enterprise quotes" },
diff --git a/frontend/src/app/compare/repositrak/page.tsx b/frontend/src/app/compare/repositrak/page.tsx
index 3133bcd6b..feb653af5 100644
--- a/frontend/src/app/compare/repositrak/page.tsx
+++ b/frontend/src/app/compare/repositrak/page.tsx
@@ -25,7 +25,7 @@ const FEATURES = [
{ feature: "Public API + OpenAPI docs", regengine: "check", competitor: "partial", note: "Full REST API; verify ReposiTrak's current API surface for your stack" },
{ feature: "FSMA 204 rule engine (KDE + relational)", regengine: "check", competitor: "partial", note: "Per-event KDE validation; rule enforcement is configurable per workflow" },
{ feature: "Per-event compliance scoring", regengine: "check", competitor: "partial", note: "Advisory readiness signal computed per event vs status tracking" },
- { feature: "CSV / API / webhook ingestion", regengine: "check", competitor: "partial", note: "All three; verify ReposiTrak's current ingestion options" },
+ { feature: "CSV upload and JSON events API", regengine: "check", competitor: "partial", note: "Both; verify ReposiTrak's current ingestion options" },
{ feature: "Retailer compliance network", regengine: "partial", competitor: "check", note: "ReposiTrak's core strength" },
{ feature: "Supplier portal", regengine: "check", competitor: "check", note: "Both offer supplier management" },
{ feature: "Published pricing on website", regengine: "check", competitor: "x", note: "List price from $849/mo (Founding rates from $425/mo, billed annually) vs custom retailer quotes" },
@@ -33,9 +33,9 @@ const FEATURES = [
];
const WHY_SWITCH = [
- { title: "Validation, not just submission tracking", icon: Zap, desc: "ReposiTrak focuses on supplier-data submission tracking. RegEngine validates whether the underlying data is FSMA 204 compliant \u2014 checking KDEs, cross-event integrity, and mass balance. You can use both." },
+ { title: "Validation, not just submission tracking", icon: Zap, desc: "ReposiTrak focuses on supplier-data submission tracking. RegEngine validates whether the underlying data is FSMA 204 compliant, checking KDEs, cross-event integrity, and mass balance. You can use both." },
{ title: "Works beyond one retailer", icon: Shield, desc: "ReposiTrak is optimized for retailer-supplier compliance mandates. RegEngine works across your supply chain regardless of which retailers you serve." },
- { title: "Public API and open egress", icon: Code, desc: "RegEngine ships a public REST API, OpenAPI spec, webhook integrations, and CSV export at any time. Confirm ReposiTrak's current integration options for your stack." },
+ { title: "Public API and open egress", icon: Code, desc: "RegEngine ships a public REST API, OpenAPI spec, JSON events API, and CSV export at any time. Confirm ReposiTrak's current integration options for your stack." },
{ title: "Complement your retailer tools", icon: ShoppingCart, desc: "Use ReposiTrak for retailer compliance tracking AND RegEngine for FSMA 204 validation. They solve adjacent problems." },
];
diff --git a/frontend/src/app/compare/tracegains/page.tsx b/frontend/src/app/compare/tracegains/page.tsx
index c35ef4729..7d18d6410 100644
--- a/frontend/src/app/compare/tracegains/page.tsx
+++ b/frontend/src/app/compare/tracegains/page.tsx
@@ -25,7 +25,7 @@ const FEATURES = [
{ feature: "Public API + OpenAPI docs", regengine: "check", competitor: "partial", note: "Full REST API; verify TraceGains' current integration surface" },
{ feature: "FSMA 204 rule engine (KDE + relational)", regengine: "check", competitor: "partial", note: "Per-event KDE validation; confirm TraceGains' current FSMA 204 coverage" },
{ feature: "Per-event compliance scoring", regengine: "check", competitor: "partial", note: "Advisory readiness signal computed per event" },
- { feature: "CSV / API / webhook ingestion", regengine: "check", competitor: "partial", note: "All three; verify TraceGains' current ingestion options" },
+ { feature: "CSV upload and JSON events API", regengine: "check", competitor: "partial", note: "Both; verify TraceGains' current ingestion options" },
{ feature: "Supplier document management (COAs, specs)", regengine: "partial", competitor: "check", note: "TraceGains' core strength" },
{ feature: "Supplier onboarding portal", regengine: "check", competitor: "check", note: "Both offer supplier management" },
{ feature: "Published pricing on website", regengine: "check", competitor: "x", note: "List price from $849/mo (Founding rates from $425/mo, billed annually) vs custom quotes" },
@@ -33,10 +33,10 @@ const FEATURES = [
];
const WHY_SWITCH = [
- { title: "CTE-level traceability", icon: Zap, desc: "TraceGains is strong at COA and supplier-spec collection. FSMA 204 also requires CTE-level KDE traceability \u2014 confirm coverage with each vendor for your commodities." },
+ { title: "CTE-level traceability", icon: Zap, desc: "TraceGains is strong at COA and supplier-spec collection. FSMA 204 also requires CTE-level KDE traceability. Confirm coverage with each vendor for your commodities." },
{ title: "Per-event rule evaluation", icon: Shield, desc: "RegEngine evaluates events against 36 FSMA 204 validation rules (33 stateless + 3 cross-event) as part of ingestion. Verify TraceGains' current validation features directly with their team." },
{ title: "Built for FTL commodities", icon: FileText, desc: "TraceGains is positioned for CPG supplier quality management. RegEngine is built for produce, seafood, and other FTL-covered commodities." },
- { title: "Complement, don't replace", icon: Users, desc: "You can use TraceGains for supplier docs AND RegEngine for CTE traceability. They solve different problems \u2014 you may need both." },
+ { title: "Complement, don't replace", icon: Users, desc: "You can use TraceGains for supplier docs AND RegEngine for CTE traceability. They solve different problems, and you may need both." },
];
@@ -66,7 +66,7 @@ export default function TraceGainsCompare() {
description={
<>
TraceGains is a supplier document management platform. RegEngine is a FSMA 204 traceability engine.
- Different tools for different problems — here's how they compare.
+ Different tools for different problems. Here's how they compare.
>
}
/>
diff --git a/frontend/src/app/compliance/page.tsx b/frontend/src/app/compliance/page.tsx
index fe293d422..7dc5b5266 100644
--- a/frontend/src/app/compliance/page.tsx
+++ b/frontend/src/app/compliance/page.tsx
@@ -257,7 +257,7 @@ export default function CompliancePage() {
FSMA 204
-
EPCIS 2.0
+
EPCIS 2.0 export
GS1
FDA CTEs
KDEs
diff --git a/frontend/src/app/compliance/profile/page.tsx b/frontend/src/app/compliance/profile/page.tsx
index d2a0e3860..15330689f 100644
--- a/frontend/src/app/compliance/profile/page.tsx
+++ b/frontend/src/app/compliance/profile/page.tsx
@@ -254,7 +254,7 @@ export default function ProductProfilePage() {
RegEngine monitors FDA recalls and alerts. By setting your product categories and supply regions,
- we can automatically alert you when a recall might affect your business — before it becomes a crisis.
+ we can automatically alert you when a recall might affect your business, before it becomes a crisis.
diff --git a/frontend/src/app/compliance/traceability-plan/page.tsx b/frontend/src/app/compliance/traceability-plan/page.tsx
index 2e7475e01..3bce508fb 100644
--- a/frontend/src/app/compliance/traceability-plan/page.tsx
+++ b/frontend/src/app/compliance/traceability-plan/page.tsx
@@ -195,7 +195,7 @@ export default function TraceabilityPlanPage() {
diff --git a/frontend/src/app/dashboard/alerts/page.tsx b/frontend/src/app/dashboard/alerts/page.tsx
index b2215ab61..4ef9a6a57 100644
--- a/frontend/src/app/dashboard/alerts/page.tsx
+++ b/frontend/src/app/dashboard/alerts/page.tsx
@@ -285,7 +285,7 @@ function AlertsDashboardPageContent() {
{ackError && (
- Couldn't acknowledge — retry.
+ Couldn't acknowledge. Retry.
)}
@@ -445,7 +445,7 @@ function AlertsDashboardPageContent() {
)}
diff --git a/frontend/src/app/dashboard/compliance/page.tsx b/frontend/src/app/dashboard/compliance/page.tsx
index a3f187739..2256832fa 100644
--- a/frontend/src/app/dashboard/compliance/page.tsx
+++ b/frontend/src/app/dashboard/compliance/page.tsx
@@ -102,20 +102,20 @@ const STATUS_CONFIG = {
'compliant': {
icon: Shield,
label: 'FSMA 204 Ready',
- desc: "Your traceability data meets RegEngine's readiness checks — an advisory indicator, not a legal determination.",
+ desc: "Your traceability data meets RegEngine's readiness checks. This is an advisory indicator, not a legal determination.",
bg: 'bg-re-brand-muted border-re-brand/30',
text: 'text-re-brand',
},
'at-risk': {
icon: ShieldAlert,
- label: 'At Risk — Action Needed',
+ label: 'At Risk: Action Needed',
desc: 'Gaps in your traceability data could cause issues during an FDA inspection.',
bg: 'bg-re-warning-muted0/10 border-re-warning/30',
text: 'text-re-warning',
},
'critical': {
icon: ShieldX,
- label: 'Critical — Not Compliant',
+ label: 'Critical: Not Compliant',
desc: 'Significant gaps exist. Prioritize the actions below before your next audit.',
bg: 'bg-re-danger-muted0/10 border-re-danger/30',
text: 'text-re-danger',
diff --git a/frontend/src/app/dashboard/export-jobs/page.tsx b/frontend/src/app/dashboard/export-jobs/page.tsx
index d82866278..3e344d220 100644
--- a/frontend/src/app/dashboard/export-jobs/page.tsx
+++ b/frontend/src/app/dashboard/export-jobs/page.tsx
@@ -49,7 +49,7 @@ export default function ExportJobsPage() {
const createJobMutation = useMutation({
mutationFn: async () => {
throw new Error(
- 'Export job scheduling is not yet available — records remain exportable on demand.',
+ 'Export job scheduling is not yet available. Records remain exportable on demand.',
);
},
});
@@ -115,7 +115,7 @@ export default function ExportJobsPage() {
icon={Link2Off}
title={"Scheduled export jobs aren't available on this workspace yet."}
>
- Recurring archive scheduling is still in development — no amount of connected data unlocks it today. Your records stay exportable on demand from FDA Export, and this page will activate when scheduling ships.
+ Recurring archive scheduling is still in development. No amount of connected data unlocks it today. Your records stay exportable on demand from FDA Export, and this page will activate when scheduling ships.
) : (
diff --git a/frontend/src/app/dashboard/heartbeat/page.tsx b/frontend/src/app/dashboard/heartbeat/page.tsx
index 74e8e016a..a559779c6 100644
--- a/frontend/src/app/dashboard/heartbeat/page.tsx
+++ b/frontend/src/app/dashboard/heartbeat/page.tsx
@@ -503,7 +503,7 @@ function HeartbeatPageContent() {
-
{error} — showing cached data if available.
+
{error}. Showing cached data if available.
diff --git a/frontend/src/app/dashboard/inflow-lab/page.tsx b/frontend/src/app/dashboard/inflow-lab/page.tsx
index 5e6156882..7d381be63 100644
--- a/frontend/src/app/dashboard/inflow-lab/page.tsx
+++ b/frontend/src/app/dashboard/inflow-lab/page.tsx
@@ -6,7 +6,7 @@ import { isExperimentalPageEnabled } from "@/lib/experimental-features";
export const metadata: Metadata = {
title: "Inflow Lab | RegEngine Dashboard",
description:
- "Test supplier traceability data before it flows into production exports — sandbox-only diagnostics, grouped exceptions, and a sticky lot lifecycle.",
+ "Test supplier traceability data before it flows into production exports: sandbox-only diagnostics, grouped exceptions, and a sticky lot lifecycle.",
};
export default function DashboardInflowLabPage() {
diff --git a/frontend/src/app/dashboard/issues/page.tsx b/frontend/src/app/dashboard/issues/page.tsx
index bc61539af..fefc06dc2 100644
--- a/frontend/src/app/dashboard/issues/page.tsx
+++ b/frontend/src/app/dashboard/issues/page.tsx
@@ -172,7 +172,7 @@ export default function IssuesPage() {
header: 'Case',
cell: (c) => (
- {c.requesting_party} — {c.scope_description || c.package_status}
+ {c.requesting_party}: {c.scope_description || c.package_status}
),
},
@@ -232,7 +232,7 @@ export default function IssuesPage() {
0 && (
- Blocking Defects — Must Fix Before Submission
+ Blocking Defects: Must Fix Before Submission
0 && (
- Warnings — Non-Blocking
+ Warnings (Non-Blocking)
diff --git a/frontend/src/app/dashboard/layout.tsx b/frontend/src/app/dashboard/layout.tsx
index 01418e112..06d08932d 100644
--- a/frontend/src/app/dashboard/layout.tsx
+++ b/frontend/src/app/dashboard/layout.tsx
@@ -550,7 +550,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
{demoMode && (
- Sandbox mode — using sample data for demonstration.
+ Sandbox mode: using sample data for demonstration.
Connect real data to exit sample mode
diff --git a/frontend/src/app/dashboard/notifications/page.tsx b/frontend/src/app/dashboard/notifications/page.tsx
index a3abe881d..d012f1dc2 100644
--- a/frontend/src/app/dashboard/notifications/page.tsx
+++ b/frontend/src/app/dashboard/notifications/page.tsx
@@ -348,7 +348,7 @@ export default function NotificationPrefsPage() {
title="Quiet Hours"
description={
<>
- Suppress non-critical {effectivePrefs.quiet_hours.start_hour}:00 – {effectivePrefs.quiet_hours.end_hour}:00
+ Suppress non-critical {effectivePrefs.quiet_hours.start_hour}:00 to {effectivePrefs.quiet_hours.end_hour}:00
{effectivePrefs.quiet_hours.override_critical && ' (critical bypass)'}
>
}
diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx
index 763df1e72..112db7c1e 100644
--- a/frontend/src/app/dashboard/page.tsx
+++ b/frontend/src/app/dashboard/page.tsx
@@ -348,7 +348,7 @@ export default function DashboardPage() {
Daily Compliance Heartbeat
- Score, alerts, chain status & next actions — your morning check
+ Score, alerts, chain status & next actions: your morning check
diff --git a/frontend/src/app/dashboard/products/page.tsx b/frontend/src/app/dashboard/products/page.tsx
index 8b99b2f7a..48e24e45e 100644
--- a/frontend/src/app/dashboard/products/page.tsx
+++ b/frontend/src/app/dashboard/products/page.tsx
@@ -94,7 +94,7 @@ async function apiAddProduct(tenantId: string, name: string, category: string, s
});
if (!res.ok) {
console.error(`Product add failed: ${res.status} ${res.statusText}`);
- throw new Error("Couldn't add the product — retry.");
+ throw new Error("Couldn't add the product. Retry.");
}
}
@@ -118,7 +118,7 @@ async function apiUpdateProduct(tenantId: string, product: Product, updates: { n
});
if (!res.ok) {
console.error(`Product update failed: ${res.status} ${res.statusText}`);
- throw new Error("Couldn't save your changes — retry.");
+ throw new Error("Couldn't save your changes. Retry.");
}
}
@@ -132,7 +132,7 @@ async function apiDeleteProduct(tenantId: string, productId: string): Promise
- {addProductMutation.error?.message || "Couldn't add the product — retry."}
+ {addProductMutation.error?.message || "Couldn't add the product. Retry."}
)}
@@ -448,7 +448,7 @@ export default function ProductCatalogPage() {
{updateProductMutation.isError && (
- {updateProductMutation.error?.message || "Couldn't save your changes — retry."}
+ {updateProductMutation.error?.message || "Couldn't save your changes. Retry."}
)}
@@ -479,7 +479,7 @@ export default function ProductCatalogPage() {
{deleteProductMutation.isError && (
- {deleteProductMutation.error?.message || "Couldn't delete the product — retry."}
+ {deleteProductMutation.error?.message || "Couldn't delete the product. Retry."}
)}
diff --git a/frontend/src/app/dashboard/recall-drills/page.tsx b/frontend/src/app/dashboard/recall-drills/page.tsx
index 38d51cc64..59a3cd87e 100644
--- a/frontend/src/app/dashboard/recall-drills/page.tsx
+++ b/frontend/src/app/dashboard/recall-drills/page.tsx
@@ -76,7 +76,7 @@ export default function RecallDrillsPage() {
const startDrillMutation = useMutation({
mutationFn: async () => {
throw new Error(
- 'Recall drill automation is not yet available — use the Requests workflow for a manual drill.',
+ 'Recall drill automation is not yet available. Use the Requests workflow for a manual drill.',
);
},
});
diff --git a/frontend/src/app/dashboard/recall-report/page.tsx b/frontend/src/app/dashboard/recall-report/page.tsx
index 774669119..48d608b74 100644
--- a/frontend/src/app/dashboard/recall-report/page.tsx
+++ b/frontend/src/app/dashboard/recall-report/page.tsx
@@ -89,7 +89,7 @@ const NOTICE_BASE =
/* ── Demo Fallback Data (shown only when demo_mode=true from API) ── */
const DEMO_INVESTIGATION = {
- scenario: 'Romaine Lettuce — E. coli O157:H7',
+ scenario: 'Romaine Lettuce (E. coli O157:H7)',
initiated: '2026-03-15T08:30:00Z',
response_time_hours: 4.2,
sla_target: 24,
@@ -111,10 +111,10 @@ const DEMO_AFFECTED_LOTS = [
const DEMO_TIMELINE = [
{ time: '08:30', label: 'FDA Request Received', desc: 'FSMA 204 records request for romaine lettuce lots from Salinas Valley region', icon: AlertTriangle, done: true },
{ time: '08:35', label: 'Automated Trace Initiated', desc: 'RegEngine backward trace from retail to harvest across 8 facilities', icon: Zap, done: true },
- { time: '08:42', label: '12 Lots Identified', desc: 'Forward trace mapped all downstream distribution — 3 supplier origins confirmed', icon: Package, done: true },
+ { time: '08:42', label: '12 Lots Identified', desc: 'Forward trace mapped all downstream distribution; 3 supplier origins confirmed', icon: Package, done: true },
{ time: '09:15', label: 'Supplier Notifications Sent', desc: '3 suppliers contacted: Salinas Valley Farms, Pacific Coast Growers, FreshCut Processing', icon: Users, done: true },
{ time: '10:00', label: 'FDA CSV Export Generated', desc: '24-hour response package with all CTEs, KDEs, and chain hashes', icon: Download, done: true },
- { time: '—', label: 'Retailer EPCIS Notification', desc: 'GS1 EPCIS 2.0 export package ready for retailer portal upload — confirm specific format with each buyer', icon: ShoppingCart, done: false },
+ { time: '—', label: 'Retailer EPCIS Notification', desc: 'GS1 EPCIS 2.0 export package ready for retailer portal upload. Confirm specific format with each buyer', icon: ShoppingCart, done: false },
{ time: '—', label: 'Investigation Closed', desc: 'All affected lots accounted for, remediation verified', icon: CheckCircle2, done: false },
];
@@ -366,7 +366,7 @@ export default function RecallReportPage() {
- SLA Met — {(24 - DEMO_INVESTIGATION.response_time_hours).toFixed(1)}h to spare
+ SLA Met: {(24 - DEMO_INVESTIGATION.response_time_hours).toFixed(1)}h to spare
diff --git a/frontend/src/app/dashboard/receiving/page.tsx b/frontend/src/app/dashboard/receiving/page.tsx
index fb397b1a9..62f235314 100644
--- a/frontend/src/app/dashboard/receiving/page.tsx
+++ b/frontend/src/app/dashboard/receiving/page.tsx
@@ -244,7 +244,7 @@ export default function ReceivingDockPage() {
quantity: item.quantity,
unit_of_measure: 'cases',
timestamp: item.scannedAt || new Date().toISOString(),
- location_name: `Receiving Dock — ${session.supplier}`,
+ location_name: `Receiving Dock: ${session.supplier}`,
kdes: {
gtin: item.gtin || undefined,
lot_code: item.lotCode || undefined,
@@ -639,7 +639,7 @@ export default function ReceivingDockPage() {
Receiving Complete
- {session.supplier} — PO {session.poNumber}
+ {session.supplier}, PO {session.poNumber}
{ts}
diff --git a/frontend/src/app/dashboard/scan/page.tsx b/frontend/src/app/dashboard/scan/page.tsx
index cb93551ef..e29617365 100644
--- a/frontend/src/app/dashboard/scan/page.tsx
+++ b/frontend/src/app/dashboard/scan/page.tsx
@@ -90,7 +90,7 @@ const HOW_IT_WORKS = [
{
step: '2',
title: 'Select event type & scan item',
- detail: 'Choose what you\'re doing: Receiving, Shipping, or Transforming. Point your camera at the barcode — product number, lot code, expiry, and serial are extracted automatically.',
+ detail: 'Choose what you\'re doing: Receiving, Shipping, or Transforming. Point your camera at the barcode; product number, lot code, expiry, and serial are extracted automatically.',
},
{
step: '3',
@@ -195,7 +195,7 @@ function ScanPageContent() {
- Display this QR code on a tablet or print it. Floor operators scan it with their phone to open the capture tool — no app install required.
+ Display this QR code on a tablet or print it. Floor operators scan it with their phone to open the capture tool. No app install required.
{/* QR Code */}
@@ -282,7 +282,7 @@ function ScanPageContent() {
))}
- Barcodes are parsed automatically — product number, lot code, serial, expiry, and pack date are extracted and mapped to the required data fields.
+ Barcodes are parsed automatically: product number, lot code, serial, expiry, and pack date are extracted and mapped to the required data fields.
diff --git a/frontend/src/app/dashboard/settings/page.tsx b/frontend/src/app/dashboard/settings/page.tsx
index fafc5df1d..415dedfe4 100644
--- a/frontend/src/app/dashboard/settings/page.tsx
+++ b/frontend/src/app/dashboard/settings/page.tsx
@@ -367,7 +367,7 @@ export default function SettingsPage() {
size="lg"
value={profile.fei_number}
onChange={e => setProfile({ ...profile, fei_number: e.target.value })}
- placeholder="Optional — used in FDA exports"
+ placeholder="Optional, used in FDA exports"
/>
diff --git a/frontend/src/app/demo/page.tsx b/frontend/src/app/demo/page.tsx
index 5b6e57dee..a3656f0ea 100644
--- a/frontend/src/app/demo/page.tsx
+++ b/frontend/src/app/demo/page.tsx
@@ -90,7 +90,7 @@ export default function DemoPage() {
title="Compliance Dashboard"
description={
<>
- DEMO WORKSPACE — FreshCo Distribution is a fictional distributor. Numbers are illustrative.
+ DEMO WORKSPACE: FreshCo Distribution is a fictional distributor. Numbers are illustrative.
>
}
/>
diff --git a/frontend/src/app/design-system/page.tsx b/frontend/src/app/design-system/page.tsx
index bcf352b55..8c47b3832 100644
--- a/frontend/src/app/design-system/page.tsx
+++ b/frontend/src/app/design-system/page.tsx
@@ -264,7 +264,7 @@ export default function DesignSystemPage() {
- Card variant inset — wells, code blocks and summary strips.
+ Card variant inset: wells, code blocks and summary strips.
diff --git a/frontend/src/app/developers/compliance-verticals/page.tsx b/frontend/src/app/developers/compliance-verticals/page.tsx
index e12957749..946b69891 100644
--- a/frontend/src/app/developers/compliance-verticals/page.tsx
+++ b/frontend/src/app/developers/compliance-verticals/page.tsx
@@ -34,7 +34,7 @@ const FRAMEWORKS = [
title: 'Seafood',
icon: Fish,
description: 'Finfish and shellfish chain-of-custody controls',
- details: 'Reference scaffold for seafood obtained from a fishing vessel — uses §1.1335 First Land-Based Receiving as the entry CTE. Final CTE/KDE coverage is configured during onboarding.',
+ details: 'Reference scaffold for seafood obtained from a fishing vessel. Uses §1.1335 First Land-Based Receiving as the entry CTE. Final CTE/KDE coverage is configured during onboarding.',
jsonSnippet: `{
"profile": "seafood",
"ftl_categories": ["Fresh Finfish", "Crustaceans"],
diff --git a/frontend/src/app/developers/page.tsx b/frontend/src/app/developers/page.tsx
index 3ac0d8ee2..e096f7a1c 100644
--- a/frontend/src/app/developers/page.tsx
+++ b/frontend/src/app/developers/page.tsx
@@ -1,7 +1,7 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import {
- ArrowRight, Webhook, Cog, Users, FileSpreadsheet,
+ ArrowRight, Braces, Cog, Users, FileSpreadsheet,
BarChart3, GitBranch, Terminal, BookOpen,
} from 'lucide-react';
import { Badge } from '@/components/ui/badge';
@@ -13,11 +13,11 @@ import { INGEST_CURL_SAMPLE, INGEST_ENV_SETUP } from '@/lib/api-samples/ingest-s
export const metadata: Metadata = {
title: 'Developers | RegEngine FSMA 204 Compliance API',
description:
- 'Build on the RegEngine API: webhook ingestion with KDE validation, 36 FSMA 204 rules, identity resolution, FDA export, compliance scoring, and request workflow management.',
+ 'Build on the RegEngine API: a JSON events API with KDE validation, 36 FSMA 204 rules, identity resolution, FDA export, compliance scoring, and request workflow management.',
openGraph: {
title: 'Developers | RegEngine FSMA 204 Compliance API',
description:
- 'Build on the RegEngine API: webhook ingestion, rules engine, identity resolution, FDA export, compliance scoring, and request workflow.',
+ 'Build on the RegEngine API: JSON events API, rules engine, identity resolution, FDA export, compliance scoring, and request workflow.',
url: 'https://regengine.co/developers',
type: 'website',
},
@@ -26,9 +26,9 @@ export const metadata: Metadata = {
/* ── API Capabilities ── */
const capabilities = [
{
- Icon: Webhook,
- title: 'Webhook Ingestion',
- description: 'POST events with KDE validation. Inbound CTEs are validated against FSMA 204 Key Data Elements; failures surface as exceptions before package assembly.',
+ Icon: Braces,
+ title: 'JSON events API',
+ description: 'POST CTE events as JSON with KDE validation. Inbound events are validated against FSMA 204 Key Data Elements; failures surface as exceptions before package assembly.',
},
{
Icon: Cog,
@@ -167,7 +167,7 @@ export default function DevelopersPage() {
SDKs Coming Soon
Official client libraries for Python, Node.js, and Go are planned.
- In the meantime, use our REST API directly — all endpoints accept and return JSON.
+ In the meantime, use our REST API directly. All endpoints accept and return JSON.
diff --git a/frontend/src/app/docs/authentication/page.tsx b/frontend/src/app/docs/authentication/page.tsx
index 42bcb8d56..568730062 100644
--- a/frontend/src/app/docs/authentication/page.tsx
+++ b/frontend/src/app/docs/authentication/page.tsx
@@ -133,8 +133,8 @@ export default function AuthenticationDocsPage() {
Scopes limit which of the endpoints above a key can call. They are not a read-only guarantee: some other
- operations on the RegEngine backend, for example EPCIS ingest, compliance snapshots, SLA request updates
- and onboarding steps, accept any valid tenant key without checking a named scope. Treat every key as
+ operations on the RegEngine backend, for example compliance snapshots, SLA request updates, onboarding steps
+ and the EPCIS intake endpoint (on the roadmap, not a live intake channel), accept any valid tenant key without checking a named scope. Treat every key as
read-write for its workspace. Keep it on your server, never in client-side code, and ask RegEngine to
revoke it if it leaks.
diff --git a/frontend/src/app/docs/walkthrough/page.tsx b/frontend/src/app/docs/walkthrough/page.tsx
index d527f77d2..f54b1fe6c 100644
--- a/frontend/src/app/docs/walkthrough/page.tsx
+++ b/frontend/src/app/docs/walkthrough/page.tsx
@@ -208,7 +208,7 @@ head -20 lot-export.csv`}
{filterExperimentalToolLinks([
{ title: 'Try a Recall Drill', desc: 'Simulate an FDA recall request against the data you just posted', href: '/dashboard/recall-drills' },
{ title: 'CSV Bulk Ingest', desc: 'Upload a real supplier CSV through Inflow Workbench preflight', href: '/tools/inflow-lab' },
- { title: 'Set up EPCIS or EDI', desc: 'Replace manual curl with your existing system-of-record', href: '/docs/connectors/inflow-lab' },
+ { title: 'EPCIS and EDI intake (on the roadmap)', desc: 'Planned connectors for your existing system-of-record. Today, use CSV upload or the JSON events API', href: '/docs/connectors/inflow-lab' },
]).map(({ title, desc, href }) => (
0 ? (
diff --git a/frontend/src/app/fsma-204/[cte]/page.tsx b/frontend/src/app/fsma-204/[cte]/page.tsx
index ebf9b016e..c8e3d05dc 100644
--- a/frontend/src/app/fsma-204/[cte]/page.tsx
+++ b/frontend/src/app/fsma-204/[cte]/page.tsx
@@ -70,15 +70,15 @@ const CTE_DATA: Record = {
{ field: "Harvester Business Name", description: "Legal name of the entity that harvested", example: "Sunny Acres Farm LLC" },
],
commonMistakes: [
- "Missing field or growing area — the FDA requires this, not just the farm address. Each field needs a distinct identifier.",
- "Inconsistent lot code formats — mixing formats like LOT-001, Lot001, and lot_001 across seasons or crews breaks traceability.",
- "Date format chaos — switching between MM/DD/YYYY and DD/MM/YYYY within the same file. The FDA expects a consistent, unambiguous format.",
+ "Missing field or growing area: the FDA requires this, not just the farm address. Each field needs a distinct identifier.",
+ "Inconsistent lot code formats: mixing formats like LOT-001, Lot001, and lot_001 across seasons or crews breaks traceability.",
+ "Date format chaos: switching between MM/DD/YYYY and DD/MM/YYYY within the same file. The FDA expects a consistent, unambiguous format.",
],
howRegEngineHelps: [
- "Validates that every required KDE is present before you submit — no more surprise gaps during an audit.",
+ "Validates that every required KDE is present before you submit. No more surprise gaps during an audit.",
"Flags inconsistent lot code formats and suggests standardized alternatives.",
"Catches date format mismatches and normalizes them to ISO 8601 (YYYY-MM-DD).",
- "Checks that field/growing area is populated — the most commonly missed KDE for harvesting events.",
+ "Checks that field/growing area is populated. It is the most commonly missed KDE for harvesting events.",
],
},
cooling: {
@@ -98,9 +98,9 @@ const CTE_DATA: Record = {
{ field: "Temperature (recommended)", description: "Temperature the product was cooled to. Recommended for cold-chain practice; not required by §1.1325.", example: "34°F" },
],
commonMistakes: [
- "Missing cooling date — data entry delays mean the cooling event is recorded hours or days late, often without the actual date.",
- "Temperature not captured — temperature isn't required by FSMA 204, but most cooling-chain audits expect it.",
- "Facility name inconsistency — using 'CoolCo', 'Cool Co LLC', and 'CoolCo Pre-Cool' interchangeably across records.",
+ "Missing cooling date: data entry delays mean the cooling event is recorded hours or days late, often without the actual date.",
+ "Temperature not captured: temperature isn't required by FSMA 204, but most cooling-chain audits expect it.",
+ "Facility name inconsistency: using 'CoolCo', 'Cool Co LLC', and 'CoolCo Pre-Cool' interchangeably across records.",
],
howRegEngineHelps: [
"Flags missing cooling dates and prompts for the actual date, not the upload date.",
@@ -126,12 +126,12 @@ const CTE_DATA: Record = {
{ field: "Input Lot Codes", description: "TLCs of the harvested lots that went into this pack run", example: "LOT-2026-04-15-BLU-001, LOT-2026-04-15-BLU-002" },
],
commonMistakes: [
- "Missing input lot codes — this is the single most common packing error. Without input TLCs, the traceability chain breaks at the packhouse.",
- "Duplicate rows from ERP exports — many ERP systems export one row per case rather than one row per lot, creating thousands of duplicate CTE records.",
- "CTE type aliases — some systems label this event as 'packing', 'pack', 'IP', or 'initial pack'. Mixed labels cause mapping failures.",
+ "Missing input lot codes: this is the single most common packing error. Without input TLCs, the traceability chain breaks at the packhouse.",
+ "Duplicate rows from ERP exports: many ERP systems export one row per case rather than one row per lot, creating thousands of duplicate CTE records.",
+ "CTE type aliases: some systems label this event as 'packing', 'pack', 'IP', or 'initial pack'. Mixed labels cause mapping failures.",
],
howRegEngineHelps: [
- "Requires input lot codes before an export can build — preventing the most common traceability break.",
+ "Requires input lot codes before an export can build, preventing the most common traceability break.",
"Deduplicates rows automatically when it detects ERP-style per-case exports.",
"Normalizes CTE type labels so 'packing', 'pack', and 'initial_packing' all map correctly.",
"Validates that input TLCs reference real harvesting or cooling events in your data.",
@@ -157,9 +157,9 @@ const CTE_DATA: Record = {
{ field: "Bill of Lading (BOL)", description: "Unique shipping document reference number", example: "BOL-78234" },
],
commonMistakes: [
- "Missing destination (ship-to) — WMS systems often omit the full destination address, recording only a customer code.",
- "Abbreviated headers from WMS — column names like 'SHP_DT', 'DEST_CD', or 'QTY_CS' may not map cleanly to FDA-oriented field names.",
- "Carrier name inconsistency — the same carrier appearing as 'Pacific Cold', 'Pacific Cold Freight', and 'PCF Logistics'.",
+ "Missing destination (ship-to): WMS systems often omit the full destination address, recording only a customer code.",
+ "Abbreviated headers from WMS: column names like 'SHP_DT', 'DEST_CD', or 'QTY_CS' may not map cleanly to FDA-oriented field names.",
+ "Carrier name inconsistency: the same carrier appearing as 'Pacific Cold', 'Pacific Cold Freight', and 'PCF Logistics'.",
],
howRegEngineHelps: [
"Validates that ship-to includes a full address or GLN, not just a customer code.",
@@ -193,9 +193,9 @@ const CTE_DATA: Record = {
{ field: "Reference Document", description: "BOL, PO, or ASN number associated with the shipment", example: "PO-44210" },
],
commonMistakes: [
- "Missing immediate previous source — receivers often record what arrived but not who sent it, breaking the trace-back chain.",
- "Product name mismatch vs. shipped — the shipper calls it 'Blueberries 6oz' and the receiver logs 'Fresh Blueberry Clamshell'. The FDA sees two different products.",
- "Missing reference document — without a BOL or PO number, there is no way to link the receiving event to the corresponding shipping event.",
+ "Missing immediate previous source: receivers often record what arrived but not who sent it, breaking the trace-back chain.",
+ "Product name mismatch vs. shipped: the shipper calls it 'Blueberries 6oz' and the receiver logs 'Fresh Blueberry Clamshell'. The FDA sees two different products.",
+ "Missing reference document: without a BOL or PO number, there is no way to link the receiving event to the corresponding shipping event.",
],
howRegEngineHelps: [
"Requires immediate previous source before an export can build.",
@@ -217,7 +217,7 @@ const CTE_DATA: Record = {
"Anyone who creates new products from FTL ingredients",
],
kdes: [
- { field: "Traceability Lot Code (TLC) — New", description: "New lot code assigned to the output product", example: "TFM-2026-04-18-MIX-001" },
+ { field: "New Traceability Lot Code (TLC)", description: "New lot code assigned to the output product", example: "TFM-2026-04-18-MIX-001" },
{ field: "Product Description", description: "FDA-standard description of the output product", example: "Spring Mix, 5oz bag" },
{ field: "Quantity", description: "Amount of the output product", example: "6,000" },
{ field: "Unit of Measure", description: "UOM for the output quantity", example: "bags" },
@@ -226,9 +226,9 @@ const CTE_DATA: Record = {
{ field: "Input TLCs", description: "All lot codes of ingredients that went into this product", example: "LOT-ROM-042, LOT-SPN-038, LOT-KAL-019" },
],
commonMistakes: [
- "Missing input TLCs — this is the most critical transformation error. Without input lot codes, trace-back stops at the processor.",
- "Mass balance violations — 100 lbs of inputs producing 120 lbs of output. The math must add up (minus documented waste/trim).",
- "No transformation date — the system records when the data was entered, not when the transformation actually occurred.",
+ "Missing input TLCs: this is the most critical transformation error. Without input lot codes, trace-back stops at the processor.",
+ "Mass balance violations: 100 lbs of inputs producing 120 lbs of output. The math must add up (minus documented waste/trim).",
+ "No transformation date: the system records when the data was entered, not when the transformation actually occurred.",
],
howRegEngineHelps: [
"Requires input TLCs and validates that each one references a real lot in the system.",
@@ -242,7 +242,7 @@ const CTE_DATA: Record = {
name: "First Land-Based Receiving",
cfr: "21 CFR 1.1335",
description:
- "Records the first land-based receipt of food obtained from a fishing vessel — the point at which seafood lands and enters the domestic traceability chain. This CTE applies only to food obtained from a fishing vessel; generic imported food entry is covered by ordinary Receiving (§1.1345).",
+ "Records the first land-based receipt of food obtained from a fishing vessel: the point at which seafood lands and enters the domestic traceability chain. This CTE applies only to food obtained from a fishing vessel; generic imported food entry is covered by ordinary Receiving (§1.1345).",
whoNeedsThis: [
"Seafood docks and first receivers landing fish from vessels",
"Processors receiving directly from a fishing vessel",
@@ -257,16 +257,16 @@ const CTE_DATA: Record = {
{ field: "Immediate Previous Source", description: "Vessel name or foreign shipper information", example: "F/V Ocean Harvest, Fiji registry" },
],
commonMistakes: [
- "Handwritten dock logs — many port facilities still use paper logs, leading to transcription errors and illegible records.",
- "Unparseable dates — international date formats (18/04/2026 vs 04/18/2026) and handwritten dates create ambiguity.",
- "Vessel name inconsistency — the same vessel logged as 'Ocean Harvest', 'F/V OCEAN HARVEST', and 'OceanHarvest-FJ'.",
- "Missing everything — first land-based receiving has the lowest data quality of any CTE because dock operations are fast-paced and often paper-based.",
+ "Handwritten dock logs: many port facilities still use paper logs, leading to transcription errors and illegible records.",
+ "Unparseable dates: international date formats (18/04/2026 vs 04/18/2026) and handwritten dates create ambiguity.",
+ "Vessel name inconsistency: the same vessel logged as 'Ocean Harvest', 'F/V OCEAN HARVEST', and 'OceanHarvest-FJ'.",
+ "Missing everything: first land-based receiving has the lowest data quality of any CTE because dock operations are fast-paced and often paper-based.",
],
howRegEngineHelps: [
"Accepts scanned or typed dock logs and validates that all required KDEs are present.",
"Normalizes international date formats and flags ambiguous dates for manual review.",
"Detects vessel name variations and maintains a canonical vessel registry.",
- "Provides a pre-formatted template designed for dock operations — fast to fill out, impossible to miss a required field.",
+ "Provides a pre-formatted template designed for dock operations: fast to fill out, impossible to miss a required field.",
],
},
};
@@ -301,7 +301,7 @@ export async function generateMetadata({
if (!data) return {};
return {
- title: `${data.name} CTE — FSMA 204 ${data.cfr} Compliance | RegEngine`,
+ title: `${data.name} CTE: FSMA 204 ${data.cfr} Compliance | RegEngine`,
description: `Everything you need to know about the ${data.name} Critical Tracking Event under FSMA 204 (${data.cfr}). Required KDEs, common mistakes, and how to validate your data.`,
};
}
@@ -454,13 +454,13 @@ export default async function CTELandingPage({
Upload a sample {data.name.toLowerCase()} file to the RegEngine
- sandbox and get an instant validation report — free, no signup
+ sandbox and get an instant validation report. Free, no signup
required.
- Try it now — free
+ Try it now, free
diff --git a/frontend/src/app/fsma-204/page.tsx b/frontend/src/app/fsma-204/page.tsx
index 042db8e8a..85879c14d 100644
--- a/frontend/src/app/fsma-204/page.tsx
+++ b/frontend/src/app/fsma-204/page.tsx
@@ -57,7 +57,7 @@ const CTES_PLAIN = [
name: "First Land-Based Receiving",
icon: Anchor,
who: "Receivers of seafood from a fishing vessel",
- what: "Per §1.1330: record when seafood was received from a fishing vessel, the lot code, the harvest and landing location, and the receiving facility. This is distinct from generic imported-food entry.",
+ what: "Under §1.1335, record when seafood was received from a fishing vessel, the lot code, the harvest and landing location, and the receiving facility. This is distinct from generic imported-food entry.",
},
{
name: "Shipping",
diff --git a/frontend/src/app/fsma/integration/page.tsx b/frontend/src/app/fsma/integration/page.tsx
index f183ef5d8..db1d67f72 100644
--- a/frontend/src/app/fsma/integration/page.tsx
+++ b/frontend/src/app/fsma/integration/page.tsx
@@ -29,7 +29,7 @@ export default function IntegrationHubPage() {
@@ -42,7 +42,7 @@ export default function IntegrationHubPage() {
The "Overlay" Traceability Model
- RegEngine doesn't replace your WMS or inventory management system. We capture the Critical Tracking Events your operations require — Harvesting and Cooling (§1.1325), Initial Packing (§1.1330) for RACs other than from a fishing vessel, First Land-Based Receiving (§1.1335) for seafood from a fishing vessel, Shipping (§1.1340), Receiving (§1.1345, subject to §1.1305(j) restaurant/RFE exemption), and Transformation (§1.1350) — link them to your Traceability Lot Codes, and store them with SHA-256 manifests so you can produce a sortable electronic spreadsheet within 24 hours of an FDA request under §1.1455(c).
+ RegEngine doesn't replace your WMS or inventory management system. We capture the Critical Tracking Events your operations require: Harvesting and Cooling (§1.1325), Initial Packing (§1.1330) for RACs other than from a fishing vessel, First Land-Based Receiving (§1.1335) for seafood from a fishing vessel, Shipping (§1.1340), Receiving (§1.1345, subject to §1.1305(j) restaurant/RFE exemption), and Transformation (§1.1350). We link them to your Traceability Lot Codes and store them with SHA-256 manifests so you can produce a sortable electronic spreadsheet within 24 hours of an FDA request under §1.1455(c).
diff --git a/frontend/src/app/fsma/layout.tsx b/frontend/src/app/fsma/layout.tsx
index b008dd5c5..4cf5d478a 100644
--- a/frontend/src/app/fsma/layout.tsx
+++ b/frontend/src/app/fsma/layout.tsx
@@ -4,7 +4,7 @@ export const metadata: Metadata = {
title: 'FSMA 204 Dashboard | Traceability & Recall Management | RegEngine',
description: 'FSMA 204 compliance dashboard with traceability lot tracking, recall drill simulations, supplier KDE completeness, and FDA export readiness.',
openGraph: {
- title: 'FSMA 204 Dashboard — RegEngine',
+ title: 'FSMA 204 Dashboard | RegEngine',
description: 'FSMA 204 compliance dashboard with lot tracking, recall drills, and FDA export readiness.',
url: 'https://regengine.co/fsma',
type: 'website',
diff --git a/frontend/src/app/identity/page.tsx b/frontend/src/app/identity/page.tsx
index 389ec0f4e..759e279b1 100644
--- a/frontend/src/app/identity/page.tsx
+++ b/frontend/src/app/identity/page.tsx
@@ -282,7 +282,7 @@ function IdentityResolutionPageContent() {
Ambiguous Match Review Queue
- Potential duplicates requiring human review — confirm match, confirm distinct, or defer
+ Potential duplicates requiring human review: confirm match, confirm distinct, or defer
diff --git a/frontend/src/app/ingest/results/[id]/AnalysisResultClient.tsx b/frontend/src/app/ingest/results/[id]/AnalysisResultClient.tsx
index 101d5bbbe..e03937b5d 100644
--- a/frontend/src/app/ingest/results/[id]/AnalysisResultClient.tsx
+++ b/frontend/src/app/ingest/results/[id]/AnalysisResultClient.tsx
@@ -107,7 +107,7 @@ export default function AnalysisResultClient() {
Cryptographic Timeline
- Simulated example — not a verification record
+ Simulated example, not a verification record
diff --git a/frontend/src/app/login/layout.tsx b/frontend/src/app/login/layout.tsx
index c60a75d11..35e5cb5f2 100644
--- a/frontend/src/app/login/layout.tsx
+++ b/frontend/src/app/login/layout.tsx
@@ -4,7 +4,7 @@ export const metadata: Metadata = {
title: 'Sign In | RegEngine',
description: 'Sign in to your RegEngine workspace to manage FSMA 204 traceability records and review-ready exports.',
openGraph: {
- title: 'Sign In — RegEngine',
+ title: 'Sign In | RegEngine',
description: 'Sign in to your RegEngine workspace to manage FSMA 204 traceability records and review-ready exports.',
type: 'website',
url: 'https://regengine.co/login',
diff --git a/frontend/src/app/onboarding/bulk-upload/page.tsx b/frontend/src/app/onboarding/bulk-upload/page.tsx
index 9417e84f1..89f896b1b 100644
--- a/frontend/src/app/onboarding/bulk-upload/page.tsx
+++ b/frontend/src/app/onboarding/bulk-upload/page.tsx
@@ -320,7 +320,7 @@ export default function BulkUploadPage() {
Free preview mode
- Upload a CSV to preview and validate your data against FSMA 204 traceability expectations — no account required. Sign in to commit with cryptographic integrity and generate review-ready records.
+ Upload a CSV to preview and validate your data against FSMA 204 traceability expectations. No account required. Sign in to commit with cryptographic integrity and generate review-ready records.
)}
diff --git a/frontend/src/app/onboarding/setup/facility/page.tsx b/frontend/src/app/onboarding/setup/facility/page.tsx
index 4519ebddf..d0714e738 100644
--- a/frontend/src/app/onboarding/setup/facility/page.tsx
+++ b/frontend/src/app/onboarding/setup/facility/page.tsx
@@ -109,7 +109,7 @@ export default function FacilityPage() {
} else if (status === 400 || status === 422) {
setError(
apiError.response.data?.detail ||
- 'Validation failed — check your facility details and try again.',
+ 'Validation failed. Check your facility details and try again.',
);
} else if (status === 409) {
setError(
@@ -119,7 +119,7 @@ export default function FacilityPage() {
setError('Too many requests. Please wait a moment and try again.');
} else if (status !== undefined && status >= 500) {
setError(
- 'Could not save facility — server error. Try again or email support@regengine.co.',
+ 'Could not save facility (server error). Try again or email support@regengine.co.',
);
} else {
setError(
@@ -260,7 +260,7 @@ export default function FacilityPage() {
size="lg"
onClick={() => router.push('/dashboard')}
>
- Skip for now — I'll set up later
+ Skip for now. I'll set up later
router.push('/dashboard')}
>
- Skip for now — I'll set up later
+ Skip for now. I'll set up later
{!showResults ? (
- Help us tailor your workspace — this takes about 10 seconds.
+ Help us tailor your workspace. This takes about 10 seconds.
@@ -133,7 +133,7 @@ export default function WelcomePage() {
size="lg"
onClick={() => router.push('/dashboard')}
>
- Skip for now — I'll set up later
+ Skip for now. I'll set up later
- Powered by RegEngine — FSMA 204 Compliance
+ Powered by RegEngine, FSMA 204 Compliance
);
@@ -635,7 +635,7 @@ export default function PortalSubmissionPage() {
{/* Footer */}
- Powered by RegEngine — FSMA 204 Compliance Infrastructure
+ Powered by RegEngine, FSMA 204 Compliance Infrastructure
privacy@regengine.co
-
- . You'll hear from the founder directly, not a legal department.
+ . You'll hear from the founder directly, not a legal department.
diff --git a/frontend/src/app/proof/recall-drill/page.tsx b/frontend/src/app/proof/recall-drill/page.tsx
index f54ad0457..4e21e1a29 100644
--- a/frontend/src/app/proof/recall-drill/page.tsx
+++ b/frontend/src/app/proof/recall-drill/page.tsx
@@ -77,7 +77,7 @@ const DEFAULT_DRILL_STEPS: DrillStep[] = [
{
label: 'Generating FDA-oriented sortable recall CSV from sample data',
detailLines: [
- 'Wrote 21 CFR §§1.1325–1.1350 Key Data Elements for each downstream lot',
+ 'Wrote 21 CFR §§1.1325 to 1.1350 Key Data Elements for each downstream lot',
'Hash-anchored each record (SHA-256 chain integrity preserved)',
],
durationMs: 1600,
@@ -267,9 +267,9 @@ export default function RecallDrillPage() {
className="mb-0 border-b-0 pb-0"
/>
- Click Start drill — RegEngine
+ Click Start drill and RegEngine
traces the contaminated lot through the applicable CTEs and produces an FDA-oriented sortable
- recall CSV in under 60 seconds. Synthetic data — illustrative only.
+ recall CSV in under 60 seconds. Synthetic data, illustrative only.
@@ -391,7 +391,7 @@ export default function RecallDrillPage() {
Synthetic lot {drill.lot_code}
- § 204 — produce records on request
+ § 204: produce records on request
Headroom vs. regulatory window
@@ -455,7 +455,7 @@ export default function RecallDrillPage() {
Recall CSV ready
- 21 CFR §§1.1325–1.1350 Key Data Elements · 11 rows · synthetic data
+ 21 CFR §§1.1325 to 1.1350 Key Data Elements · 11 rows · synthetic data
@@ -482,7 +482,7 @@ export default function RecallDrillPage() {
2. The recall simulator walks downstream
- through all 7 CTEs — harvesting, cooling, packing, shipping,
+ through all 7 CTEs: harvesting, cooling, packing, shipping,
receiving, transformation, shipping again.
@@ -505,7 +505,7 @@ export default function RecallDrillPage() {
All data is synthetic. The drill runs on a frozen public dataset separate
- from any customer data. Run as many times as you like — results are
+ from any customer data. Run as many times as you like; results are
deterministic.
diff --git a/frontend/src/app/remediation/page.tsx b/frontend/src/app/remediation/page.tsx
index 6dc5caeaf..d62fa1a9a 100644
--- a/frontend/src/app/remediation/page.tsx
+++ b/frontend/src/app/remediation/page.tsx
@@ -48,8 +48,8 @@ const CASE_STATUS_LABEL: Record = {
// Delivery lifecycle of an outbox entry (fsma.notification_outbox.status).
// 'pending'/'previewed' predate automatic delivery and are never emailed.
const DELIVERY_LABEL: Record = {
- pending: 'Preview — not emailed',
- previewed: 'Preview — not emailed',
+ pending: 'Preview (not emailed)',
+ previewed: 'Preview (not emailed)',
queued: 'Email queued',
sending: 'Sending',
sent: 'Emailed',
@@ -103,7 +103,7 @@ function IssuedLinkPanel({ url, email }: { url: string; email: string | null })
{email ? (
<>
- Link issued — being emailed to {email} automatically (usually within a minute).
+ Link issued. It is being emailed to {email} automatically (usually within a minute).
Do not share the copy below: sending re-issues the link, so this copy stops working the
@@ -112,8 +112,8 @@ function IssuedLinkPanel({ url, email }: { url: string; email: string | null })
>
) : (
- No supplier email given — this link will NOT be emailed. Copy it now and deliver it
- yourself (shown once — only its hash is stored):
+ No supplier email given, so this link will NOT be emailed. Copy it now and deliver it
+ yourself (shown once; only its hash is stored):
)}
@@ -166,7 +166,7 @@ export default function RemediationPage() {
const pageHeader = (
);
@@ -372,7 +372,7 @@ export default function RemediationPage() {
{detail.data?.original_filename ?? 'Manifest detail'}
- SHA-256 {detail.data?.source_sha256?.slice(0, 16)}… — original bytes preserved verbatim
+ SHA-256 {detail.data?.source_sha256?.slice(0, 16)}… (original bytes preserved verbatim)
setSelectedRun(null)}>
diff --git a/frontend/src/app/requests/[id]/page.tsx b/frontend/src/app/requests/[id]/page.tsx
index bb04115a7..f12e9dd50 100644
--- a/frontend/src/app/requests/[id]/page.tsx
+++ b/frontend/src/app/requests/[id]/page.tsx
@@ -132,7 +132,7 @@ export default function RequestCaseDetailPage() {
}
title="Request Case"
- description={`${requestCase.requesting_party} — ${requestCase.scope_type?.replace(/_/g, ' ')}`}
+ description={`${requestCase.requesting_party}: ${requestCase.scope_type?.replace(/_/g, ' ')}`}
meta={
<>
{ruleList.length} rules}
primaryAction={
seedRules.mutate()} disabled={seedRules.isPending}>
diff --git a/frontend/src/app/sandbox/SandboxClient.tsx b/frontend/src/app/sandbox/SandboxClient.tsx
index c7fb9a082..34d6a19e3 100644
--- a/frontend/src/app/sandbox/SandboxClient.tsx
+++ b/frontend/src/app/sandbox/SandboxClient.tsx
@@ -40,7 +40,7 @@ export function validateSandboxFile(file: { name: string; size: number }): strin
return `Unsupported file type ${ext}. Upload a .csv export of your traceability events.`;
}
if (file.size > MAX_CSV_BYTES) {
- return `That file is ${(file.size / 1_000_000).toFixed(1)} MB. The sandbox evaluates up to 2 MB — contact us for unlimited evaluation.`;
+ return `That file is ${(file.size / 1_000_000).toFixed(1)} MB. The sandbox evaluates up to 2 MB. Contact us for unlimited evaluation.`;
}
return null;
}
@@ -55,7 +55,7 @@ export function describeSandboxFailure(status: number, detail?: string): string
}
if (detail) return detail;
if (status === 503) {
- return 'The sandbox evaluation service is temporarily unavailable. Nothing was stored — please try again shortly.';
+ return 'The sandbox evaluation service is temporarily unavailable. Nothing was stored. Please try again shortly.';
}
return `The sandbox could not evaluate that file (HTTP ${status}).`;
}
@@ -103,7 +103,7 @@ export function SandboxClient() {
non_compliant_events: data.non_compliant_events,
});
} catch {
- setError('Could not reach the sandbox. Check your connection and try again — nothing was stored.');
+ setError('Could not reach the sandbox. Check your connection and try again. Nothing was stored.');
posthog.capture('SANDBOX_EVALUATE_FAILED', { status: 0 });
} finally {
setBusy(false);
@@ -153,7 +153,7 @@ export function SandboxClient() {
Upload a CSV of traceability events and see which §1.1455 key data elements are missing,
- which rules fail, and what to fix first. No signup. Nothing is stored — the evaluation is
+ which rules fail, and what to fix first. No signup. Nothing is stored; the evaluation is
stateless and the file never leaves the request.
diff --git a/frontend/src/app/sandbox/page.tsx b/frontend/src/app/sandbox/page.tsx
index 26c23904c..1befb5af7 100644
--- a/frontend/src/app/sandbox/page.tsx
+++ b/frontend/src/app/sandbox/page.tsx
@@ -14,11 +14,11 @@ import { isSandboxEnabled } from '@/lib/sandbox-cta';
// allowlist in app/api/ingestion/[...path]/route.ts.
export const metadata: Metadata = {
- title: 'FSMA 204 Sandbox — Check your CSV | RegEngine',
+ title: 'FSMA 204 Sandbox: Check your CSV | RegEngine',
description:
'Upload a CSV of traceability events and see which FSMA 204 key data elements are missing. No signup, no data stored.',
openGraph: {
- title: 'FSMA 204 Sandbox — Check your CSV',
+ title: 'FSMA 204 Sandbox: Check your CSV',
description: 'Upload a CSV of traceability events and see which FSMA 204 key data elements are missing. No signup, no data stored.',
url: 'https://regengine.co/sandbox',
type: 'website',
@@ -37,7 +37,7 @@ export default function SandboxPage() {
RegEngine's stateless CSV evaluation endpoint is part of the experimental router
- surface and is turned off here. Nothing is broken on your end — the feature simply is
+ surface and is turned off here. Nothing is broken on your end; the feature simply is
not switched on for this environment.
diff --git a/frontend/src/app/settings/profile/page.tsx b/frontend/src/app/settings/profile/page.tsx
index 7e6310985..f19a8cc11 100644
--- a/frontend/src/app/settings/profile/page.tsx
+++ b/frontend/src/app/settings/profile/page.tsx
@@ -222,7 +222,7 @@ export default function ProfileSettingsPage() {
Upload New Picture
- Coming soon — JPG, PNG or GIF. Max size 2MB.
+ Coming soon: JPG, PNG or GIF. Max size 2MB.
diff --git a/frontend/src/app/settings/security/page.tsx b/frontend/src/app/settings/security/page.tsx
index 62e08a1a4..ff73cf73c 100644
--- a/frontend/src/app/settings/security/page.tsx
+++ b/frontend/src/app/settings/security/page.tsx
@@ -108,7 +108,7 @@ export default function SecuritySettingsPage() {
- You sign in with an email code or a passkey — there is no password to manage.
+ You sign in with an email code or a passkey. There is no password to manage.
Use a passkey when prompted for high-assurance routes.
{traceResult.tlc_code}
{traceResult.product_description && (
- — {traceResult.product_description}
+ ({traceResult.product_description})
)}
diff --git a/frontend/src/app/verify/page.tsx b/frontend/src/app/verify/page.tsx
index e66324e49..40ffa4d18 100644
--- a/frontend/src/app/verify/page.tsx
+++ b/frontend/src/app/verify/page.tsx
@@ -83,7 +83,7 @@ const TRUST_MODEL = [
{
Icon: FileCode,
title: 'Open Source',
- desc: 'The verification script is Apache 2.0-licensed. Read every line. Fork it. Modify it. You don\'t need to trust us — you can verify the math yourself.',
+ desc: 'The verification script is Apache 2.0-licensed. Read every line. Fork it. Modify it. You don\'t need to trust us. You can verify the math yourself.',
},
{
Icon: ShieldCheck,
@@ -245,8 +245,8 @@ function VerifyWidget() {
title={file ? file.name : 'Drop your export bundle here'}
description={
file
- ? `${(file.size / 1024).toFixed(1)} KB — click to choose a different file`
- : 'or click to browse — accepts .zip or .json'
+ ? `${(file.size / 1024).toFixed(1)} KB. Click to choose a different file`
+ : 'or click to browse (accepts .zip or .json)'
}
className={cn(
'transition-colors duration-120 motion-reduce:transition-none',
@@ -412,7 +412,7 @@ export default function VerifyPage() {
Every public RegEngine proof bundle carries a{' '}
SHA-256 manifest and Merkle root .
Our open-source verification script lets you independently check that
- the bundle is consistent with its own manifest — without relying on our servers.
+ the bundle is consistent with its own manifest, without relying on our servers.
It does not authenticate who published the bundle.
@@ -451,12 +451,12 @@ export default function VerifyPage() {
Your file is sent to a public verifier endpoint that runs the same algorithm
- as the export pipeline — no auth, no email capture. Want to verify entirely
+ as the export pipeline: no auth, no email capture. Want to verify entirely
offline?{' '}
Download verify_chain.py
{' '}
- and run it locally — same algorithm, zero network.
+ and run it locally: same algorithm, zero network.
What this does not prove. {' '}
@@ -513,7 +513,7 @@ export default function VerifyPage() {
- verify_chain.py — bash
+ verify_chain.py (bash)
@@ -636,7 +636,7 @@ export default function VerifyPage() {
RegEngine adds hash-based consistency checks on top of standard compliance controls.
- SHA-256 hashing lets you confirm a bundle matches its own manifest independently —
+ SHA-256 hashing lets you confirm a bundle matches its own manifest independently,
whether or not you require a SOC 2 report. It is not a signature and does not
authenticate the publisher.
diff --git a/frontend/src/app/why-regengine/page.tsx b/frontend/src/app/why-regengine/page.tsx
index 157ae2363..11ca22927 100644
--- a/frontend/src/app/why-regengine/page.tsx
+++ b/frontend/src/app/why-regengine/page.tsx
@@ -42,7 +42,7 @@ interface ComparisonRow {
const COMPARISON_DATA: ComparisonRow[] = [
{
- feature: 'REST API + Webhooks',
+ feature: 'CSV upload + JSON events API',
regengine: true,
trustwell: false,
safetychain: false,
@@ -70,7 +70,7 @@ const COMPARISON_DATA: ComparisonRow[] = [
repositrak: 'Verify with vendor',
},
{
- feature: 'EPCIS 2.0 Native',
+ feature: 'EPCIS 2.0 export',
regengine: true,
trustwell: 'Verify with vendor',
safetychain: 'Verify with vendor',
@@ -132,7 +132,7 @@ const DIFFERENTIATORS = [
icon: Code2,
title: 'API-First Architecture',
description:
- 'REST APIs, webhooks, and CSV templates. Integrate RegEngine with your existing ERP, WMS, or custom systems. No rip-and-replace required.',
+ 'CSV upload, a JSON events API, and EPCIS export. Integrate RegEngine with your existing ERP, WMS, or custom systems. No rip-and-replace required.',
detail: 'Technical teams can be live in hours. Sales ops teams use our CSV templates. Everyone gets FSMA 204 compliance their way.',
},
{
@@ -158,9 +158,9 @@ const DIFFERENTIATORS = [
},
{
icon: Workflow,
- title: 'EPCIS 2.0 Native',
+ title: 'EPCIS 2.0 export',
description:
- "EPCIS 2.0 support for trading-partner interoperability. Verify each enabled workflow against your retailer and buyer requirements.",
+ "EPCIS 2.0 export for trading-partner interoperability. Verify each enabled workflow against your retailer and buyer requirements.",
detail: 'We started on EPCIS 2.0; verify EPCIS coverage with each vendor for your stack.',
},
{
@@ -582,7 +582,7 @@ HTTP 201
- EPCIS 2.0 Native
+ EPCIS 2.0 export
EPCIS 2.0 can support trading-partner interoperability. RegEngine treats EPCIS 2.0 as a supported schema where the enabled workflow and source data allow it.
diff --git a/frontend/src/components/dashboard/metrics-overview-widget.tsx b/frontend/src/components/dashboard/metrics-overview-widget.tsx
index 06d133226..772d6a6a0 100644
--- a/frontend/src/components/dashboard/metrics-overview-widget.tsx
+++ b/frontend/src/components/dashboard/metrics-overview-widget.tsx
@@ -46,7 +46,7 @@ export function MetricsOverviewWidget({
empty={!isLoading && score <= 0}
emptyCaption={
servicesDown
- ? "No data — services unreachable"
+ ? "No data: services unreachable"
: "No saved Inflow Workbench run yet"
}
status={
diff --git a/frontend/src/components/fsma-checklist.tsx b/frontend/src/components/fsma-checklist.tsx
index 2ffdb45c2..1b1ea90fe 100644
--- a/frontend/src/components/fsma-checklist.tsx
+++ b/frontend/src/components/fsma-checklist.tsx
@@ -43,7 +43,7 @@ const checklistItems = [
id: "kdes",
title: "All KDEs populated",
description: "Key Data Elements recorded for each Critical Tracking Event type",
- regulation: "21 CFR §§ 1.1325–1.1350",
+ regulation: "21 CFR §§ 1.1325 to 1.1350",
url: "https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-1/subpart-S/section-1.1325",
},
{
@@ -162,7 +162,7 @@ export default function FSMAChecklist() {
Check off each FSMA 204 requirement your company currently meets.
- Be honest — gaps are fixable, surprises during an FDA audit aren't.
+ Be honest: gaps are fixable, surprises during an FDA audit aren't.
diff --git a/frontend/src/components/fsma/readiness-assessment.tsx b/frontend/src/components/fsma/readiness-assessment.tsx
index 955621bcf..ebb5ca11f 100644
--- a/frontend/src/components/fsma/readiness-assessment.tsx
+++ b/frontend/src/components/fsma/readiness-assessment.tsx
@@ -40,9 +40,9 @@ const FTL_CATEGORIES = [
{ id: 'sprouts', name: 'Sprouts', examples: 'Alfalfa, bean, broccoli sprouts', icon: Leaf },
{ id: 'fresh-cut-fruits', name: 'Fresh-Cut Fruits', examples: 'Pre-cut fruit mixes, fruit cups', icon: Package },
{ id: 'fresh-cut-vegetables', name: 'Fresh-Cut Vegetables (non-leafy)', examples: 'Veggie trays, pre-cut carrots, celery sticks, broccoli florets', icon: Package },
- { id: 'finfish-histamine', name: 'Finfish — Scombrotoxin/Histamine-Forming', examples: 'Tuna, mackerel, mahi-mahi, bluefish, amberjack', icon: Package },
- { id: 'finfish-ciguatoxin', name: 'Finfish — Ciguatoxin-Associated', examples: 'Barracuda, grouper, snapper, moray eel', icon: Package },
- { id: 'finfish-other', name: 'Finfish — Other (fresh/frozen)', examples: 'Salmon, cod, halibut, tilapia, trout', icon: Package },
+ { id: 'finfish-histamine', name: 'Finfish (Scombrotoxin/Histamine-Forming)', examples: 'Tuna, mackerel, mahi-mahi, bluefish, amberjack', icon: Package },
+ { id: 'finfish-ciguatoxin', name: 'Finfish (Ciguatoxin-Associated)', examples: 'Barracuda, grouper, snapper, moray eel', icon: Package },
+ { id: 'finfish-other', name: 'Finfish, Other (fresh/frozen)', examples: 'Salmon, cod, halibut, tilapia, trout', icon: Package },
{ id: 'finfish-smoked', name: 'Smoked Finfish', examples: 'Smoked salmon, lox, kippered herring, smoked trout', icon: Package },
{ id: 'crustaceans', name: 'Crustaceans', examples: 'Shrimp, crab, lobster, crawfish', icon: Package },
{ id: 'molluscan-shellfish', name: 'Molluscan Shellfish (bivalves)', examples: 'Oysters, clams, mussels, scallops', icon: Package },
@@ -59,7 +59,7 @@ const CTES = [
{ id: 'harvesting', name: 'Harvesting (§1.1325)', description: 'Harvesting of raw agricultural commodities' },
{ id: 'cooling', name: 'Cooling (§1.1325)', description: 'Cooling of an RAC before initial packing (combined with Harvesting in §1.1325)' },
{ id: 'initial_packing', name: 'Initial Packing (§1.1330)', description: 'Initial packing of a raw agricultural commodity (other than food obtained from a fishing vessel)' },
- { id: 'first_receiver', name: 'First Land-Based Receiving (§1.1335) — Seafood', description: 'First land-based receipt of food obtained directly from a fishing vessel. Applies only to seafood obtained from a fishing vessel — non-seafood importers perform §1.1345 Receiving, not FLBR.' },
+ { id: 'first_receiver', name: 'First Land-Based Receiving, Seafood (§1.1335)', description: 'First land-based receipt of food obtained directly from a fishing vessel. Applies only to seafood obtained from a fishing vessel. Non-seafood importers perform §1.1345 Receiving, not FLBR.' },
{ id: 'shipping', name: 'Shipping (§1.1340)', description: 'Sending food from one location to another' },
{ id: 'receiving', name: 'Receiving (§1.1345)', description: 'Receipt of food at a facility. Subject to the §1.1305(j) exemption for restaurants and retail food establishments selling food directly to consumers.' },
{ id: 'transformation', name: 'Transformation (§1.1350)', description: 'Manufacturing, processing, or changing a food into a new traceability lot' },
@@ -439,7 +439,7 @@ export function FSMA204Assessment() {
{!systemAnswers['24hr'] && (
-
Gap indicated: ability to produce records within 24 hours of an FDA request — review your retrieval workflow.
+
Gap indicated: ability to produce records within 24 hours of an FDA request. Review your retrieval workflow.
)}
{!systemAnswers['testing'] && (
diff --git a/frontend/src/components/marketing/sandbox-grid/SandboxPdfReport.ts b/frontend/src/components/marketing/sandbox-grid/SandboxPdfReport.ts
index b649bc6dc..029a88c5c 100644
--- a/frontend/src/components/marketing/sandbox-grid/SandboxPdfReport.ts
+++ b/frontend/src/components/marketing/sandbox-grid/SandboxPdfReport.ts
@@ -163,7 +163,7 @@ export function generateComplianceReport(result: SandboxResult): void {
doc.setFontSize(9);
doc.setTextColor(DANGER.r, DANGER.g, DANGER.b);
doc.text(
- `IMPORT MAPPING NEEDS CORRECTION \u2014 ${result.blocking_reasons.length} blocker${result.blocking_reasons.length !== 1 ? 's' : ''}`,
+ `IMPORT MAPPING NEEDS CORRECTION: ${result.blocking_reasons.length} blocker${result.blocking_reasons.length !== 1 ? 's' : ''}`,
margin + 4, y + 6,
);
doc.setFont('helvetica', 'normal');
@@ -333,7 +333,7 @@ export function generateComplianceReport(result: SandboxResult): void {
doc.setFont('helvetica', 'normal');
doc.setFontSize(7);
doc.setTextColor(GRAY.r, GRAY.g, GRAY.b);
- doc.text('Generated by RegEngine \u2014 www.regengine.co', margin, pageH - 9);
+ doc.text('Generated by RegEngine (www.regengine.co)', margin, pageH - 9);
doc.text(`Page ${p} of ${totalPages}`, pageWidth - margin, pageH - 9, { align: 'right' });
doc.setFontSize(7);
doc.setTextColor(BRAND.r, BRAND.g, BRAND.b);
diff --git a/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx b/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
index 4ef5c8ff5..3778a1561 100644
--- a/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
+++ b/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
@@ -190,7 +190,7 @@ export function SandboxResultView({
{result.submission_blocked && (
- TEST RUN NEEDS CORRECTION — {result.blocking_reasons.length} blocker{result.blocking_reasons.length !== 1 ? 's' : ''}
+ TEST RUN NEEDS CORRECTION: {result.blocking_reasons.length} blocker{result.blocking_reasons.length !== 1 ? 's' : ''}
{result.blocking_reasons.slice(0, 10).map((reason, i) => (
@@ -206,7 +206,7 @@ export function SandboxResultView({
{!result.submission_blocked && result.non_compliant_events === 0 && (
- SANDBOX CHECKS CLEAR — ready to save as a test run
+ SANDBOX CHECKS CLEAR: ready to save as a test run
)}
diff --git a/frontend/src/components/mobile/BarcodeScanner.tsx b/frontend/src/components/mobile/BarcodeScanner.tsx
index ff34b349c..0c38a9c6a 100644
--- a/frontend/src/components/mobile/BarcodeScanner.tsx
+++ b/frontend/src/components/mobile/BarcodeScanner.tsx
@@ -167,7 +167,7 @@ export function BarcodeScanner({ onScan, onError }: BarcodeScannerProps) {
Supports QR (GS1 Digital Link), GS1-128, DataMatrix, EAN-13, and UPC-A.
- {continuous ? ' Keep scanning — each new code is captured automatically.' : ' Ensure good lighting and hold steady.'}
+ {continuous ? ' Keep scanning. Each new code is captured automatically.' : ' Ensure good lighting and hold steady.'}
);
diff --git a/frontend/src/components/mobile/FieldCaptureClient.tsx b/frontend/src/components/mobile/FieldCaptureClient.tsx
index 8d3e9a48c..0580a6723 100644
--- a/frontend/src/components/mobile/FieldCaptureClient.tsx
+++ b/frontend/src/components/mobile/FieldCaptureClient.tsx
@@ -333,12 +333,12 @@ export function FieldCaptureClient() {
toast({
title: 'Label Analyzed & Ingested',
- description: `${productName} — ${visionData.fsma_kdes?.length || 0} KDEs extracted`,
+ description: `${productName}: ${visionData.fsma_kdes?.length || 0} KDEs extracted`,
});
} else {
// Vision failed — fall back to raw file upload
await ingestFileMutation.mutateAsync({ file, sourceSystem: 'mobile_capture_pwa' });
- toast({ title: 'Photo Uploaded', description: 'Vision analysis unavailable — raw image stored.' });
+ toast({ title: 'Photo Uploaded', description: 'Vision analysis unavailable. Raw image stored.' });
}
} catch {
await savePhoto(blob);
diff --git a/frontend/src/components/ui/data-table.tsx b/frontend/src/components/ui/data-table.tsx
index a11b1012e..2525192cf 100644
--- a/frontend/src/components/ui/data-table.tsx
+++ b/frontend/src/components/ui/data-table.tsx
@@ -240,7 +240,7 @@ export function DataTable({
{pagination && status === "idle" && data.length > 0 && (
- {(pagination.page - 1) * pagination.pageSize + 1}–
+ {(pagination.page - 1) * pagination.pageSize + 1} to{' '}
{Math.min(pagination.page * pagination.pageSize, pagination.total)} of {pagination.total}
diff --git a/frontend/src/lib/api-config.ts b/frontend/src/lib/api-config.ts
index 966a1a5d1..045b310b6 100644
--- a/frontend/src/lib/api-config.ts
+++ b/frontend/src/lib/api-config.ts
@@ -25,7 +25,7 @@ export function getServerServiceURL(service: ServiceName): string {
if (process.env.VERCEL) {
console.error(
- `[api-config] ${service.toUpperCase()}_SERVICE_URL not configured — local dev fallback is unreachable from Vercel`,
+ `[api-config] ${service.toUpperCase()}_SERVICE_URL not configured; local dev fallback is unreachable from Vercel`,
);
return '';
}
diff --git a/frontend/src/lib/api-proxy.ts b/frontend/src/lib/api-proxy.ts
index 55de259ce..06f04a126 100644
--- a/frontend/src/lib/api-proxy.ts
+++ b/frontend/src/lib/api-proxy.ts
@@ -260,7 +260,7 @@ export function requireProxyAuth(request: NextRequest): NextResponse | null {
}
return NextResponse.json(
- { error: 'Unauthorized — no valid credentials provided' },
+ { error: 'Unauthorized: no valid credentials provided' },
{ status: 401 },
);
}
@@ -374,7 +374,7 @@ export async function validateProxySession(
const tokenPayload = decodeRegEngineClaims(regengineToken);
if (!tokenPayload) {
return NextResponse.json(
- { error: 'Session expired or invalid — please log in again' },
+ { error: 'Session expired or invalid. Please log in again' },
{ status: 401 },
);
}
@@ -419,7 +419,7 @@ export async function validateProxySession(
if (!hasSupabaseCookies) {
if (options.requireSupabaseSession) {
return NextResponse.json(
- { error: 'Session expired or invalid — please log in again' },
+ { error: 'Session expired or invalid. Please log in again' },
{ status: 401 },
);
}
@@ -452,14 +452,14 @@ export async function validateProxySession(
if (error || !user) {
return NextResponse.json(
- { error: 'Session expired or invalid — please log in again' },
+ { error: 'Session expired or invalid. Please log in again' },
{ status: 401 },
);
}
} catch {
if (options.requireSupabaseSession) {
return NextResponse.json(
- { error: 'Session expired or invalid — please log in again' },
+ { error: 'Session expired or invalid. Please log in again' },
{ status: 401 },
);
}
@@ -482,7 +482,7 @@ export async function validateProxySession(
*/
export function staticExportGuard(serviceName: string): NextResponse | null {
if (process.env.REGENGINE_DEPLOY_MODE === 'static') {
- console.error(`[proxy/${serviceName}] 503 — proxy unavailable in static export mode`);
+ console.error(`[proxy/${serviceName}] 503: proxy unavailable in static export mode`);
return proxyError(`${serviceName} proxy unavailable in static export mode`, 503);
}
return null;
diff --git a/frontend/src/lib/auth-context.tsx b/frontend/src/lib/auth-context.tsx
index 3c218aa5e..b22ecc629 100644
--- a/frontend/src/lib/auth-context.tsx
+++ b/frontend/src/lib/auth-context.tsx
@@ -215,7 +215,7 @@ async function migrateLocalStorageToCookies(): Promise
{
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
- console.info('[auth] Migration complete — localStorage secrets removed.');
+ console.info('[auth] Migration complete; localStorage secrets removed.');
}
}
diff --git a/frontend/src/lib/csrf.ts b/frontend/src/lib/csrf.ts
index d185867a0..ac87643d4 100644
--- a/frontend/src/lib/csrf.ts
+++ b/frontend/src/lib/csrf.ts
@@ -34,7 +34,7 @@ function getSecret(): string {
const secret = process.env.CSRF_SECRET || '';
if (!secret) {
if (process.env.NODE_ENV === 'production') {
- console.error('[csrf] CSRF_SECRET not set in production — all mutating requests will be rejected');
+ console.error('[csrf] CSRF_SECRET not set in production; all mutating requests will be rejected');
return '';
}
return process.env.AUTH_SECRET_KEY || '';
@@ -79,7 +79,7 @@ export async function verifyCsrfToken(token: string, signature: string): Promise
const secret = getSecret();
if (!secret) {
if (process.env.NODE_ENV === 'production') {
- console.error('[csrf] CSRF_SECRET / AUTH_SECRET_KEY not set — rejecting mutating request');
+ console.error('[csrf] CSRF_SECRET / AUTH_SECRET_KEY not set; rejecting mutating request');
return false;
}
return true;
diff --git a/frontend/src/lib/customer-readiness.ts b/frontend/src/lib/customer-readiness.ts
index 645cf7aa4..6ab407849 100644
--- a/frontend/src/lib/customer-readiness.ts
+++ b/frontend/src/lib/customer-readiness.ts
@@ -486,7 +486,7 @@ export const MAPPING_REVIEW_ITEMS: MappingReviewItem[] = [
},
{
id: 'map_case_005',
- source: 'EDI 856 ASN',
+ source: 'JSON events API',
sourceField: 'Case Count',
mappedField: null,
status: 'needs_review',
diff --git a/frontend/src/lib/fsma-enforcement.ts b/frontend/src/lib/fsma-enforcement.ts
index 3d261a803..a09861412 100644
--- a/frontend/src/lib/fsma-enforcement.ts
+++ b/frontend/src/lib/fsma-enforcement.ts
@@ -7,4 +7,4 @@
export const FSMA_ENFORCEMENT_DATE = 'July 20, 2028';
export const FSMA_ENFORCEMENT_FRAMING =
- 'FDA has been directed by Congress not to enforce the Food Traceability Rule before July 20, 2028, and has stated it intends to comply — the requirements are unchanged, only enforcement moved.';
+ 'FDA has been directed by Congress not to enforce the Food Traceability Rule before July 20, 2028, and has stated it intends to comply. The requirements are unchanged; only enforcement moved.';
diff --git a/frontend/src/lib/ftl-data.ts b/frontend/src/lib/ftl-data.ts
index 1b6b697bd..e887fe72d 100644
--- a/frontend/src/lib/ftl-data.ts
+++ b/frontend/src/lib/ftl-data.ts
@@ -146,7 +146,7 @@ export const FTL_CATEGORIES: FTLCategory[] = [
},
{
id: 'finfish-histamine',
- name: 'Finfish — Scombrotoxin/Histamine-Forming',
+ name: 'Finfish (Scombrotoxin/Histamine-Forming)',
category: 'Seafood',
examples: 'Tuna, mackerel, mahi-mahi, bluefish, amberjack, bonito',
exclusions: 'Catfish (Siluriformes) are USDA-regulated and excluded per §1.1305(g)',
@@ -158,7 +158,7 @@ export const FTL_CATEGORIES: FTLCategory[] = [
},
{
id: 'finfish-ciguatoxin',
- name: 'Finfish — Ciguatoxin-Associated',
+ name: 'Finfish (Ciguatoxin-Associated)',
category: 'Seafood',
examples: 'Barracuda, grouper, snapper, moray eel (tropical reef species)',
exclusions: 'Catfish (Siluriformes) are USDA-regulated and excluded per §1.1305(g)',
@@ -170,7 +170,7 @@ export const FTL_CATEGORIES: FTLCategory[] = [
},
{
id: 'finfish-other',
- name: 'Finfish — Other (fresh/frozen/previously frozen)',
+ name: 'Finfish, Other (fresh/frozen/previously frozen)',
category: 'Seafood',
examples: 'Salmon, cod, halibut, tilapia, trout, bass, swordfish',
exclusions: 'Catfish (Siluriformes) are USDA-regulated and excluded per §1.1305(g)',
diff --git a/frontend/src/lib/proxy-factory.ts b/frontend/src/lib/proxy-factory.ts
index 6ab7d3c1a..b0fdbcb8c 100644
--- a/frontend/src/lib/proxy-factory.ts
+++ b/frontend/src/lib/proxy-factory.ts
@@ -138,7 +138,7 @@ export function createJsonProxy(config: JsonProxyConfig): MethodHandlers {
const queryString = new URL(request.url).search;
const targetUrl = config.buildTargetUrl(path, queryString, request);
if (!targetUrl) {
- console.error(`[proxy/${config.serviceName}] 503 — backend not configured`);
+ console.error(`[proxy/${config.serviceName}] 503: backend not configured`);
return proxyError(`${config.serviceName} backend not configured`, 503);
}
@@ -179,7 +179,7 @@ export function createJsonProxy(config: JsonProxyConfig): MethodHandlers {
if (!response.ok) {
const detail = extractDetail(data);
if (response.status >= 500) {
- console.error(`[proxy/${config.serviceName}] ${response.status} — upstream request failed`, {
+ console.error(`[proxy/${config.serviceName}] ${response.status}: upstream request failed`, {
targetUrl,
detail: data,
});
@@ -196,7 +196,7 @@ export function createJsonProxy(config: JsonProxyConfig): MethodHandlers {
}
return NextResponse.json(data);
} catch (error: unknown) {
- console.error(`[proxy/${config.serviceName}] 500 — proxy request failed`, { error });
+ console.error(`[proxy/${config.serviceName}] 500: proxy request failed`, { error });
return proxyError(`${config.serviceName} request failed`, 500);
}
};
@@ -369,7 +369,7 @@ export function createStreamProxy(config: StreamProxyConfig): MethodHandlers {
const queryString = new URL(request.url).search;
const bases = config.resolveTargetBases();
if (bases.length === 0) {
- console.error(`[proxy/${config.serviceName}] 503 — no upstream targets configured`);
+ console.error(`[proxy/${config.serviceName}] 503: no upstream targets configured`);
return proxyError(`${config.serviceName} backend not configured`, 503);
}
@@ -413,7 +413,7 @@ export function createStreamProxy(config: StreamProxyConfig): MethodHandlers {
}
if (response.status >= 500) {
- console.error(`[proxy/${config.serviceName}] ${response.status} — upstream request failed`, {
+ console.error(`[proxy/${config.serviceName}] ${response.status}: upstream request failed`, {
targetUrl,
upstreamError: await readUpstreamErrorForLog(response),
});
@@ -446,10 +446,10 @@ export function createStreamProxy(config: StreamProxyConfig): MethodHandlers {
}
}
- console.error(`[proxy/${config.serviceName}] 502 — all targets failed:`, attemptErrors);
+ console.error(`[proxy/${config.serviceName}] 502: all targets failed:`, attemptErrors);
return proxyError(`Unable to reach ${config.serviceName} service`, 502);
} catch (error: unknown) {
- console.error(`[proxy/${config.serviceName}] 500 — proxy request failed`, { error });
+ console.error(`[proxy/${config.serviceName}] 500: proxy request failed`, { error });
return proxyError(`${config.serviceName} request failed`, 500);
}
};
diff --git a/frontend/src/lib/roi-calculator-data.ts b/frontend/src/lib/roi-calculator-data.ts
index 899442a96..456b9cc71 100644
--- a/frontend/src/lib/roi-calculator-data.ts
+++ b/frontend/src/lib/roi-calculator-data.ts
@@ -54,7 +54,7 @@ export const ROI_CALCULATOR_CONFIG: ToolConfig = {
],
leadGate: {
title: 'Your Illustrative Savings Estimate is Ready',
- description: 'Enter your work email to see the illustrative breakdown. The numbers are not a forecast or commitment — book a call to model against your actual record volume.',
+ description: 'Enter your work email to see the illustrative breakdown. The numbers are not a forecast or commitment. Book a call to model against your actual record volume.',
cta: 'View My Estimate'
}
}
From 1def2639bd2f80ee4db8881ec424066eb39f0257 Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:41:19 -0700
Subject: [PATCH 3/8] docs(frontend): label EPCIS intake as Preview sitewide
and restore receiving location_name
Signed-off-by: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
---
frontend/src/__tests__/lib/epcis-upload.test.ts | 2 +-
frontend/src/__tests__/pages/homepage.test.tsx | 2 +-
frontend/src/app/dashboard/receiving/page.tsx | 2 +-
frontend/src/app/dashboard/settings/page.tsx | 2 +-
frontend/src/app/docs/authentication/page.tsx | 2 +-
frontend/src/app/docs/walkthrough/page.tsx | 2 +-
frontend/src/app/fsma/integration/page.tsx | 2 +-
frontend/src/app/ingest/page.tsx | 5 +++--
frontend/src/app/integrations/page.tsx | 6 +++---
frontend/src/app/page.tsx | 2 +-
frontend/src/app/pricing/page.tsx | 2 +-
frontend/src/app/product/page.tsx | 2 +-
frontend/src/app/trust/architecture/page.tsx | 2 +-
frontend/src/lib/customer-readiness.ts | 2 +-
frontend/src/lib/epcis-upload.ts | 2 +-
15 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/frontend/src/__tests__/lib/epcis-upload.test.ts b/frontend/src/__tests__/lib/epcis-upload.test.ts
index 799d71410..816779618 100644
--- a/frontend/src/__tests__/lib/epcis-upload.test.ts
+++ b/frontend/src/__tests__/lib/epcis-upload.test.ts
@@ -82,6 +82,6 @@ describe('epcisErrorMessage', () => {
it('falls back to the error message and then to a default', () => {
expect(epcisErrorMessage(new Error('Network Error'))).toBe('Network Error');
- expect(epcisErrorMessage(null)).toBe('EPCIS upload failed');
+ expect(epcisErrorMessage(null)).toBe('EPCIS upload (Preview) failed');
});
});
diff --git a/frontend/src/__tests__/pages/homepage.test.tsx b/frontend/src/__tests__/pages/homepage.test.tsx
index c91cb7985..b210303a9 100644
--- a/frontend/src/__tests__/pages/homepage.test.tsx
+++ b/frontend/src/__tests__/pages/homepage.test.tsx
@@ -13,7 +13,7 @@ describe("HomePage Compliance OS foundation", () => {
}),
).toBeInTheDocument();
expect(
- screen.getByText(/ingest supply-chain data through csv upload or the json events api\. epcis, edi, and sftp intake are on the roadmap\./i),
+ screen.getByText(/ingest supply-chain data through csv upload or the json events api\. epcis intake is in preview; edi and sftp intake are on the roadmap\./i),
).toBeInTheDocument();
});
diff --git a/frontend/src/app/dashboard/receiving/page.tsx b/frontend/src/app/dashboard/receiving/page.tsx
index 62f235314..acd4c70cd 100644
--- a/frontend/src/app/dashboard/receiving/page.tsx
+++ b/frontend/src/app/dashboard/receiving/page.tsx
@@ -244,7 +244,7 @@ export default function ReceivingDockPage() {
quantity: item.quantity,
unit_of_measure: 'cases',
timestamp: item.scannedAt || new Date().toISOString(),
- location_name: `Receiving Dock: ${session.supplier}`,
+ location_name: `Receiving Dock — ${session.supplier}`,
kdes: {
gtin: item.gtin || undefined,
lot_code: item.lotCode || undefined,
diff --git a/frontend/src/app/dashboard/settings/page.tsx b/frontend/src/app/dashboard/settings/page.tsx
index 415dedfe4..d6f5b159e 100644
--- a/frontend/src/app/dashboard/settings/page.tsx
+++ b/frontend/src/app/dashboard/settings/page.tsx
@@ -47,7 +47,7 @@ const INTEGRATIONS = [
{ id: 'netsuite', name: 'Oracle NetSuite', category: 'ERP', status: 'available', desc: 'Cloud ERP and financials' },
{ id: 'walmart', name: 'Walmart GDSN', category: 'Retailer', status: 'coming_soon', desc: 'Global Data Synchronization' },
{ id: 'kroger', name: 'Kroger 84.51\u00b0', category: 'Retailer', status: 'coming_soon', desc: 'Retailer data exchange' },
- { id: 'epcis', name: 'EPCIS 2.0 Gateway', category: 'Standards', status: 'available', desc: 'GS1 event format bridge' },
+ { id: 'epcis', name: 'EPCIS 2.0 Gateway', category: 'Standards', status: 'available', desc: 'GS1 event format bridge; ingest in Preview' },
{ id: 'webhook', name: 'Custom Webhooks', category: 'Custom', status: 'available', desc: 'Push events to your endpoints' },
];
/**
diff --git a/frontend/src/app/docs/authentication/page.tsx b/frontend/src/app/docs/authentication/page.tsx
index 568730062..25a1615c7 100644
--- a/frontend/src/app/docs/authentication/page.tsx
+++ b/frontend/src/app/docs/authentication/page.tsx
@@ -134,7 +134,7 @@ export default function AuthenticationDocsPage() {
Scopes limit which of the endpoints above a key can call. They are not a read-only guarantee: some other
operations on the RegEngine backend, for example compliance snapshots, SLA request updates, onboarding steps
- and the EPCIS intake endpoint (on the roadmap, not a live intake channel), accept any valid tenant key without checking a named scope. Treat every key as
+ and the EPCIS intake endpoint (in Preview), accept any valid tenant key without checking a named scope. Treat every key as
read-write for its workspace. Keep it on your server, never in client-side code, and ask RegEngine to
revoke it if it leaks.
diff --git a/frontend/src/app/docs/walkthrough/page.tsx b/frontend/src/app/docs/walkthrough/page.tsx
index f54b1fe6c..a30130931 100644
--- a/frontend/src/app/docs/walkthrough/page.tsx
+++ b/frontend/src/app/docs/walkthrough/page.tsx
@@ -208,7 +208,7 @@ head -20 lot-export.csv`}
{filterExperimentalToolLinks([
{ title: 'Try a Recall Drill', desc: 'Simulate an FDA recall request against the data you just posted', href: '/dashboard/recall-drills' },
{ title: 'CSV Bulk Ingest', desc: 'Upload a real supplier CSV through Inflow Workbench preflight', href: '/tools/inflow-lab' },
- { title: 'EPCIS and EDI intake (on the roadmap)', desc: 'Planned connectors for your existing system-of-record. Today, use CSV upload or the JSON events API', href: '/docs/connectors/inflow-lab' },
+ { title: 'EPCIS intake (Preview) and EDI intake (on the roadmap)', desc: 'EPCIS upload is in Preview on the Ingest page; EDI connectors are planned. Live intake today is CSV upload or the JSON events API', href: '/docs/connectors/inflow-lab' },
]).map(({ title, desc, href }) => (
API & EPCIS 2.0
- For enterprise systems (SAP, Oracle, NetSuite). Push events directly to our endpoints via Webhooks or standard GS1 EPCIS 2.0 XML/JSON payloads.
+ For enterprise systems (SAP, Oracle, NetSuite). Push events directly to our endpoints via the JSON events API; GS1 EPCIS 2.0 XML/JSON upload is in Preview.
diff --git a/frontend/src/app/ingest/page.tsx b/frontend/src/app/ingest/page.tsx
index 1606d97dd..b5dc1b2e2 100644
--- a/frontend/src/app/ingest/page.tsx
+++ b/frontend/src/app/ingest/page.tsx
@@ -421,7 +421,7 @@ export default function IngestPage() {
const demoBanner = (
- Simulated walkthrough — sample output
+ Simulated walkthrough: sample output
);
@@ -595,7 +595,7 @@ export default function IngestPage() {
URL Ingestion
File Upload
- EPCIS 2.0
+ EPCIS 2.0 Preview
@@ -678,6 +678,7 @@ export default function IngestPage() {
className="inline-flex w-fit items-center gap-1 text-ui font-medium text-re-text-primary"
>
Select EPCIS file
+ Preview
diff --git a/frontend/src/app/integrations/page.tsx b/frontend/src/app/integrations/page.tsx
index f3a93bd04..a2244ef06 100644
--- a/frontend/src/app/integrations/page.tsx
+++ b/frontend/src/app/integrations/page.tsx
@@ -31,10 +31,10 @@ import { cn } from "@/lib/utils";
export const metadata: Metadata = {
title: "Integrations: Supplier Data Intake | RegEngine",
description:
- "RegEngine accepts supplier data via CSV upload and the JSON events API, with custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS, EDI, and SFTP intake are on the roadmap.",
+ "RegEngine accepts supplier data via CSV upload and the JSON events API, with custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.",
openGraph: {
title: 'Integrations: Supplier Data Intake | RegEngine',
- description: 'CSV upload and JSON events API intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS, EDI, and SFTP intake are on the roadmap.',
+ description: 'CSV upload and JSON events API intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.',
url: 'https://regengine.co/integrations',
type: 'website',
},
@@ -119,7 +119,7 @@ export default function IntegrationsPage() {
Know which sources are ready, guided, or custom scoped.
- A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Live intake today is CSV upload and the JSON events API; EPCIS, EDI, and SFTP intake are on the roadmap. Inflow Lab is the simulator path for JSON events API demos and contract CI.
+ A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Live intake today is CSV upload and the JSON events API; EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap. Inflow Lab is the simulator path for JSON events API demos and contract CI.
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 8d7f86d10..176095d77 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -204,7 +204,7 @@ export default function HomePage() {
FSMA 204 recordkeeping for the Food Traceability Rule.
- Ingest supply-chain data through CSV upload or the JSON events API. EPCIS, EDI, and SFTP intake are on the roadmap. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
+ Ingest supply-chain data through CSV upload or the JSON events API. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
diff --git a/frontend/src/app/pricing/page.tsx b/frontend/src/app/pricing/page.tsx
index ba2adca9a..ed2c8d1c0 100644
--- a/frontend/src/app/pricing/page.tsx
+++ b/frontend/src/app/pricing/page.tsx
@@ -141,7 +141,7 @@ const FAQ: PricingFaqItem[] = [
{ q: 'Can I switch plans anytime?', a: 'Plan changes are handled under your executed order form or design-partner agreement. We scope upgrades, downgrades, facility count, and billing changes before applying them.' },
{ q: 'Do you offer annual billing?', a: 'Annual and monthly billing can be scoped during procurement. Pricing shown is indicative; the executed agreement controls final plan, billing period, and checkout availability.' },
{ q: 'Does my Founding rate ever change?', a: 'Your Founding rate is controlled by the executed order form or design-partner agreement, including renewal, scope, add-ons, taxes, and plan changes.' },
- { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: CSV upload, the JSON events API, or custom-scoped implementation. EPCIS, EDI, and SFTP intake are on the roadmap.' },
+ { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: CSV upload, the JSON events API, or custom-scoped implementation. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.' },
{ q: 'What if the FDA delays enforcement again?', a: 'Major retailers are already requiring traceability data from suppliers regardless of the FDA timeline. RegEngine gives you the tooling and records to support either trigger: the FDA rule or a retailer mandate.' },
{ q: 'Do I need this if I\'m a small farm?', a: 'FSMA 204 applies to entities on the Food Traceability List handling specific foods. Use our free FTL Checker to see if your products are covered.' },
{ q: 'Can I integrate with my existing ERP?', a: 'RegEngine accepts data via API, CSV upload, or scoped ERP integration. Guided onboarding is available for approved design-partner workspaces. Timeline, support, and commercial terms are confirmed during scoping.' },
diff --git a/frontend/src/app/product/page.tsx b/frontend/src/app/product/page.tsx
index 90964a209..64acb7df9 100644
--- a/frontend/src/app/product/page.tsx
+++ b/frontend/src/app/product/page.tsx
@@ -106,7 +106,7 @@ function InflowImpactDiagram() {
Raw supplier feed
- CSV, portal, API, EPCIS, or EDI-shaped records
+ CSV, portal, API, or EPCIS-shaped records (EPCIS in Preview)
diff --git a/frontend/src/app/trust/architecture/page.tsx b/frontend/src/app/trust/architecture/page.tsx
index fc1f6e855..f8f30757d 100644
--- a/frontend/src/app/trust/architecture/page.tsx
+++ b/frontend/src/app/trust/architecture/page.tsx
@@ -69,7 +69,7 @@ const DATA_FLOW_STEPS = [
{
step: '1',
title: 'Ingest',
- description: 'CTE events arrive via CSV upload or the JSON events API. Both paths run validation synchronously and persist before coverage checks. EPCIS, EDI, and SFTP intake are on the roadmap.',
+ description: 'CTE events arrive via CSV upload or the JSON events API. Both paths run validation synchronously and persist before coverage checks. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.',
},
{
step: '2',
diff --git a/frontend/src/lib/customer-readiness.ts b/frontend/src/lib/customer-readiness.ts
index 6ab407849..d0a22fe9e 100644
--- a/frontend/src/lib/customer-readiness.ts
+++ b/frontend/src/lib/customer-readiness.ts
@@ -315,7 +315,7 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
status: 'export_supported',
delivery_mode: 'export_only',
integration_type: 'one_way_export',
- customer_copy: 'JSON-LD EPCIS export is supported. EPCIS ingest is on the roadmap. Default deployments use PostgreSQL-backed task processing; legacy Kafka-compatible signing is opt-in.',
+ customer_copy: 'JSON-LD EPCIS export is supported. EPCIS ingest is in Preview. Default deployments use PostgreSQL-backed task processing; legacy Kafka-compatible signing is opt-in.',
evidence_url: '/developers',
},
{
diff --git a/frontend/src/lib/epcis-upload.ts b/frontend/src/lib/epcis-upload.ts
index 181cc9104..fda18c2d6 100644
--- a/frontend/src/lib/epcis-upload.ts
+++ b/frontend/src/lib/epcis-upload.ts
@@ -122,5 +122,5 @@ export function epcisErrorMessage(error: unknown): string {
if (fromDetail) return fromDetail;
if (error.message) return error.message;
}
- return 'EPCIS upload failed';
+ return 'EPCIS upload (Preview) failed';
}
From 7e9ecfa6fe5125b1d156d21467bac1bab7644ae8 Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:46:43 -0700
Subject: [PATCH 4/8] chore: trigger preview build
From a7064e70eed546bb63712c2205be1a024454979b Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:46:56 -0700
Subject: [PATCH 5/8] chore: trigger preview build
From b75c249ad0339e74a109cf69de237891efad131d Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 22:47:15 -0700
Subject: [PATCH 6/8] chore: trigger preview build
From 5f46c5b6ec9b46398dc4d0a8442caf936b1fb222 Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Thu, 22 Oct 2026 23:29:58 -0700
Subject: [PATCH 7/8] docs(frontend): limit live intake to CSV and JSON events
API, label EPCIS ingest Preview, add empty-value constants
---
frontend/src/__tests__/pages/homepage.test.tsx | 2 +-
frontend/src/app/audit/page.tsx | 3 ++-
frontend/src/app/dashboard/compliance/page.tsx | 3 ++-
frontend/src/app/dashboard/heartbeat/page.tsx | 3 ++-
frontend/src/app/dashboard/integrations/page.tsx | 9 ++++-----
frontend/src/app/dashboard/issues/page.tsx | 3 ++-
frontend/src/app/dashboard/recall-report/page.tsx | 7 ++++---
frontend/src/app/dashboard/receiving/page.tsx | 7 ++++---
frontend/src/app/dashboard/settings/page.tsx | 6 ++++--
frontend/src/app/dashboard/suppliers/page.tsx | 3 ++-
frontend/src/app/docs/api/ApiReferenceClient.tsx | 4 ++--
frontend/src/app/docs/api/page.tsx | 4 ++--
frontend/src/app/docs/page.tsx | 2 +-
frontend/src/app/docs/walkthrough/page.tsx | 2 +-
frontend/src/app/docs/webhooks/page.tsx | 10 +++++-----
frontend/src/app/fsma/page.tsx | 7 ++++---
frontend/src/app/ingest/page.tsx | 5 ++---
frontend/src/app/integrations/page.tsx | 6 +++---
frontend/src/app/page.tsx | 2 +-
frontend/src/app/pricing/page.tsx | 2 +-
frontend/src/app/product/page.tsx | 2 +-
frontend/src/app/proof/page.tsx | 2 +-
frontend/src/app/remediation/page.tsx | 9 +++++----
frontend/src/app/rules/page.tsx | 5 +++--
.../data-import/components/DataImportClient.tsx | 10 +++++-----
frontend/src/app/tools/data-import/page.tsx | 10 +++++-----
frontend/src/app/tools/export/layout.tsx | 2 +-
frontend/src/app/tools/label-scanner/layout.tsx | 2 +-
frontend/src/app/tools/scan/layout.tsx | 2 +-
.../sop-generator/components/SOPGeneratorClient.tsx | 2 +-
frontend/src/app/trust/architecture/page.tsx | 2 +-
frontend/src/app/trust/page.tsx | 2 +-
frontend/src/app/why-regengine/page.tsx | 8 ++++----
frontend/src/components/ui/stat-tile.tsx | 3 ++-
frontend/src/lib/customer-readiness.ts | 12 +-----------
frontend/src/lib/empty-values.ts | 13 +++++++++++++
frontend/src/lib/public-openapi.ts | 8 ++++----
37 files changed, 99 insertions(+), 85 deletions(-)
create mode 100644 frontend/src/lib/empty-values.ts
diff --git a/frontend/src/__tests__/pages/homepage.test.tsx b/frontend/src/__tests__/pages/homepage.test.tsx
index b210303a9..a0044f6fa 100644
--- a/frontend/src/__tests__/pages/homepage.test.tsx
+++ b/frontend/src/__tests__/pages/homepage.test.tsx
@@ -13,7 +13,7 @@ describe("HomePage Compliance OS foundation", () => {
}),
).toBeInTheDocument();
expect(
- screen.getByText(/ingest supply-chain data through csv upload or the json events api\. epcis intake is in preview; edi and sftp intake are on the roadmap\./i),
+ screen.getByText(/send records by csv upload or the json events api\. epcis 2\.0 is in preview\./i),
).toBeInTheDocument();
});
diff --git a/frontend/src/app/audit/page.tsx b/frontend/src/app/audit/page.tsx
index 7e14b433a..4c2b5c8c0 100644
--- a/frontend/src/app/audit/page.tsx
+++ b/frontend/src/app/audit/page.tsx
@@ -21,6 +21,7 @@ import { experimentalFeaturesEnabled } from '@/lib/experimental-features';
import { useQuery } from '@tanstack/react-query';
import { Lock, Shield } from 'lucide-react';
+import { NOT_SET } from '@/lib/empty-values';
const INGESTION_API = '/api/ingestion';
@@ -115,7 +116,7 @@ function AuditReviewContent() {
mono: true,
width: '12rem',
cell: (rule) => (
-
{rule.citation_reference || '—'}
+
{rule.citation_reference || NOT_SET}
),
},
{
diff --git a/frontend/src/app/dashboard/compliance/page.tsx b/frontend/src/app/dashboard/compliance/page.tsx
index 2256832fa..f516e0fc4 100644
--- a/frontend/src/app/dashboard/compliance/page.tsx
+++ b/frontend/src/app/dashboard/compliance/page.tsx
@@ -33,6 +33,7 @@ import { useAuth } from '@/lib/auth-context';
import { useTenant } from '@/lib/tenant-context';
import { fetchComplianceScore, fetchWorkbenchReadinessSummary } from '@/lib/api-hooks';
import { experimentalFeaturesEnabled, filterExperimentalLinks } from '@/lib/experimental-features';
+import { NO_DATA_YET } from '@/lib/empty-values';
/* ── Types matching ComplianceScoreResponse from backend ── */
@@ -531,7 +532,7 @@ export default function ComplianceDashboardPage() {
- {workbenchSummary?.score ?? '—'}
+ {workbenchSummary?.score ?? NO_DATA_YET}
{workbenchSummary?.label ?? 'No saved preflight run yet'}
diff --git a/frontend/src/app/dashboard/heartbeat/page.tsx b/frontend/src/app/dashboard/heartbeat/page.tsx
index a559779c6..a6b99e8aa 100644
--- a/frontend/src/app/dashboard/heartbeat/page.tsx
+++ b/frontend/src/app/dashboard/heartbeat/page.tsx
@@ -37,6 +37,7 @@ import {
FileText,
ShieldCheck,
} from 'lucide-react';
+import { NO_DATA_YET } from '@/lib/empty-values';
// ── Types ──
@@ -686,7 +687,7 @@ function HeartbeatPageContent() {
0 ? 'good' : 'neutral'}
/>
inflow_lab'],
['Dashboard source', 'Tagged as Inflow Lab'],
];
@@ -100,7 +100,7 @@ const ROUTE_GUIDANCE = [
},
{
title: 'Inflow Lab',
- description: 'Run FSMA event simulations and webhook replay without mixing test traffic into normal imports.',
+ description: 'Run FSMA event simulations and event replay without mixing test traffic into normal imports.',
href: '/dashboard/inflow-lab',
icon: FlaskConical,
},
@@ -431,7 +431,7 @@ export default function DashboardIntegrationsPage() {
loading={profilesStatus === 'loading'}
>
- Reusable mappings for CSV, spreadsheet, API, EDI-style, and supplier portal feeds.
+ Reusable mappings for CSV, spreadsheet, API, and supplier portal feeds.
CSV
Spreadsheet
- EDI-style
- EPCIS
+ EPCIS (Preview)
API
Webhook
Supplier portal
diff --git a/frontend/src/app/dashboard/issues/page.tsx b/frontend/src/app/dashboard/issues/page.tsx
index fefc06dc2..aa1b2761e 100644
--- a/frontend/src/app/dashboard/issues/page.tsx
+++ b/frontend/src/app/dashboard/issues/page.tsx
@@ -27,6 +27,7 @@ import {
import { useAuth } from '@/lib/auth-context';
import { fetchWithCsrf } from '@/lib/fetch-with-csrf';
import { useTenant } from '@/lib/tenant-context';
+import { NOT_SET } from '@/lib/empty-values';
/* ── Types ── */
@@ -224,7 +225,7 @@ export default function IssuesPage() {
header: 'Citation',
width: '12rem',
mono: true,
- cell: (b) => b.citation ?? '—',
+ cell: (b) => b.citation ?? NOT_SET,
},
];
diff --git a/frontend/src/app/dashboard/recall-report/page.tsx b/frontend/src/app/dashboard/recall-report/page.tsx
index 48d608b74..8706e3cd8 100644
--- a/frontend/src/app/dashboard/recall-report/page.tsx
+++ b/frontend/src/app/dashboard/recall-report/page.tsx
@@ -36,6 +36,7 @@ import {
ChevronUp,
RefreshCw,
} from 'lucide-react';
+import { NOT_SET } from '@/lib/empty-values';
/* ── API Response Types ── */
@@ -114,8 +115,8 @@ const DEMO_TIMELINE = [
{ time: '08:42', label: '12 Lots Identified', desc: 'Forward trace mapped all downstream distribution; 3 supplier origins confirmed', icon: Package, done: true },
{ time: '09:15', label: 'Supplier Notifications Sent', desc: '3 suppliers contacted: Salinas Valley Farms, Pacific Coast Growers, FreshCut Processing', icon: Users, done: true },
{ time: '10:00', label: 'FDA CSV Export Generated', desc: '24-hour response package with all CTEs, KDEs, and chain hashes', icon: Download, done: true },
- { time: '—', label: 'Retailer EPCIS Notification', desc: 'GS1 EPCIS 2.0 export package ready for retailer portal upload. Confirm specific format with each buyer', icon: ShoppingCart, done: false },
- { time: '—', label: 'Investigation Closed', desc: 'All affected lots accounted for, remediation verified', icon: CheckCircle2, done: false },
+ { time: 'Pending', label: 'Retailer EPCIS Notification (Preview)', desc: 'GS1 EPCIS 2.0 export package ready for retailer portal upload. Confirm specific format with each buyer', icon: ShoppingCart, done: false },
+ { time: 'Pending', label: 'Investigation Closed', desc: 'All affected lots accounted for, remediation verified', icon: CheckCircle2, done: false },
];
/* ── Helpers ── */
@@ -180,7 +181,7 @@ export default function RecallReportPage() {
const actionItems = report?.action_items ?? [];
const overallScore = report?.overall_score ?? 0;
const overallGrade = report?.overall_grade ?? '—';
- const responseTimeStr = report?.time_to_respond_estimate ?? '—';
+ const responseTimeStr = report?.time_to_respond_estimate ?? NOT_SET;
// Demo-mode fallback stats for summary banner
const demoSlaPercent = Math.round((DEMO_INVESTIGATION.response_time_hours / DEMO_INVESTIGATION.sla_target) * 100);
diff --git a/frontend/src/app/dashboard/receiving/page.tsx b/frontend/src/app/dashboard/receiving/page.tsx
index acd4c70cd..9901259cd 100644
--- a/frontend/src/app/dashboard/receiving/page.tsx
+++ b/frontend/src/app/dashboard/receiving/page.tsx
@@ -30,6 +30,7 @@ import { useToast } from '@/components/ui/use-toast';
import { parseGS1 } from '@/lib/gs1-parser';
import { scanMatchesItem } from '@/lib/scan-match';
import { notifyDashboardRefresh } from '@/hooks/use-dashboard-refresh';
+import { NOT_SET } from '@/lib/empty-values';
/* ─── Types ─── */
interface LineItem {
@@ -65,9 +66,9 @@ const EXPECTED_FIELD_HINTS: readonly (readonly [string, string])[] = [
];
const RECEIPT_COLUMNS: DataTableColumn[] = [
- { key: 'productName', header: 'Product', cell: (item) => item.productName || '—' },
- { key: 'gtin', header: 'Barcode', mono: true, cell: (item) => item.gtin || '—' },
- { key: 'lotCode', header: 'Lot', mono: true, cell: (item) => item.lotCode || '—' },
+ { key: 'productName', header: 'Product', cell: (item) => item.productName || NOT_SET },
+ { key: 'gtin', header: 'Barcode', mono: true, cell: (item) => item.gtin || NOT_SET },
+ { key: 'lotCode', header: 'Lot', mono: true, cell: (item) => item.lotCode || NOT_SET },
{ key: 'quantity', header: 'Qty', align: 'right', cell: (item) => item.quantity },
];
diff --git a/frontend/src/app/dashboard/settings/page.tsx b/frontend/src/app/dashboard/settings/page.tsx
index d6f5b159e..51df3bafb 100644
--- a/frontend/src/app/dashboard/settings/page.tsx
+++ b/frontend/src/app/dashboard/settings/page.tsx
@@ -47,8 +47,8 @@ const INTEGRATIONS = [
{ id: 'netsuite', name: 'Oracle NetSuite', category: 'ERP', status: 'available', desc: 'Cloud ERP and financials' },
{ id: 'walmart', name: 'Walmart GDSN', category: 'Retailer', status: 'coming_soon', desc: 'Global Data Synchronization' },
{ id: 'kroger', name: 'Kroger 84.51\u00b0', category: 'Retailer', status: 'coming_soon', desc: 'Retailer data exchange' },
- { id: 'epcis', name: 'EPCIS 2.0 Gateway', category: 'Standards', status: 'available', desc: 'GS1 event format bridge; ingest in Preview' },
- { id: 'webhook', name: 'Custom Webhooks', category: 'Custom', status: 'available', desc: 'Push events to your endpoints' },
+ { id: 'epcis', name: 'EPCIS 2.0 Gateway', category: 'Standards', status: 'epcis_preview', desc: 'GS1 event format bridge; ingest in Preview' },
+ { id: 'webhook', name: 'Custom Webhooks', category: 'Custom', status: 'preview', desc: 'Push events to your endpoints' },
];
/**
* Integration status. `state` promotes the operational statuses to the
@@ -61,6 +61,8 @@ const STATUS_CONFIG: Record
available: { label: 'Available' },
disconnected: { label: 'Available' },
coming_soon: { label: 'Coming Soon' },
+ preview: { label: 'Preview / contact us' },
+ epcis_preview: { label: 'Preview' },
};
const TABS = [
diff --git a/frontend/src/app/dashboard/suppliers/page.tsx b/frontend/src/app/dashboard/suppliers/page.tsx
index 5ca8c265b..1c9d28dd9 100644
--- a/frontend/src/app/dashboard/suppliers/page.tsx
+++ b/frontend/src/app/dashboard/suppliers/page.tsx
@@ -39,6 +39,7 @@ import type {
PortalLink,
IntegrationProfile,
} from '@/types/api';
+import { NO_DATA_YET } from '@/lib/empty-values';
/* ------------------------------------------------------------------ */
/* Types */
@@ -425,7 +426,7 @@ export default function SupplierDashboardPage() {
- {workbenchSummary?.score ?? '—'}
+ {workbenchSummary?.score ?? NO_DATA_YET}
Inflow Workbench readiness
diff --git a/frontend/src/app/docs/api/ApiReferenceClient.tsx b/frontend/src/app/docs/api/ApiReferenceClient.tsx
index c17bda3be..4f8b50e54 100644
--- a/frontend/src/app/docs/api/ApiReferenceClient.tsx
+++ b/frontend/src/app/docs/api/ApiReferenceClient.tsx
@@ -43,7 +43,7 @@ interface Endpoint {
// API Endpoint Documentation
const API_SERVICES: { name: string; baseUrl: string; icon: React.ComponentType<{ className?: string }>; description: string; provisioned?: boolean; endpoints: Endpoint[] }[] = [
{
- name: 'Webhook Ingestion API',
+ name: 'JSON Events API',
baseUrl: '/api/v1/webhooks',
icon: FileText,
description: 'Primary FSMA event ingestion endpoint for CTE batches',
@@ -490,7 +490,7 @@ export function ApiReferenceClient() {
Available on contracted workspaces. These endpoints are served from your
workspace's provisioned endpoint URL (supplied during onboarding), not the
- public regengine.co base URL. Webhook Ingestion, Records, and FDA
+ public regengine.co base URL. JSON Events API, Records, and FDA
Trace & Export above are the publicly reachable surface.
)}
diff --git a/frontend/src/app/docs/api/page.tsx b/frontend/src/app/docs/api/page.tsx
index 311fe6326..19e7ad24e 100644
--- a/frontend/src/app/docs/api/page.tsx
+++ b/frontend/src/app/docs/api/page.tsx
@@ -4,10 +4,10 @@ import { ApiReferenceClient } from './ApiReferenceClient';
export const metadata: Metadata = {
title: 'API Reference | RegEngine',
description:
- 'RegEngine API reference for FSMA 204 traceability records, advisory compliance validation, webhook ingestion, and FDA-oriented sortable exports.',
+ 'RegEngine API reference for FSMA 204 traceability records, advisory compliance validation, JSON events API ingestion, and FDA-oriented sortable exports.',
openGraph: {
title: 'API Reference',
- description: 'RegEngine API reference for FSMA 204 traceability records, advisory compliance validation, webhook ingestion, and FDA-oriented sortable exports.',
+ description: 'RegEngine API reference for FSMA 204 traceability records, advisory compliance validation, JSON events API ingestion, and FDA-oriented sortable exports.',
url: 'https://regengine.co/docs/api',
type: 'website',
},
diff --git a/frontend/src/app/docs/page.tsx b/frontend/src/app/docs/page.tsx
index 2d3965f01..902a669fe 100644
--- a/frontend/src/app/docs/page.tsx
+++ b/frontend/src/app/docs/page.tsx
@@ -80,7 +80,7 @@ const subPages = [
{ title: 'Quickstart', href: '/docs/quickstart', icon: Zap, description: 'Your first API call in about 5 minutes' },
{ title: 'Authentication', href: '/docs/authentication', icon: Key, description: 'The key header, scopes, and what a key can reach' },
{ title: 'API Reference', href: '/docs/api', icon: Code2, description: 'Full endpoint reference with schemas' },
- { title: 'Outbound webhooks (planned)', href: '/docs/webhooks', icon: Webhook, description: 'Notifications from RegEngine. To send events in, use POST /webhooks/ingest.' },
+ { title: 'Outbound webhooks (planned)', href: '/docs/webhooks', icon: Webhook, description: 'Notifications from RegEngine. To send events in, use the JSON events API (POST /webhooks/ingest).' },
{ title: 'Inflow Lab', href: '/docs/connectors/inflow-lab', icon: Terminal, description: 'Preflight, readiness scoring, fix queue, and commit gates' },
{ title: 'Error Codes', href: '/docs/errors', icon: AlertTriangle, description: 'Error responses and troubleshooting' },
{ title: 'Rate Limits', href: '/docs/rate-limits', icon: Clock, description: 'What to do when you get a 429' },
diff --git a/frontend/src/app/docs/walkthrough/page.tsx b/frontend/src/app/docs/walkthrough/page.tsx
index a30130931..e2a5c3b8d 100644
--- a/frontend/src/app/docs/walkthrough/page.tsx
+++ b/frontend/src/app/docs/walkthrough/page.tsx
@@ -208,7 +208,7 @@ head -20 lot-export.csv`}
{filterExperimentalToolLinks([
{ title: 'Try a Recall Drill', desc: 'Simulate an FDA recall request against the data you just posted', href: '/dashboard/recall-drills' },
{ title: 'CSV Bulk Ingest', desc: 'Upload a real supplier CSV through Inflow Workbench preflight', href: '/tools/inflow-lab' },
- { title: 'EPCIS intake (Preview) and EDI intake (on the roadmap)', desc: 'EPCIS upload is in Preview on the Ingest page; EDI connectors are planned. Live intake today is CSV upload or the JSON events API', href: '/docs/connectors/inflow-lab' },
+ { title: 'EPCIS intake (Preview)', desc: 'Send records by CSV upload or the JSON events API. EPCIS 2.0 is in Preview on the Ingest page.', href: '/docs/connectors/inflow-lab' },
]).map(({ title, desc, href }) => (
- That is ingestion, and it is available now:{' '}
+ That is the JSON events API, and it is available now:{' '}
POST /api/v1/webhooks/ingest
@@ -125,7 +125,7 @@ export default function WebhooksDocsPage() {
Get Notified on Release
- Be the first to know when webhooks are available.
+ Be the first to know when customer-managed webhooks are available.
diff --git a/frontend/src/app/fsma/page.tsx b/frontend/src/app/fsma/page.tsx
index a878bc587..dd599e907 100644
--- a/frontend/src/app/fsma/page.tsx
+++ b/frontend/src/app/fsma/page.tsx
@@ -51,6 +51,7 @@ import {
CheckCircle,
XCircle,
} from 'lucide-react';
+import { NO_DATA_YET } from '@/lib/empty-values';
// Empty state shown before a trace is run
const EMPTY_FACILITIES: Facility[] = [];
@@ -166,12 +167,12 @@ function FSMADashboardContent() {
- Use URL ingestion for public documents, File Upload for CSV traceability events, or EPCIS 2.0 for GS1 EPCIS JSON and XML files.
+ Use URL ingestion for public documents, File Upload for CSV traceability events, or EPCIS 2.0 (Preview) for GS1 EPCIS JSON and XML files.
{experimentalFeaturesEnabled() && (
@@ -939,7 +939,7 @@ export default function IngestPage() {
Inflow Lab
- Use the lab for FSMA event simulation and webhook replay so test traffic stays tagged.
+ Use the lab for FSMA event simulation and event replay so test traffic stays tagged.
@@ -981,7 +981,6 @@ export default function IngestPage() {
{SUPPORTED_FORMATS.map((format) => (
{format}
))}
- EDI (X12/EDIFACT)
URL ingestion requires the document to be publicly accessible. For private documents, use the File Upload tab above.
diff --git a/frontend/src/app/integrations/page.tsx b/frontend/src/app/integrations/page.tsx
index a2244ef06..ddf51c345 100644
--- a/frontend/src/app/integrations/page.tsx
+++ b/frontend/src/app/integrations/page.tsx
@@ -31,10 +31,10 @@ import { cn } from "@/lib/utils";
export const metadata: Metadata = {
title: "Integrations: Supplier Data Intake | RegEngine",
description:
- "RegEngine accepts supplier data via CSV upload and the JSON events API, with custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.",
+ "RegEngine accepts supplier data via CSV upload and the JSON events API, with custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS 2.0 is in Preview.",
openGraph: {
title: 'Integrations: Supplier Data Intake | RegEngine',
- description: 'CSV upload and JSON events API intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.',
+ description: 'CSV upload and JSON events API intake, plus custom-scoped connectors for ERP, food-safety, and retailer systems. EPCIS 2.0 is in Preview.',
url: 'https://regengine.co/integrations',
type: 'website',
},
@@ -119,7 +119,7 @@ export default function IntegrationsPage() {
Know which sources are ready, guided, or custom scoped.
- A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Live intake today is CSV upload and the JSON events API; EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap. Inflow Lab is the simulator path for JSON events API demos and contract CI.
+ A compact view of available intake modes, guided workflows, and custom-scoped implementation paths. Named vendor and retailer workflows require scope confirmation and evidence review before being treated as production connectors. Send records by CSV upload or the JSON events API. EPCIS 2.0 is in Preview. Inflow Lab is the simulator path for JSON events API demos and contract CI.
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 176095d77..800517e5f 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -204,7 +204,7 @@ export default function HomePage() {
FSMA 204 recordkeeping for the Food Traceability Rule.
- Ingest supply-chain data through CSV upload or the JSON events API. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
+ Send records by CSV upload or the JSON events API. EPCIS 2.0 is in Preview. Check CTE/KDE coverage and completeness in the Inflow Workbench. Persist append-only after checks you configure. Export FDA-oriented and buyer-oriented spreadsheets.
diff --git a/frontend/src/app/pricing/page.tsx b/frontend/src/app/pricing/page.tsx
index ed2c8d1c0..9fb1d259e 100644
--- a/frontend/src/app/pricing/page.tsx
+++ b/frontend/src/app/pricing/page.tsx
@@ -141,7 +141,7 @@ const FAQ: PricingFaqItem[] = [
{ q: 'Can I switch plans anytime?', a: 'Plan changes are handled under your executed order form or design-partner agreement. We scope upgrades, downgrades, facility count, and billing changes before applying them.' },
{ q: 'Do you offer annual billing?', a: 'Annual and monthly billing can be scoped during procurement. Pricing shown is indicative; the executed agreement controls final plan, billing period, and checkout availability.' },
{ q: 'Does my Founding rate ever change?', a: 'Your Founding rate is controlled by the executed order form or design-partner agreement, including renewal, scope, add-ons, taxes, and plan changes.' },
- { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: CSV upload, the JSON events API, or custom-scoped implementation. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.' },
+ { q: 'What integrations are available?', a: 'Core APIs and export flows are available today. ERP, retailer, and partner-system integrations are evaluated per delivery mode: CSV upload, the JSON events API, or custom-scoped implementation. EPCIS 2.0 is in Preview.' },
{ q: 'What if the FDA delays enforcement again?', a: 'Major retailers are already requiring traceability data from suppliers regardless of the FDA timeline. RegEngine gives you the tooling and records to support either trigger: the FDA rule or a retailer mandate.' },
{ q: 'Do I need this if I\'m a small farm?', a: 'FSMA 204 applies to entities on the Food Traceability List handling specific foods. Use our free FTL Checker to see if your products are covered.' },
{ q: 'Can I integrate with my existing ERP?', a: 'RegEngine accepts data via API, CSV upload, or scoped ERP integration. Guided onboarding is available for approved design-partner workspaces. Timeline, support, and commercial terms are confirmed during scoping.' },
diff --git a/frontend/src/app/product/page.tsx b/frontend/src/app/product/page.tsx
index 64acb7df9..b6942aaba 100644
--- a/frontend/src/app/product/page.tsx
+++ b/frontend/src/app/product/page.tsx
@@ -106,7 +106,7 @@ function InflowImpactDiagram() {
Raw supplier feed
- CSV, portal, API, or EPCIS-shaped records (EPCIS in Preview)
+ CSV/XLSX upload or supplier portal, the JSON events API, or EPCIS-shaped records (EPCIS in Preview)
diff --git a/frontend/src/app/proof/page.tsx b/frontend/src/app/proof/page.tsx
index 63e5bfbbf..0136fee33 100644
--- a/frontend/src/app/proof/page.tsx
+++ b/frontend/src/app/proof/page.tsx
@@ -212,7 +212,7 @@ export default function ProofPage() {
$ python verify_chain.py audit-bundle-tampered.zip
manifest: ok
- verify: FAILED — fsma-204-sample.csv: sha256 mismatch
+ verify: FAILED: fsma-204-sample.csv sha256 mismatch
result: bundle TAMPERED
$ echo $?
1
diff --git a/frontend/src/app/remediation/page.tsx b/frontend/src/app/remediation/page.tsx
index d62fa1a9a..9bb34bb4a 100644
--- a/frontend/src/app/remediation/page.tsx
+++ b/frontend/src/app/remediation/page.tsx
@@ -31,6 +31,7 @@ import {
} from '@/hooks/use-remediation';
import { Check, Copy, FileWarning, Link2, Mail, PackageCheck } from 'lucide-react';
+import { NOT_SET, NO_DATA_YET } from '@/lib/empty-values';
const CASE_STATUS_LABEL: Record = {
detected: 'Detected',
@@ -77,7 +78,7 @@ function DeliveryBadge({ status, reason }: { status: string; reason?: string | n
}
function pct(value: number | null | undefined): string {
- if (value === null || value === undefined) return '—';
+ if (value === null || value === undefined) return NO_DATA_YET;
return `${Math.round(value * 100)}%`;
}
@@ -264,7 +265,7 @@ export default function RemediationPage() {
header: 'Case',
width: '12.5rem',
cell: (record) => {
- if (!record.case) return — ;
+ if (!record.case) return {NOT_SET} ;
const delivery = outboxByCase.get(record.case.case_id);
return (
@@ -289,7 +290,7 @@ export default function RemediationPage() {
width: '7rem',
cell: (record) => (
- {record.case?.due_at ? new Date(record.case.due_at).toLocaleDateString() : '—'}
+ {record.case?.due_at ? new Date(record.case.due_at).toLocaleDateString() : NOT_SET}
),
},
@@ -298,7 +299,7 @@ export default function RemediationPage() {
header: 'Why blocked',
cell: (record) => (
- {(record.failures ?? []).map((f) => f.why_failed).join('; ') || '—'}
+ {(record.failures ?? []).map((f) => f.why_failed).join('; ') || NOT_SET}
),
},
diff --git a/frontend/src/app/rules/page.tsx b/frontend/src/app/rules/page.tsx
index d0e56d459..7650cac9f 100644
--- a/frontend/src/app/rules/page.tsx
+++ b/frontend/src/app/rules/page.tsx
@@ -26,6 +26,7 @@ import {
XCircle,
Zap,
} from 'lucide-react';
+import { NOT_SET } from '@/lib/empty-values';
/**
* Category accent uses the categorical token ramp (--re-cat-1..6): a rule's
@@ -158,14 +159,14 @@ export default function RulesDashboardPage() {
mono: true,
width: '12rem',
cell: (rule) => (
- {rule.citation_reference || '—'}
+ {rule.citation_reference || NOT_SET}
),
},
{
key: 'remediation_suggestion',
header: 'Remediation',
cell: (rule) => (
- {rule.remediation_suggestion || '—'}
+ {rule.remediation_suggestion || NOT_SET}
),
},
];
diff --git a/frontend/src/app/tools/data-import/components/DataImportClient.tsx b/frontend/src/app/tools/data-import/components/DataImportClient.tsx
index 0ef0bfec7..81627da73 100644
--- a/frontend/src/app/tools/data-import/components/DataImportClient.tsx
+++ b/frontend/src/app/tools/data-import/components/DataImportClient.tsx
@@ -251,7 +251,7 @@ export function DataImportClient() {
trackToolRunCompleted('data-import', result.accepted > 0 ? 'success' : 'error');
} catch (err: unknown) {
const axiosErr = err as { response?: { data?: { detail?: string } }; message?: string };
- const msg = axiosErr?.response?.data?.detail || axiosErr?.message || 'Webhook ingest failed';
+ const msg = axiosErr?.response?.data?.detail || axiosErr?.message || 'JSON events API ingest failed';
addStep('Batch ingest', false, msg);
setSampleState('error');
trackToolRunCompleted('data-import', 'error');
@@ -269,19 +269,19 @@ export function DataImportClient() {
return (
Three Ways to Import
- CSV Upload with templates for every Critical Tracking Event (CTE) type, IoT Sensitech TempTale import, and a full REST webhook API.
+ CSV and XLSX upload with templates for every Critical Tracking Event (CTE) type, Sensitech TempTale CSV import, and the JSON events API.
}
>
@@ -604,7 +604,7 @@ export function DataImportClient() {
-
Webhook Ingestion API
+
JSON Events API
Push CTE events from any system using a single REST endpoint.
diff --git a/frontend/src/app/tools/data-import/page.tsx b/frontend/src/app/tools/data-import/page.tsx
index 5fc8abd12..3f275fed3 100644
--- a/frontend/src/app/tools/data-import/page.tsx
+++ b/frontend/src/app/tools/data-import/page.tsx
@@ -9,14 +9,14 @@ import { Skeleton } from "@/components/ui/skeleton";
import { filterExperimentalToolLinks } from "@/lib/experimental-features";
export const metadata: Metadata = {
- title: "FSMA 204 Data Import Hub | Upload CSV, IoT & Webhook Traceability Data | RegEngine",
- description: "Import FSMA 204 traceability data via CSV upload, IoT temperature logs, or webhook API. Supports Sensitech TempTale and all Critical Tracking Event (CTE) types with schema checks and field auto-mapping.",
+ title: "FSMA 204 Data Import Hub | Upload CSV, XLSX & JSON Traceability Data | RegEngine",
+ description: "Import FSMA 204 traceability data via CSV or XLSX upload (including Sensitech TempTale temperature logs), or the JSON events API. Supports all Critical Tracking Event (CTE) types with schema checks and field auto-mapping.",
alternates: {
canonical: "https://regengine.co/tools/data-import",
},
openGraph: {
title: "FSMA 204 Data Import Hub | RegEngine",
- description: "Import traceability data via CSV, IoT logs, or webhook API with FSMA 204 schema checks. Free tool.",
+ description: "Import traceability data via CSV, XLSX, or the JSON events API with FSMA 204 schema checks. Free tool.",
type: "website",
url: "https://regengine.co/tools/data-import",
},
@@ -28,7 +28,7 @@ const jsonLd = {
"name": "RegEngine Data Import Hub",
"operatingSystem": "All",
"applicationCategory": "BusinessApplication",
- "description": "Import traceability data via CSV, IoT logs, or API for FSMA 204 compliance.",
+ "description": "Import traceability data via CSV, XLSX, or the JSON events API for FSMA 204 compliance.",
};
function DataImportFallback() {
@@ -37,7 +37,7 @@ function DataImportFallback() {
Data Import Hub
-
Import your traceability data into RegEngine via CSV upload, XLSX spreadsheets, IoT temperature logs, or webhook API. Supports all FSMA 204 Critical Tracking Event (CTE) types with automatic validation and auto-cleaning of common formatting issues.
+
Import your traceability data into RegEngine via CSV upload, XLSX spreadsheets (including IoT temperature logs), or the JSON events API. Supports all FSMA 204 Critical Tracking Event (CTE) types with automatic validation and auto-cleaning of common formatting issues.
diff --git a/frontend/src/app/tools/export/layout.tsx b/frontend/src/app/tools/export/layout.tsx
index 7675749ca..4e5afbcf9 100644
--- a/frontend/src/app/tools/export/layout.tsx
+++ b/frontend/src/app/tools/export/layout.tsx
@@ -27,7 +27,7 @@ const jsonLd = {
};
const relatedTools = [
- { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data via CSV, IoT temperature logs, or webhook API before exporting.' },
+ { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data via CSV or XLSX (including IoT temperature logs), or the JSON events API before exporting.' },
{ href: '/tools/notice-validator', title: 'FDA Request Validator', description: 'Validate your draft FDA response against FSMA 204 record requirements before submission.' },
{ href: '/tools/records-request-checklist', title: 'Records Request Checklist', description: 'A self reported checklist for an FDA records request. Not a 24 hour test and not a readiness score.' },
];
diff --git a/frontend/src/app/tools/label-scanner/layout.tsx b/frontend/src/app/tools/label-scanner/layout.tsx
index ff075e2b4..f4562f940 100644
--- a/frontend/src/app/tools/label-scanner/layout.tsx
+++ b/frontend/src/app/tools/label-scanner/layout.tsx
@@ -28,7 +28,7 @@ const jsonLd = {
const relatedTools = [
{ href: '/tools/scan', title: 'GS1 Barcode Scanner', description: 'Scan or paste GS1 barcodes to decode GTIN, lot codes, and expiry into traceability records.' },
- { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data via CSV, IoT temperature logs, or webhook API.' },
+ { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data via CSV or XLSX (including IoT temperature logs), or the JSON events API.' },
{ href: '/tools/kde-checker', title: 'KDE Field Checklist', description: 'Generate the full Key Data Element (KDE) checklist required for your FTL product and Critical Tracking Event (CTE) type.' },
];
diff --git a/frontend/src/app/tools/scan/layout.tsx b/frontend/src/app/tools/scan/layout.tsx
index 536a21852..9c2741e30 100644
--- a/frontend/src/app/tools/scan/layout.tsx
+++ b/frontend/src/app/tools/scan/layout.tsx
@@ -29,7 +29,7 @@ const jsonLd = {
const relatedTools = [
{ href: '/tools/label-scanner', title: 'AI Label Scanner', description: 'Upload a food label and AI extracts lot code, GTIN, expiry date, and FSMA 204 Key Data Element (KDE) fields automatically.' },
- { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data from CSV files, IoT temperature logs, or webhook API.' },
+ { href: '/tools/data-import', title: 'Data Import Hub', description: 'Import traceability data from CSV or XLSX files (including IoT temperature logs), or the JSON events API.' },
{ href: '/tools/tlc-validator', title: 'TLC Format Check', description: 'Check a traceability lot code for format and uniqueness assumptions. FDA does not set one TLC format.' },
];
diff --git a/frontend/src/app/tools/sop-generator/components/SOPGeneratorClient.tsx b/frontend/src/app/tools/sop-generator/components/SOPGeneratorClient.tsx
index 687207f7f..4f7e9fb8e 100644
--- a/frontend/src/app/tools/sop-generator/components/SOPGeneratorClient.tsx
+++ b/frontend/src/app/tools/sop-generator/components/SOPGeneratorClient.tsx
@@ -112,7 +112,7 @@ ${ctes.join('\n')}
## Operations
${formData.has_iot ? '✅ IoT Temperature Monitoring (Sensitech)' : '⬜ No IoT monitoring'}
-${formData.has_erp ? '✅ ERP/WMS Integration via Webhook API' : '⬜ Manual data entry / CSV upload'}
+${formData.has_erp ? '✅ ERP/WMS Integration via the JSON events API' : '⬜ Manual data entry / CSV upload'}
${retailers.length > 0 ? `## Retailer Requirements (informational)\n${retailers.map(r => `- ${r}`).join('\n')}\n\n*Specific retailer traceability requirements vary, change frequently, and should be confirmed directly with each buyer.*` : ''}
diff --git a/frontend/src/app/trust/architecture/page.tsx b/frontend/src/app/trust/architecture/page.tsx
index f8f30757d..fc1a92454 100644
--- a/frontend/src/app/trust/architecture/page.tsx
+++ b/frontend/src/app/trust/architecture/page.tsx
@@ -69,7 +69,7 @@ const DATA_FLOW_STEPS = [
{
step: '1',
title: 'Ingest',
- description: 'CTE events arrive via CSV upload or the JSON events API. Both paths run validation synchronously and persist before coverage checks. EPCIS intake is in Preview; EDI and SFTP intake are on the roadmap.',
+ description: 'CTE events arrive via CSV upload or the JSON events API. Both paths run validation synchronously and persist before coverage checks. EPCIS 2.0 is in Preview.',
},
{
step: '2',
diff --git a/frontend/src/app/trust/page.tsx b/frontend/src/app/trust/page.tsx
index bf240fca6..7dcdcd618 100644
--- a/frontend/src/app/trust/page.tsx
+++ b/frontend/src/app/trust/page.tsx
@@ -63,7 +63,7 @@ const STATUS_SUMMARY = [
},
{
label: 'File Import Supported',
- detail: 'Customer data can be onboarded through CSV upload with mapping review and exception handling. SFTP delivery is on the roadmap.',
+ detail: 'Customer data can be onboarded through CSV upload with mapping review and exception handling.',
},
{
label: 'Custom Scoped',
diff --git a/frontend/src/app/why-regengine/page.tsx b/frontend/src/app/why-regengine/page.tsx
index 11ca22927..665ab68d5 100644
--- a/frontend/src/app/why-regengine/page.tsx
+++ b/frontend/src/app/why-regengine/page.tsx
@@ -132,7 +132,7 @@ const DIFFERENTIATORS = [
icon: Code2,
title: 'API-First Architecture',
description:
- 'CSV upload, a JSON events API, and EPCIS export. Integrate RegEngine with your existing ERP, WMS, or custom systems. No rip-and-replace required.',
+ 'CSV upload and the JSON events API. Integrate RegEngine with your existing ERP, WMS, or custom systems through those two live paths. No rip-and-replace required.',
detail: 'Technical teams can be live in hours. Sales ops teams use our CSV templates. Everyone gets FSMA 204 compliance their way.',
},
{
@@ -390,7 +390,7 @@ export default function WhyRegEnginePage() {
API-First, Not UI-Only
- Every feature in RegEngine has an API. REST endpoints. Webhooks for real-time events. CSV templates for ops teams. Your developers can integrate in hours, not months.
+ REST endpoints, CSV templates for ops teams, and outbound webhooks for FDA recall/enforcement alerts (enabled by RegEngine). API coverage for every feature is on the roadmap. Your developers can integrate in hours, not months.
RegEngine started with APIs and added the dashboard on top, so every dashboard action is reachable programmatically. Verify API surface depth with each vendor for your stack.
@@ -398,7 +398,7 @@ export default function WhyRegEnginePage() {
{[
'Full REST API for CTEs, suppliers, compliance status',
- 'Event webhooks for recall triggers and compliance alerts',
+ 'Outbound webhooks for FDA recall/enforcement alerts (enabled by RegEngine); broader compliance alerts on the roadmap',
'CSV import with smart field mapping',
'Native integrations with Shopify, WooCommerce (coming soon)',
].map((item, idx) => (
@@ -730,7 +730,7 @@ HTTP 201
{
Icon: Code2,
title: 'Technical Buyers',
- detail: 'Your team owns integrations. You want APIs, webhooks, and source control. RegEngine gives you that.',
+ detail: 'Your team owns integrations. You want APIs, outbound webhooks for FDA recall/enforcement alerts (enabled by RegEngine), and source control. RegEngine gives you that.',
},
{
Icon: Workflow,
diff --git a/frontend/src/components/ui/stat-tile.tsx b/frontend/src/components/ui/stat-tile.tsx
index 6dce3072b..3ddd845b5 100644
--- a/frontend/src/components/ui/stat-tile.tsx
+++ b/frontend/src/components/ui/stat-tile.tsx
@@ -4,6 +4,7 @@ import { ArrowDownRight, ArrowUpRight, Minus } from "lucide-react"
import { Card } from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
import { cn } from "@/lib/utils"
+import { NO_DATA_YET } from "@/lib/empty-values"
/**
* StatTile — SPEC §4, following the data-viz rules.
@@ -121,7 +122,7 @@ export function StatTile({
empty && "text-re-text-disabled"
)}
>
- {empty ? "—" : value}
+ {empty ? NO_DATA_YET : value}
{unit && !empty && {unit} }
{trend && trend.length > 1 && !empty && (
diff --git a/frontend/src/lib/customer-readiness.ts b/frontend/src/lib/customer-readiness.ts
index d0a22fe9e..9443503fb 100644
--- a/frontend/src/lib/customer-readiness.ts
+++ b/frontend/src/lib/customer-readiness.ts
@@ -195,7 +195,7 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
status: 'file_import_supported',
delivery_mode: 'csv_sftp_import',
integration_type: 'file_based_import',
- customer_copy: 'Upload CSV files for ERP and warehouse data that is not available over API. Scheduled SFTP delivery is on the roadmap.',
+ customer_copy: 'Upload CSV files for ERP and warehouse data that is not available over API.',
evidence_url: '/tools/data-import',
},
{
@@ -318,16 +318,6 @@ export const CAPABILITY_REGISTRY: CapabilityRegistryEntry[] = [
customer_copy: 'JSON-LD EPCIS export is supported. EPCIS ingest is in Preview. Default deployments use PostgreSQL-backed task processing; legacy Kafka-compatible signing is opt-in.',
evidence_url: '/developers',
},
- {
- id: 'edi-856',
- name: 'EDI 856',
- category: 'developer_api',
- status: 'preparation',
- delivery_mode: 'custom_scoped',
- integration_type: 'file_based_import',
- customer_copy: 'EDI 856 (ASN) inbound processing is on the roadmap. It is not available as a live intake channel.',
- evidence_url: '/trust',
- },
{
id: 'design-partner',
name: 'Design Partner Program',
diff --git a/frontend/src/lib/empty-values.ts b/frontend/src/lib/empty-values.ts
new file mode 100644
index 000000000..c2051af77
--- /dev/null
+++ b/frontend/src/lib/empty-values.ts
@@ -0,0 +1,13 @@
+/**
+ * Shared empty-value placeholders. Use these instead of a bare dash so empty
+ * UI states read as intentional copy:
+ *
+ * - NOT_SET: a field the user or upstream system has not provided (settings,
+ * profile fields, optional record attributes).
+ * - NO_DATA_YET: a metric or count with no underlying data yet.
+ *
+ * Real zeros stay 0. Never use these where logic compares against the
+ * placeholder (for example the recall-report grade sentinels).
+ */
+export const NOT_SET = 'Not set';
+export const NO_DATA_YET = 'No data yet';
diff --git a/frontend/src/lib/public-openapi.ts b/frontend/src/lib/public-openapi.ts
index 47247631f..f3fac4de3 100644
--- a/frontend/src/lib/public-openapi.ts
+++ b/frontend/src/lib/public-openapi.ts
@@ -36,7 +36,7 @@ export const publicOpenApiSpec = {
},
],
tags: [
- { name: 'Webhook Ingestion', description: 'Create tenant-scoped CTE/KDE records.' },
+ { name: 'JSON Events API', description: 'Create tenant-scoped CTE/KDE records.' },
{ name: 'Records', description: 'Read canonical ingestion-run records.' },
{ name: 'FDA Export', description: 'Export FDA-oriented sortable records where configured data supports the request.' },
],
@@ -44,7 +44,7 @@ export const publicOpenApiSpec = {
paths: {
'/api/v1/webhooks/ingest': {
post: {
- tags: ['Webhook Ingestion'],
+ tags: ['JSON Events API'],
operationId: 'ingestWebhookEvents',
summary: 'Ingest traceability events',
description:
@@ -84,7 +84,7 @@ export const publicOpenApiSpec = {
},
'/api/v1/webhooks/recent': {
get: {
- tags: ['Webhook Ingestion'],
+ tags: ['JSON Events API'],
operationId: 'listRecentWebhookEvents',
summary: 'List recent traceability events',
description: 'Requires the webhooks.read scope.',
@@ -116,7 +116,7 @@ export const publicOpenApiSpec = {
},
'/api/v1/webhooks/chain/verify': {
get: {
- tags: ['Webhook Ingestion'],
+ tags: ['JSON Events API'],
operationId: 'verifyWebhookChain',
summary: 'Verify a tenant hash chain',
description: 'Requires the webhooks.read scope.',
From c774c4b0934dd9adead4d375e8e8aa0a7e0f8853 Mon Sep 17 00:00:00 2001
From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com>
Date: Fri, 23 Oct 2026 00:02:20 -0700
Subject: [PATCH 8/8] fix(frontend): replace demo recall timeline with empty
state, use shared empty values, drop EDI roadmap line
---
frontend/src/app/api/fsma/[...path]/route.ts | 4 +-
.../src/app/api/ingestion/[...path]/route.ts | 2 +-
.../src/app/api/review/[...path]/route.ts | 2 +-
frontend/src/app/api/tools/verify/route.ts | 4 +-
.../[tenantId]/[snapshotId]/export/route.ts | 2 +-
frontend/src/app/blog/page.tsx | 2 +-
frontend/src/app/buyer-programs/page.tsx | 2 +-
frontend/src/app/case-studies/page.tsx | 2 +-
frontend/src/app/compare/foodlogiq/page.tsx | 4 +-
frontend/src/app/compare/repositrak/page.tsx | 2 +-
frontend/src/app/compare/tracegains/page.tsx | 2 +-
frontend/src/app/dashboard/alerts/page.tsx | 2 +-
.../src/app/dashboard/compliance/page.tsx | 4 +-
frontend/src/app/dashboard/heartbeat/page.tsx | 2 +-
frontend/src/app/dashboard/layout.tsx | 16 ++---
.../src/app/dashboard/notifications/page.tsx | 4 +-
frontend/src/app/dashboard/page.tsx | 8 +--
frontend/src/app/dashboard/products/page.tsx | 2 +-
.../src/app/dashboard/recall-report/page.tsx | 58 +++++--------------
frontend/src/app/dashboard/receiving/page.tsx | 8 +--
frontend/src/app/dashboard/scan/page.tsx | 4 +-
frontend/src/app/dashboard/settings/page.tsx | 4 +-
frontend/src/app/dashboard/suppliers/page.tsx | 6 +-
frontend/src/app/demo/page.tsx | 2 +-
frontend/src/app/design-system/page.tsx | 2 +-
.../src/app/docs/api/ApiReferenceClient.tsx | 4 +-
frontend/src/app/docs/authentication/page.tsx | 2 +-
frontend/src/app/docs/changelog/page.tsx | 18 +++---
frontend/src/app/docs/walkthrough/page.tsx | 2 +-
frontend/src/app/fsma-204/[cte]/page.tsx | 14 ++---
frontend/src/app/fsma-204/page.tsx | 18 +++---
.../app/onboarding/setup/facility/page.tsx | 16 ++---
.../app/onboarding/setup/ftl-check/page.tsx | 4 +-
frontend/src/app/privacy/page.tsx | 4 +-
frontend/src/app/proof/page.tsx | 2 +-
frontend/src/app/remediation/page.tsx | 6 +-
frontend/src/app/requests/page.tsx | 6 +-
frontend/src/app/sandbox/SandboxClient.tsx | 2 +-
frontend/src/app/sandbox/page.tsx | 2 +-
frontend/src/app/settings/profile/page.tsx | 6 +-
frontend/src/app/settings/security/page.tsx | 2 +-
frontend/src/app/supplier-compliance/page.tsx | 2 +-
frontend/src/app/terms/TermsClient.tsx | 2 +-
.../components/DataImportClient.tsx | 2 +-
frontend/src/app/trace/page.tsx | 2 +-
frontend/src/app/verify/page.tsx | 4 +-
.../dashboard/metrics-overview-widget.tsx | 2 +-
frontend/src/components/fsma-checklist.tsx | 2 +-
.../components/fsma/readiness-assessment.tsx | 2 +-
.../sandbox-grid/SandboxResultView.tsx | 2 +-
.../components/mobile/FieldCaptureClient.tsx | 2 +-
frontend/src/components/ui/data-table.tsx | 4 +-
frontend/src/components/ui/stat-tile.tsx | 12 ++--
frontend/src/lib/api-client.ts | 12 ++--
frontend/src/lib/api-config.ts | 2 +-
frontend/src/lib/api-proxy.ts | 20 +++----
frontend/src/lib/auth-context.tsx | 30 +++++-----
frontend/src/lib/csrf.ts | 20 +++----
frontend/src/lib/customer-readiness.ts | 2 +-
frontend/src/lib/fsma-enforcement.ts | 2 +-
frontend/src/lib/ftl-data.ts | 2 +-
frontend/src/lib/proxy-factory.ts | 4 +-
frontend/src/lib/roi-calculator-data.ts | 2 +-
63 files changed, 182 insertions(+), 210 deletions(-)
diff --git a/frontend/src/app/api/fsma/[...path]/route.ts b/frontend/src/app/api/fsma/[...path]/route.ts
index cd1cab4c5..4e1e159a0 100644
--- a/frontend/src/app/api/fsma/[...path]/route.ts
+++ b/frontend/src/app/api/fsma/[...path]/route.ts
@@ -14,7 +14,7 @@ import { applyCookieCredentials, createJsonProxy, passthroughRequestHeaders } fr
// :62 metrics_router prefix="/fsma/metrics" -> /api/v1/fsma/metrics/*
// :63 compliance_router prefix="/fsma/compliance" -> /api/v1/fsma/compliance/*
//
-// `gaps` and `export/` are NOT top-level FSMA routes — they are endpoints on
+// `gaps` and `export/` are NOT top-level FSMA routes - they are endpoints on
// the compliance sub-router (services/graph/app/routers/fsma/compliance.py):
// :640 @router.get("/gaps") -> /api/v1/fsma/compliance/gaps
// :681 @router.get("/gaps/orphans") -> /api/v1/fsma/compliance/gaps/orphans
@@ -32,7 +32,7 @@ import { applyCookieCredentials, createJsonProxy, passthroughRequestHeaders } fr
// entry pointed at /api/v1/fsma/drift/* which has never existed. Do not add
// it back without a real backend router to point it at.
//
-// Compliance service — services/compliance/app/routes.py:64 declares
+// Compliance service - services/compliance/app/routes.py:64 declares
// `APIRouter(tags=["fsma-compliance"])` with NO prefix, and server/main.py:929
// mounts it with no prefix either (`app.include_router(fsma_router, ...)`), so
// its routes are /industries, /checklists, /checklists/{id} and
diff --git a/frontend/src/app/api/ingestion/[...path]/route.ts b/frontend/src/app/api/ingestion/[...path]/route.ts
index 3bf8c5375..9a6700488 100644
--- a/frontend/src/app/api/ingestion/[...path]/route.ts
+++ b/frontend/src/app/api/ingestion/[...path]/route.ts
@@ -85,7 +85,7 @@ const { GET, POST, PUT, PATCH, DELETE, OPTIONS } = createStreamProxy({
// Inject access token + tenant API key + tenant ID from cookies.
// Unlike admin, ingestion overwrites an incoming Authorization header
- // with the cookie token — preserving pre-refactor behavior.
+ // with the cookie token - preserving pre-refactor behavior.
applyCookieCredentials(headers, request);
return headers;
diff --git a/frontend/src/app/api/review/[...path]/route.ts b/frontend/src/app/api/review/[...path]/route.ts
index c823c62b2..036ee0f08 100644
--- a/frontend/src/app/api/review/[...path]/route.ts
+++ b/frontend/src/app/api/review/[...path]/route.ts
@@ -8,7 +8,7 @@ import { getServerServiceURL } from '@/lib/api-config';
import { attestPrivilegedProxyClientIp } from '@/lib/proxy-ip-attestation';
// Proxy review API requests to the Admin backend service.
-// Handles the approve/reject actions on flagged extractions — paths like
+// Handles the approve/reject actions on flagged extractions - paths like
// /api/review/{id}/approve
// /api/review/{id}/reject
// are transformed into
diff --git a/frontend/src/app/api/tools/verify/route.ts b/frontend/src/app/api/tools/verify/route.ts
index c74810892..0ded72ca0 100644
--- a/frontend/src/app/api/tools/verify/route.ts
+++ b/frontend/src/app/api/tools/verify/route.ts
@@ -1,5 +1,5 @@
/**
- * Proxy for tool email verification — forwards to backend and sets
+ * Proxy for tool email verification - forwards to backend and sets
* the re_tool_access HTTP-only cookie on successful code confirmation.
*
* POST /api/tools/verify
@@ -32,7 +32,7 @@ function getBackendUrl(): string {
}
export async function POST(request: NextRequest) {
- // On Vercel, localhost fallback will never work — fail fast with a clear error.
+ // On Vercel, localhost fallback will never work - fail fast with a clear error.
const backendUrl = getBackendUrl();
if (process.env.VERCEL && !backendUrl) {
console.error(
diff --git a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
index 3126a9d92..51cd9b40d 100644
--- a/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
+++ b/frontend/src/app/api/v1/compliance/snapshots/[tenantId]/[snapshotId]/export/route.ts
@@ -42,7 +42,7 @@ export async function GET(
const { tenantId: rawTenantId, snapshotId: rawSnapshotId } = await params;
// Validate UUIDs before interpolating into the upstream URL (see
- // verify/route.ts — same hardening applied to every named-segment proxy).
+ // verify/route.ts - same hardening applied to every named-segment proxy).
const tenantId = validateUuid(rawTenantId);
const snapshotId = validateUuid(rawSnapshotId);
if (!tenantId || !snapshotId) {
diff --git a/frontend/src/app/blog/page.tsx b/frontend/src/app/blog/page.tsx
index ed1879f23..451042843 100644
--- a/frontend/src/app/blog/page.tsx
+++ b/frontend/src/app/blog/page.tsx
@@ -30,7 +30,7 @@ type BlogPost = {
// Slugs are typed against BLOG_POST_SLUGS so a post added here without being
// added to the shared list (and therefore the sitemap) fails typecheck.
-// Titles live in that shared list too — the social cards render from them.
+// Titles live in that shared list too - the social cards render from them.
const BLOG_POSTS: BlogPost[] = [
{
slug: 'fsma-204-compliance-guide',
diff --git a/frontend/src/app/buyer-programs/page.tsx b/frontend/src/app/buyer-programs/page.tsx
index 14719d720..4c0b7c492 100644
--- a/frontend/src/app/buyer-programs/page.tsx
+++ b/frontend/src/app/buyer-programs/page.tsx
@@ -86,7 +86,7 @@ export default function BuyerProgramsPage() {
• FTL by that date; other products ASAP
- We do not make you Walmart-ready, transmit ASN on Retail Link, certify labels, or assess chargebacks. EDI 856 / ASN mapping is on the roadmap.
+ We do not make you Walmart-ready, transmit ASN on Retail Link, certify labels, or assess chargebacks.
diff --git a/frontend/src/app/case-studies/page.tsx b/frontend/src/app/case-studies/page.tsx
index 931363d55..324e1e589 100644
--- a/frontend/src/app/case-studies/page.tsx
+++ b/frontend/src/app/case-studies/page.tsx
@@ -74,7 +74,7 @@ const NORMALIZATION_EXAMPLES = [
},
];
-/** Identifiers and sample values are recorded data — mono, on the inset well. */
+/** Identifiers and sample values are recorded data - mono, on the inset well. */
const chipClass = 'rounded-sm bg-re-surface-inset px-1.5 py-0.5 font-mono text-[0.8125rem] text-re-text-primary';
const cellClass = 'px-4 py-3 align-middle text-re-text-secondary';
const headClass = 'px-4 py-3 text-left align-middle text-label text-re-text-tertiary';
diff --git a/frontend/src/app/compare/foodlogiq/page.tsx b/frontend/src/app/compare/foodlogiq/page.tsx
index 9266b842a..e14e897f1 100644
--- a/frontend/src/app/compare/foodlogiq/page.tsx
+++ b/frontend/src/app/compare/foodlogiq/page.tsx
@@ -33,7 +33,7 @@ const FEATURES = [
];
const WHY_SWITCH = [
- // #2757 — this used to assert the sandbox returns results "in seconds" regardless of
+ // #2757 - this used to assert the sandbox returns results "in seconds" regardless of
// whether the sandbox surface is enabled on the deployment. Reworded to the claim the
// product makes unconditionally: rule evaluation runs on the first CSV you upload.
{ title: "Self-serve onboarding", desc: "RegEngine evaluates your first CSV against the FSMA 204 rule set on upload, with no implementation project to get a readiness answer. FoodLogiQ ships through enterprise implementation; verify current onboarding timelines with their team." },
@@ -130,7 +130,7 @@ export default function FoodLogiQCompare() {
{/* CTA */}
See the difference yourself
- {/* #2757 — copy and destination resolve together so the blurb can never
+ {/* #2757 - copy and destination resolve together so the blurb can never
promise a CSV sandbox that this deployment does not serve. */}
{sandboxCta().blurb}
diff --git a/frontend/src/app/compare/repositrak/page.tsx b/frontend/src/app/compare/repositrak/page.tsx
index feb653af5..92d73c5a4 100644
--- a/frontend/src/app/compare/repositrak/page.tsx
+++ b/frontend/src/app/compare/repositrak/page.tsx
@@ -121,7 +121,7 @@ export default function ReposiTrakCompare() {
{/* CTA */}
See the difference yourself
- {/* #2757 — copy and destination resolve together so the blurb can never
+ {/* #2757 - copy and destination resolve together so the blurb can never
promise a CSV sandbox that this deployment does not serve. */}
{sandboxCta().blurb}
diff --git a/frontend/src/app/compare/tracegains/page.tsx b/frontend/src/app/compare/tracegains/page.tsx
index 7d18d6410..bf5144e46 100644
--- a/frontend/src/app/compare/tracegains/page.tsx
+++ b/frontend/src/app/compare/tracegains/page.tsx
@@ -121,7 +121,7 @@ export default function TraceGainsCompare() {
{/* CTA */}
See the difference yourself
- {/* #2757 — copy and destination resolve together so the blurb can never
+ {/* #2757 - copy and destination resolve together so the blurb can never
promise a CSV sandbox that this deployment does not serve. */}
{sandboxCta().blurb}
diff --git a/frontend/src/app/dashboard/alerts/page.tsx b/frontend/src/app/dashboard/alerts/page.tsx
index 4ef9a6a57..d80ce7ce1 100644
--- a/frontend/src/app/dashboard/alerts/page.tsx
+++ b/frontend/src/app/dashboard/alerts/page.tsx
@@ -221,7 +221,7 @@ function AlertsDashboardPageContent() {
{isLoggedIn && !loading && alerts.length > 0 && (
<>
- {/* Summary tiles — each one also toggles its severity filter */}
+ {/* Summary tiles - each one also toggles its severity filter */}
{SUMMARY_TILES.map((item) => (
= 80) return 'text-re-brand';
if (score >= 60) return 'text-re-warning';
@@ -778,7 +778,7 @@ export default function ComplianceDashboardPage() {
)}
- {/* Empty state — no score and not loading */}
+ {/* Empty state - no score and not loading */}
{!score && !loading && !error && isLoggedIn && (
= 80 ? 'good' : 'warn'}
/>
) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch {
- // silent – quota exceeded, private browsing, etc.
+ // silent - quota exceeded, private browsing, etc.
}
}
@@ -290,7 +290,7 @@ function CollapsibleNavSection({
return (
- {/* Section header — clickable toggle */}
+ {/* Section header - clickable toggle */}
= {
@@ -571,7 +571,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
{/* Nav sections */}
- {/* MEDIUM #12: Keyboard navigation — arrow keys traverse nav items */}
+ {/* MEDIUM #12: Keyboard navigation - arrow keys traverse nav items */}
- {/* Status strip — the only topbar (SPEC §3.3) */}
+ {/* Status strip - the only topbar (SPEC §3.3) */}
diff --git a/frontend/src/app/dashboard/receiving/page.tsx b/frontend/src/app/dashboard/receiving/page.tsx
index 9901259cd..9611fbeb5 100644
--- a/frontend/src/app/dashboard/receiving/page.tsx
+++ b/frontend/src/app/dashboard/receiving/page.tsx
@@ -160,7 +160,7 @@ export default function ReceivingDockPage() {
const scannedGtin = parsed.gtin || '';
const scannedLot = parsed.tlc || '';
// The input invites typing a bare GTIN or lot code, but parseGS1 only
- // extracts values from AI-encoded / Digital Link strings — so a user
+ // extracts values from AI-encoded / Digital Link strings - so a user
// typing exactly what the Expected Items list displays never matched
// and every scan landed in Unexpected Items. scanMatchesItem also
// compares the raw string directly (matrix unit-tested in
@@ -185,7 +185,7 @@ export default function ReceivingDockPage() {
}
if (!matched) {
- // Unexpected scan — add to unexpected list
+ // Unexpected scan - add to unexpected list
updated.unexpectedScans.push({
id: `unx-${Date.now()}`,
gtin: scannedGtin,
@@ -314,7 +314,7 @@ export default function ReceivingDockPage() {
/* ─── Render ─── */
return (
- {/* Back link — the shell owns the breadcrumb; this stays as the
+ {/* Back link - the shell owns the breadcrumb; this stays as the
dock's own return affordance. */}
@@ -410,7 +410,7 @@ export default function ReceivingDockPage() {
- {/* Scan input — keyboard wedge or manual */}
+ {/* Scan input - keyboard wedge or manual */}
{/* The dashboard shell owns the breadcrumb and the service-health
- badge — this page only renders its own header. */}
+ badge: this page only renders its own header. */}
- {/* Portal Links — Invite Suppliers */}
+ {/* Portal Links - Invite Suppliers */}
@@ -770,7 +770,7 @@ export default function SupplierDashboardPage() {
)}
- {/* Facility List — hairline ledger rows */}
+ {/* Facility List - hairline ledger rows */}
{!loading && facilities.length > 0 && (
diff --git a/frontend/src/app/demo/page.tsx b/frontend/src/app/demo/page.tsx
index a3656f0ea..cd54b6a00 100644
--- a/frontend/src/app/demo/page.tsx
+++ b/frontend/src/app/demo/page.tsx
@@ -14,7 +14,7 @@ import { StatTile } from '@/components/ui/stat-tile';
import { StatusBadge, type ComplianceState } from '@/components/ui/status-badge';
// ---------------------------------------------------------------------------
-// Synthetic demo data — what a mid-market produce distributor would see
+// Synthetic demo data - what a mid-market produce distributor would see
// ---------------------------------------------------------------------------
const COMPLIANCE_SCORE = 94.2;
diff --git a/frontend/src/app/design-system/page.tsx b/frontend/src/app/design-system/page.tsx
index 8c47b3832..fdf30a43b 100644
--- a/frontend/src/app/design-system/page.tsx
+++ b/frontend/src/app/design-system/page.tsx
@@ -29,7 +29,7 @@ import { StatusBadge, type ComplianceState } from '@/components/ui/status-badge'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
/**
- * /design-system — the rendered contract for the design system.
+ * /design-system - the rendered contract for the design system.
*
* Every primitive, in every state, in whichever theme is active. This is what a
* page author checks their work against, and the fastest way for a human to
diff --git a/frontend/src/app/docs/api/ApiReferenceClient.tsx b/frontend/src/app/docs/api/ApiReferenceClient.tsx
index 4f8b50e54..09ddf689b 100644
--- a/frontend/src/app/docs/api/ApiReferenceClient.tsx
+++ b/frontend/src/app/docs/api/ApiReferenceClient.tsx
@@ -227,7 +227,7 @@ const API_SERVICES: { name: string; baseUrl: string; icon: React.ComponentType<{
},
];
-/** Section label inside an endpoint panel — the only uppercase in the system (SPEC §2.2). */
+/** Section label inside an endpoint panel - the only uppercase in the system (SPEC §2.2). */
const PANEL_LABEL = 'font-mono text-label uppercase text-re-text-muted';
function CopyButton({ text }: { text: string }) {
@@ -387,7 +387,7 @@ const RATE_LIMIT_HEADERS = [
{ header: 'X-RateLimit-Reset', desc: 'When limit resets (epoch)' },
];
-/** A key/value well — one surface step below the card it sits on (SPEC §5.1). */
+/** A key/value well - one surface step below the card it sits on (SPEC §5.1). */
const WELL = 'rounded-md border border-re-border-subtle bg-re-surface-inset p-3';
export function ApiReferenceClient() {
diff --git a/frontend/src/app/docs/authentication/page.tsx b/frontend/src/app/docs/authentication/page.tsx
index 25a1615c7..a253ba9f4 100644
--- a/frontend/src/app/docs/authentication/page.tsx
+++ b/frontend/src/app/docs/authentication/page.tsx
@@ -8,7 +8,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import { CodeBlock } from "@/components/ui/code-block";
import { API_BASE } from "@/lib/api-base";
-/** Inline identifier — SPEC §2.3. */
+/** Inline identifier - SPEC §2.3. */
const CODE =
"rounded-sm bg-re-surface-inset px-1.5 py-0.5 font-mono text-[0.8125rem] text-re-text-primary";
diff --git a/frontend/src/app/docs/changelog/page.tsx b/frontend/src/app/docs/changelog/page.tsx
index 733f7143a..c68568f6d 100644
--- a/frontend/src/app/docs/changelog/page.tsx
+++ b/frontend/src/app/docs/changelog/page.tsx
@@ -16,7 +16,7 @@ export const metadata: Metadata = {
},
};
-/** Inline identifier — SPEC §2.3. */
+/** Inline identifier - SPEC §2.3. */
const CODE =
'rounded-sm bg-re-surface-inset px-1.5 py-0.5 font-mono text-[0.8125rem] text-re-text-primary';
@@ -24,7 +24,7 @@ const LIST = 'mt-3 list-disc space-y-1.5 pl-5 text-ui text-re-text-secondary mar
const GROUP = 'font-mono text-label uppercase text-re-text-muted';
/**
- * One release. A hairline rule separates releases — a tinted band per version
+ * One release. A hairline rule separates releases - a tinted band per version
* would turn the page into a colour field (SPEC §3.2), and the version stamp is
* mono because it is a recorded identifier (SPEC §2.3).
*/
@@ -78,7 +78,7 @@ export default function ChangelogPage() {
/>
- {/* v1.6.0 — Proof Bundle Verification */}
+ {/* v1.6.0 - Proof Bundle Verification */}
Verification
@@ -90,7 +90,7 @@ export default function ChangelogPage() {
- {/* v1.5.0 — Trust and Safety Copy Sweep */}
+ {/* v1.5.0 - Trust and Safety Copy Sweep */}
Product Copy
@@ -103,7 +103,7 @@ export default function ChangelogPage() {
- {/* v1.4.0 — Security and Tenant Isolation Hardening */}
+ {/* v1.4.0 - Security and Tenant Isolation Hardening */}
Security
@@ -117,7 +117,7 @@ export default function ChangelogPage() {
- {/* v1.3.0 — Production Auth and Architecture Cleanup */}
+ {/* v1.3.0 - Production Auth and Architecture Cleanup */}
Platform
@@ -130,7 +130,7 @@ export default function ChangelogPage() {
- {/* v1.2.0 — Phase 4: Accessibility Polish */}
+ {/* v1.2.0 - Phase 4: Accessibility Polish */}
♿ Accessibility
@@ -146,7 +146,7 @@ export default function ChangelogPage() {
- {/* v1.1.0 — Phase 3: Onboarding UX Redesign */}
+ {/* v1.1.0 - Phase 3: Onboarding UX Redesign */}
✨ Features
@@ -160,7 +160,7 @@ export default function ChangelogPage() {
- {/* v1.0.0 — Initial Public Release */}
+ {/* v1.0.0 - Initial Public Release */}
✨ Features
diff --git a/frontend/src/app/docs/walkthrough/page.tsx b/frontend/src/app/docs/walkthrough/page.tsx
index e2a5c3b8d..9e8b1aa87 100644
--- a/frontend/src/app/docs/walkthrough/page.tsx
+++ b/frontend/src/app/docs/walkthrough/page.tsx
@@ -25,7 +25,7 @@ export const metadata: Metadata = {
},
};
-/** Inline identifier — SPEC §2.3. */
+/** Inline identifier - SPEC §2.3. */
const CODE =
'rounded-sm bg-re-surface-inset px-1.5 py-0.5 font-mono text-[0.8125rem] text-re-text-primary';
diff --git a/frontend/src/app/fsma-204/[cte]/page.tsx b/frontend/src/app/fsma-204/[cte]/page.tsx
index c8e3d05dc..b978c6ad8 100644
--- a/frontend/src/app/fsma-204/[cte]/page.tsx
+++ b/frontend/src/app/fsma-204/[cte]/page.tsx
@@ -323,7 +323,7 @@ export default async function CTELandingPage({
return (
- {/* — HERO — */}
+ {/* - HERO - */}
- {/* — WHO NEEDS THIS — */}
+ {/* - WHO NEEDS THIS - */}
Who needs to record this CTE
@@ -360,7 +360,7 @@ export default async function CTELandingPage({
- {/* — REQUIRED KDEs TABLE — */}
+ {/* - REQUIRED KDEs TABLE - */}
Required Data Elements}
@@ -394,7 +394,7 @@ export default async function CTELandingPage({
- {/* — COMMON DATA QUALITY ISSUES — */}
+ {/* - COMMON DATA QUALITY ISSUES - */}
Watch out for these}
@@ -416,7 +416,7 @@ export default async function CTELandingPage({
- {/* — HOW REGENGINE HELPS — */}
+ {/* - HOW REGENGINE HELPS - */}
Automated validation}
@@ -446,7 +446,7 @@ export default async function CTELandingPage({
- {/* — CTA — */}
+ {/* - CTA - */}
@@ -471,7 +471,7 @@ export default async function CTELandingPage({
- {/* — OTHER CTEs NAV — */}
+ {/* - OTHER CTEs NAV - */}
Other Critical Tracking Events
diff --git a/frontend/src/app/fsma-204/page.tsx b/frontend/src/app/fsma-204/page.tsx
index 85879c14d..3b8e9a9e8 100644
--- a/frontend/src/app/fsma-204/page.tsx
+++ b/frontend/src/app/fsma-204/page.tsx
@@ -145,7 +145,7 @@ const FAQS = [
export default function FSMA204BusinessGuidePage() {
return (
- {/* — HERO — */}
+ {/* - HERO - */}
- {/* — KEY FACTS STRIP — */}
+ {/* - KEY FACTS STRIP - */}
{KEY_FACTS.map((fact) => (
@@ -188,7 +188,7 @@ export default function FSMA204BusinessGuidePage() {
- {/* — WHAT IS FSMA 204 — */}
+ {/* - WHAT IS FSMA 204 - */}
@@ -211,7 +211,7 @@ export default function FSMA204BusinessGuidePage() {
- {/* — ARE YOUR PRODUCTS COVERED? — */}
+ {/* - ARE YOUR PRODUCTS COVERED? - */}
- {/* — WHAT YOU HAVE TO RECORD — */}
+ {/* - WHAT YOU HAVE TO RECORD - */}
- {/* — THE 24-HOUR RULE — */}
+ {/* - THE 24-HOUR RULE - */}
- {/* — HOW TO COMPLY — */}
+ {/* - HOW TO COMPLY - */}
- {/* — FAQ — */}
+ {/* - FAQ - */}
{FAQS.map((faq) => (
@@ -340,7 +340,7 @@ export default function FSMA204BusinessGuidePage() {
- {/* — FINAL CTA — */}
+ {/* - FINAL CTA - */}
diff --git a/frontend/src/app/onboarding/setup/facility/page.tsx b/frontend/src/app/onboarding/setup/facility/page.tsx
index d0714e738..13c298f7d 100644
--- a/frontend/src/app/onboarding/setup/facility/page.tsx
+++ b/frontend/src/app/onboarding/setup/facility/page.tsx
@@ -23,10 +23,10 @@ import { apiClient } from '@/lib/api-client';
import { StepIndicator } from '@/components/onboarding/StepIndicator';
import { US_STATES, SUPPLY_CHAIN_ROLES } from '@/lib/constants';
-// #539 — US ZIP: 5 digits or 5+4 (e.g. 93901 or 93901-1234)
+// #539 - US ZIP: 5 digits or 5+4 (e.g. 93901 or 93901-1234)
const ZIP_RE = /^\d{5}(-\d{4})?$/;
-// #540 — UUID v4 format expected from the API
+// #540 - UUID v4 format expected from the API
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
export default function FacilityPage() {
@@ -50,7 +50,7 @@ export default function FacilityPage() {
);
};
- // #539 — ZIP is required and must match the US ZIP pattern
+ // #539 - ZIP is required and must match the US ZIP pattern
const zipValid = ZIP_RE.test(zip);
const zipInvalid = zip.length > 0 && !zipValid;
@@ -69,15 +69,15 @@ export default function FacilityPage() {
try {
const facility = await apiClient.createSupplierFacility({
name,
- street, // #539 — real value, no '--' placeholder
+ street, // #539: real value, no '--' placeholder
city,
state,
- postal_code: zip, // #539 — required, validated above
+ postal_code: zip, // #539: required, validated above
fda_registration_number: fdaReg.trim() || undefined,
roles,
});
- // #540 — Validate the returned facility ID before navigating.
+ // #540 - Validate the returned facility ID before navigating.
// An empty or malformed ID would produce an unusable URL and a broken
// next step. Surface the problem here rather than silently navigating.
const facilityId = facility?.id;
@@ -159,7 +159,7 @@ export default function FacilityPage() {
/>
- {/* Street address — #539: real field replaces hardcoded '--' */}
+ {/* Street address - #539: real field replaces hardcoded '--' */}
- {/* ZIP / FDA reg — #539: ZIP required with format validation */}
+ {/* ZIP / FDA reg - #539: ZIP required with format validation */}
)}
- {/* #541 — Error banner with retry; no silent redirect on failure */}
+ {/* #541 - Error banner with retry; no silent redirect on failure */}
{saveError && (
{saveError}
diff --git a/frontend/src/app/privacy/page.tsx b/frontend/src/app/privacy/page.tsx
index 9807a8c60..d2def65d6 100644
--- a/frontend/src/app/privacy/page.tsx
+++ b/frontend/src/app/privacy/page.tsx
@@ -222,7 +222,7 @@ export default function PrivacyPage() {
{/* ── Two-column layout: TOC + Content ───────────────── */}
- {/* Sticky TOC — desktop only */}
+ {/* Sticky TOC - desktop only */}
@@ -283,7 +283,7 @@ export default function PrivacyPage() {
- {/* ── What We Don't Do — highlighted callout ──── */}
+ {/* ── What We Don't Do: highlighted callout ──── */}
diff --git a/frontend/src/app/proof/page.tsx b/frontend/src/app/proof/page.tsx
index 0136fee33..5b4235333 100644
--- a/frontend/src/app/proof/page.tsx
+++ b/frontend/src/app/proof/page.tsx
@@ -74,7 +74,7 @@ function formatSize(bytes: number): string {
}
/**
- * A terminal transcript. SPEC §5.1: code is a well — one surface step below the
+ * A terminal transcript. SPEC §5.1: code is a well - one surface step below the
* card, bounded by a hairline rather than an inverted ink block. Result lines
* keep a status colour, but never alone: each one carries its own word ("ok",
* "matched", "FAILED"), so the meaning survives greyscale.
diff --git a/frontend/src/app/remediation/page.tsx b/frontend/src/app/remediation/page.tsx
index 9bb34bb4a..b7ff339a7 100644
--- a/frontend/src/app/remediation/page.tsx
+++ b/frontend/src/app/remediation/page.tsx
@@ -95,7 +95,7 @@ function IssuedLinkPanel({ url, email }: { url: string; email: string | null })
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
- // Clipboard denied (insecure context, permission) — the URL is on screen.
+ // Clipboard denied (insecure context, permission) - the URL is on screen.
}
};
@@ -151,7 +151,7 @@ export default function RemediationPage() {
const releaseManifest = useReleaseManifest(tid);
const issueLink = useIssueCorrectionLink(tid);
- // Latest outbox entry per case (list is newest-first) — the per-case
+ // Latest outbox entry per case (list is newest-first) - the per-case
// delivery state shown in the manifest detail table.
const outboxByCase = useMemo(() => {
const byCase = new Map();
@@ -444,7 +444,7 @@ export default function RemediationPage() {
)}
- {/* Notification outbox — queued link emails are delivered by the drainer */}
+ {/* Notification outbox - queued link emails are delivered by the drainer */}
- {/* Back link — the shell owns the breadcrumb, this stays as the
+ {/* Back link - the shell owns the breadcrumb, this stays as the
page's own return affordance. */}
- {/* Email — read-only, sourced from auth */}
+ {/* Email - read-only, sourced from auth */}
- {/* Role and Email — read-only account facts */}
+ {/* Role and Email - read-only account facts */}
Role
diff --git a/frontend/src/app/settings/security/page.tsx b/frontend/src/app/settings/security/page.tsx
index ff73cf73c..9a1c5cd0b 100644
--- a/frontend/src/app/settings/security/page.tsx
+++ b/frontend/src/app/settings/security/page.tsx
@@ -81,7 +81,7 @@ export default function SecuritySettingsPage() {
return (
- {/* Back link — the shell owns the breadcrumb, this stays as the page's
+ {/* Back link - the shell owns the breadcrumb, this stays as the page's
own return affordance. */}
- {/* Sticky TOC — desktop only */}
+ {/* Sticky TOC - desktop only */}
diff --git a/frontend/src/app/tools/data-import/components/DataImportClient.tsx b/frontend/src/app/tools/data-import/components/DataImportClient.tsx
index 81627da73..1202c9a29 100644
--- a/frontend/src/app/tools/data-import/components/DataImportClient.tsx
+++ b/frontend/src/app/tools/data-import/components/DataImportClient.tsx
@@ -74,7 +74,7 @@ const EXAMPLE_CURL = `curl -X POST https://regengine.co/api/v1/webhooks/ingest \
]
}'`;
-// Synthetic FSMA 204 traceability dataset — mirrors test_data/regengine_test_traceability.csv
+// Synthetic FSMA 204 traceability dataset - mirrors test_data/regengine_test_traceability.csv
const SAMPLE_EVENTS = [
{ event_type: 'HARVESTING', event_date: '2026-03-10', tlc: 'TLC1001', location_identifier: 'Green Valley Farm, Salinas, CA', product_description: 'Romaine Lettuce', gtin: '09524000059109', quantity: 1200, uom: 'cases' },
{ event_type: 'RECEIVING', event_date: '2026-03-10', tlc: 'TLC1001', location_identifier: 'Salinas Cold Storage, Salinas, CA', product_description: 'Romaine Lettuce', gtin: '09524000059109' },
diff --git a/frontend/src/app/trace/page.tsx b/frontend/src/app/trace/page.tsx
index 0b6c9f294..a2fb37a10 100644
--- a/frontend/src/app/trace/page.tsx
+++ b/frontend/src/app/trace/page.tsx
@@ -186,7 +186,7 @@ export default function TracePage() {
- {/* Error — the page's one alarm. `Callout` cannot be imported here:
+ {/* Error - the page's one alarm. `Callout` cannot be imported here:
src/__tests__/pages/trace.test.tsx mocks lucide-react with six
icons and vitest throws on any other icon access at import time. */}
{error && (
diff --git a/frontend/src/app/verify/page.tsx b/frontend/src/app/verify/page.tsx
index 40ffa4d18..5de2f73a6 100644
--- a/frontend/src/app/verify/page.tsx
+++ b/frontend/src/app/verify/page.tsx
@@ -119,7 +119,7 @@ const MANIFEST_COLUMNS: DataTableColumn[] = [
const PROSE_LINK =
'text-re-brand underline underline-offset-[3px] decoration-re-border-strong hover:decoration-re-brand';
-/** Terminal transcript colouring — the word on the line always carries the meaning too. */
+/** Terminal transcript colouring - the word on the line always carries the meaning too. */
function transcriptLineClass(line: string): string {
if (line.startsWith('✓ VALID')) return 'text-re-success';
if (line.startsWith('✗ INVALID')) return 'text-re-danger';
@@ -131,7 +131,7 @@ function transcriptLineClass(line: string): string {
}
/* ─────────────────────────────────────────────────────────────
- VerifyWidget — drop-and-verify export bundle
+ VerifyWidget: drop-and-verify export bundle
───────────────────────────────────────────────────────────── */
type VerifyCheck = { name: string; passed: boolean; detail?: string };
type VerifyResponse = {
diff --git a/frontend/src/components/dashboard/metrics-overview-widget.tsx b/frontend/src/components/dashboard/metrics-overview-widget.tsx
index 772d6a6a0..9cbdc3fef 100644
--- a/frontend/src/components/dashboard/metrics-overview-widget.tsx
+++ b/frontend/src/components/dashboard/metrics-overview-widget.tsx
@@ -11,7 +11,7 @@ import type { WorkbenchReadinessSnapshot } from "@/lib/api-hooks";
* Follows the data-viz rules (SPEC §4, §7.1): exactly one hero figure per view;
* a tile is label / value / delta / trend with no icon; the value is never
* coloured; only the delta arrow carries sentiment. The readiness score appears
- * here and nowhere else on the page — it used to be rendered twice, once in
+ * here and nowhere else on the page - it used to be rendered twice, once in
* this row and again in the "Traceability Readiness" card below it.
*/
export function MetricsOverviewWidget({
diff --git a/frontend/src/components/fsma-checklist.tsx b/frontend/src/components/fsma-checklist.tsx
index 1b1ea90fe..4dccac134 100644
--- a/frontend/src/components/fsma-checklist.tsx
+++ b/frontend/src/components/fsma-checklist.tsx
@@ -127,7 +127,7 @@ export default function FSMAChecklist() {
}
};
- // Band colour for the readiness meter. The number itself stays ink — the
+ // Band colour for the readiness meter. The number itself stays ink - the
// meter is a supporting mark, and "N/8" carries the meaning on its own.
const scoreBarClass =
checkedCount <= 3
diff --git a/frontend/src/components/fsma/readiness-assessment.tsx b/frontend/src/components/fsma/readiness-assessment.tsx
index ebb5ca11f..d8adfa498 100644
--- a/frontend/src/components/fsma/readiness-assessment.tsx
+++ b/frontend/src/components/fsma/readiness-assessment.tsx
@@ -26,7 +26,7 @@ import {
import { FSMA_ENFORCEMENT_DATE, FSMA_ENFORCEMENT_FRAMING } from '@/lib/fsma-enforcement';
import { trackReadinessAssessmentSubmit, trackToolRunCompleted, trackToolRunStarted } from '@/lib/conversion-events';
-// Food Traceability List categories — synced with the final FDA FTL as implemented
+// Food Traceability List categories - synced with the final FDA FTL as implemented
// in src/app/tools/ftl-checker/components/FTLCheckerClient.tsx (source of truth)
const FTL_CATEGORIES = [
{ id: 'leafy-greens-fresh', name: 'Leafy Greens (fresh, intact)', examples: 'Whole leaf lettuce, spinach bunches, kale, arugula, chard, collard greens', icon: Leaf },
diff --git a/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx b/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
index 3778a1561..9baac9b74 100644
--- a/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
+++ b/frontend/src/components/marketing/sandbox-grid/SandboxResultView.tsx
@@ -1,6 +1,6 @@
'use client';
-// #2757 — extracted verbatim from the shared-result page so /sandbox and
+// #2757 - extracted verbatim from the shared-result page so /sandbox and
// /sandbox/results/[id] render one diagnosis, not two that drift apart.
// Presentational only: no fetching, no analytics. Callers own those.
diff --git a/frontend/src/components/mobile/FieldCaptureClient.tsx b/frontend/src/components/mobile/FieldCaptureClient.tsx
index 0580a6723..a7fe14bf0 100644
--- a/frontend/src/components/mobile/FieldCaptureClient.tsx
+++ b/frontend/src/components/mobile/FieldCaptureClient.tsx
@@ -336,7 +336,7 @@ export function FieldCaptureClient() {
description: `${productName}: ${visionData.fsma_kdes?.length || 0} KDEs extracted`,
});
} else {
- // Vision failed — fall back to raw file upload
+ // Vision failed - fall back to raw file upload
await ingestFileMutation.mutateAsync({ file, sourceSystem: 'mobile_capture_pwa' });
toast({ title: 'Photo Uploaded', description: 'Vision analysis unavailable. Raw image stored.' });
}
diff --git a/frontend/src/components/ui/data-table.tsx b/frontend/src/components/ui/data-table.tsx
index 2525192cf..cf89310b9 100644
--- a/frontend/src/components/ui/data-table.tsx
+++ b/frontend/src/components/ui/data-table.tsx
@@ -20,7 +20,7 @@ import { Skeleton } from "@/components/ui/skeleton"
import { cn } from "@/lib/utils"
/**
- * DataTable — SPEC §4.
+ * DataTable - SPEC §4.
*
* Columns are a plain descriptor array rather than TanStack `ColumnDef`
* generics: there is exactly one obvious implementation, which is what keeps
@@ -48,7 +48,7 @@ export type DataTableSort = { key: string; direction: "asc" | "desc" }
export interface DataTableProps {
columns: DataTableColumn[]
data: T[]
- /** Visually hidden by default — the table's accessible name. */
+ /** Visually hidden by default - the table's accessible name. */
caption: string
density?: "low" | "medium" | "high"
toolbar?: {
diff --git a/frontend/src/components/ui/stat-tile.tsx b/frontend/src/components/ui/stat-tile.tsx
index 3ddd845b5..d5681ed0f 100644
--- a/frontend/src/components/ui/stat-tile.tsx
+++ b/frontend/src/components/ui/stat-tile.tsx
@@ -7,18 +7,18 @@ import { cn } from "@/lib/utils"
import { NO_DATA_YET } from "@/lib/empty-values"
/**
- * StatTile — SPEC §4, following the data-viz rules.
+ * StatTile - SPEC §4, following the data-viz rules.
*
* Anatomy is fixed: label / value / optional delta / optional trend. There is
- * deliberately **no icon slot** — an icon slot is what let three competing tile
+ * deliberately **no icon slot** - an icon slot is what let three competing tile
* styles grow across the dashboard last time.
*
* Colour rules:
- * · the value is never coloured — it is always `text-re-text-primary`;
+ * · the value is never coloured - it is always `text-re-text-primary`;
* · the delta *text* stays secondary; only the arrow carries sentiment colour,
* with an sr-only word so the direction is not colour-only;
- * · the sparkline is aria-hidden and decorative — the delta carries the
- * meaning — and is `text-tertiary` on every tile except the hero, which is
+ * · the sparkline is aria-hidden and decorative - the delta carries the
+ * meaning - and is `text-tertiary` on every tile except the hero, which is
* the one place a brand stroke is allowed.
*
* Exactly one `hero` tile per view.
@@ -36,7 +36,7 @@ export interface StatTileProps {
value: React.ReactNode
unit?: string
delta?: StatTileDelta
- /** 8–30 points. Omit for no chart. */
+ /** 8-30 points. Omit for no chart. */
trend?: number[]
/** A StatusBadge, typically. */
status?: React.ReactNode
diff --git a/frontend/src/lib/api-client.ts b/frontend/src/lib/api-client.ts
index 76abd66d4..89e21bd81 100644
--- a/frontend/src/lib/api-client.ts
+++ b/frontend/src/lib/api-client.ts
@@ -427,7 +427,7 @@ class APIClient {
const formData = new FormData();
formData.append('file', file);
formData.append('source', sourceSystem);
- // cte_type is optional — the backend auto-detects from a cte_type/event_type column
+ // cte_type is optional - the backend auto-detects from a cte_type/event_type column
if (cteType) {
formData.append('cte_type', cteType);
}
@@ -612,7 +612,7 @@ class APIClient {
}
// validateConfig() was removed on 2026-04-17 (#1203). The compliance
- // service's POST /validate endpoint was orphaned — no component ever
+ // service's POST /validate endpoint was orphaned: no component ever
// invoked the hook, and the real compliance evaluation lives in the
// ingestion service's /api/v1/rules/evaluate route via the versioned
// RulesEngine.
@@ -658,7 +658,7 @@ class APIClient {
}
/**
- * Ingest CTE events via the webhook endpoint — persists to fsma.cte_events + hash chain.
+ * Ingest CTE events via the webhook endpoint - persists to fsma.cte_events + hash chain.
* Use this for sample data loading and programmatic event ingestion.
*/
async ingestWebhookEvents(
@@ -876,7 +876,7 @@ class APIClient {
};
}
- // Bulk upload — uses adminClient (Vercel Pro proxy with maxDuration=300s)
+ // Bulk upload - uses adminClient (Vercel Pro proxy with maxDuration=300s)
async parseSupplierBulkUpload(file: File): Promise {
const formData = new FormData();
@@ -922,7 +922,7 @@ class APIClient {
return data;
}
- // Portal Links — supplier portal link management
+ // Portal Links - supplier portal link management
async listPortalLinks(): Promise<{ links: PortalLink[]; total: number }> {
const tenantId = this.currentTenantId;
if (!tenantId) throw new Error('No tenant selected');
@@ -954,7 +954,7 @@ class APIClient {
await this.ingestionClient.patch(`/api/v1/portal/links/${encodeURIComponent(portalId)}/revoke`);
}
- // Supplier Integration Profiles — saved field mappings for portal and file feeds
+ // Supplier Integration Profiles - saved field mappings for portal and file feeds
async listIntegrationProfiles(): Promise {
const tenantId = this.currentTenantId;
if (!tenantId) throw new Error('No tenant selected');
diff --git a/frontend/src/lib/api-config.ts b/frontend/src/lib/api-config.ts
index 045b310b6..2fd26cede 100644
--- a/frontend/src/lib/api-config.ts
+++ b/frontend/src/lib/api-config.ts
@@ -9,7 +9,7 @@ const SERVICE_PORTS = { ingestion: 8002, graph: 8200, compliance: 8500, admin: 8
type ServiceName = keyof typeof SERVICE_PORTS;
/**
- * Server-side only — resolve backend URL from env vars with localhost fallback.
+ * Server-side only - resolve backend URL from env vars with localhost fallback.
* Use this in Next.js API routes instead of inline `|| 'http://localhost:XXXX'`.
*/
export function getServerServiceURL(service: ServiceName): string {
diff --git a/frontend/src/lib/api-proxy.ts b/frontend/src/lib/api-proxy.ts
index 06f04a126..5ffd7befd 100644
--- a/frontend/src/lib/api-proxy.ts
+++ b/frontend/src/lib/api-proxy.ts
@@ -1,9 +1,9 @@
/**
* Shared utilities for API proxy routes.
*
- * – sanitizePath: prevents path traversal and null-byte injection
- * – proxyError: returns a consistent JSON error shape across all proxies
- * – validateProxySession: validates Supabase session tokens before proxying
+ * - sanitizePath: prevents path traversal and null-byte injection
+ * - proxyError: returns a consistent JSON error shape across all proxies
+ * - validateProxySession: validates Supabase session tokens before proxying
*/
import { NextRequest, NextResponse } from 'next/server';
@@ -58,7 +58,7 @@ export function validateUuid(value: string | undefined | null): string | null {
/**
* Resolve the authoritative tenant for an opaque `__Host-regengine_session`
* by calling the backend `/auth/me`. The session cookie is httpOnly and
- * server-validated, so the returned `organization_id` is trustworthy — unlike
+ * server-validated, so the returned `organization_id` is trustworthy - unlike
* the client-writable `re_tenant_id` cookie. Returns the tenant id (lowercased)
* or `null` when no server-derived tenant is available (caller must fail closed).
*
@@ -334,7 +334,7 @@ export function hasSupabaseSessionCookies(request: NextRequest): boolean {
// A real Supabase session is the `sb--auth-token` cookie (and its
// chunked `.0` / `.1` variants when the payload is large). The PKCE flow
// also writes a transient `sb--auth-token-code-verifier` cookie
- // that is NOT a session — it's just the verifier for an in-flight OAuth
+ // that is NOT a session - it's just the verifier for an in-flight OAuth
// exchange and can outlive the flow if the user navigates away. Matching
// it as a session caused authenticated RegEngine sessions to 401 at the
// proxy when supabase.auth.getUser() returned no user.
@@ -355,7 +355,7 @@ export function hasSupabaseSessionCookies(request: NextRequest): boolean {
*
* Only validates when Supabase cookies are present (sb-* cookies indicate
* the user authenticated via Supabase). API-key-only requests are validated
- * by the backend — the proxy can't verify those.
+ * by the backend - the proxy can't verify those.
*
* Returns a 401 NextResponse if the session is invalid/expired,
* or null if the request should proceed.
@@ -366,7 +366,7 @@ export async function validateProxySession(
): Promise {
const regengineToken = request.cookies.get('re_access_token')?.value;
if (isUsableCallerCredential(regengineToken)) {
- // Decode-only check — the backend (services/admin) owns JWTKeyRegistry
+ // Decode-only check - the backend (services/admin) owns JWTKeyRegistry
// and is the authoritative verifier. We reject malformed/expired tokens
// and obvious iss/aud mismatches up front, then compare the JWT's
// tenant_id claim against the re_tenant_id cookie for defense-in-depth.
@@ -389,7 +389,7 @@ export async function validateProxySession(
}
// The RegEngine JWT is an authoritative caller credential. Don't fall
- // through to the Supabase check — stale `sb-*` cookies (e.g. leftover
+ // through to the Supabase check - stale `sb-*` cookies (e.g. leftover
// PKCE `-code-verifier`) would otherwise fail Supabase validation and
// 401 a request that already authenticated successfully.
return null;
@@ -426,7 +426,7 @@ export async function validateProxySession(
return null;
}
- // Also skip if the request carries an API key — backend handles that auth
+ // Also skip if the request carries an API key - backend handles that auth
const hasApiKey =
!!request.cookies.get('re_api_key')?.value ||
!!request.headers.get('x-regengine-api-key');
@@ -463,7 +463,7 @@ export async function validateProxySession(
{ status: 401 },
);
}
- // Supabase SDK error — don't block requests that also carry backend-validated
+ // Supabase SDK error - don't block requests that also carry backend-validated
// credentials; let the backend make the final auth decision.
return null;
}
diff --git a/frontend/src/lib/auth-context.tsx b/frontend/src/lib/auth-context.tsx
index b22ecc629..f01197839 100644
--- a/frontend/src/lib/auth-context.tsx
+++ b/frontend/src/lib/auth-context.tsx
@@ -36,7 +36,7 @@ type LoginOptions = {
};
/**
- * HTTP-only cookie auth — CRITICAL #2 fix complete.
+ * HTTP-only cookie auth - CRITICAL #2 fix complete.
*
* Sensitive credentials (access_token and tenant API keys) are stored
* ONLY in HTTP-only cookies via /api/session. They are never readable
@@ -50,7 +50,7 @@ type LoginOptions = {
* access is derived from the authenticated user session, never from a key.
*/
-/** Placeholder value for apiKey — indicates credentials are
+/** Placeholder value for apiKey - indicates credentials are
* managed server-side in HTTP-only cookies. NOT the real key. */
const COOKIE_MANAGED_PLACEHOLDER = 'cookie-managed';
@@ -59,13 +59,13 @@ const STORAGE_KEYS = {
ONBOARDED: 'regengine_onboarded',
DEMO_MODE: 'regengine_demo_mode',
USER: 'regengine_user',
- // DEPRECATED — migrated to HTTP-only cookies, then removed from localStorage
+ // DEPRECATED - migrated to HTTP-only cookies, then removed from localStorage
_LEGACY_API_KEY: 'regengine_api_key',
_LEGACY_ACCESS_TOKEN: 'regengine_access_token',
};
// ---------------------------------------------------------------------------
-// Cookie helpers — talk to /api/session (server-side)
+// Cookie helpers - talk to /api/session (server-side)
// ---------------------------------------------------------------------------
/** Store sensitive credentials in HTTP-only cookies via /api/session POST.
@@ -90,13 +90,13 @@ async function setSessionCookies(params: {
// double-submit check, so this POST needs a valid X-CSRF-Token header.
// GET /api/session is idempotent and sets the cookie pair on first
// call. The auth provider runs this on mount, but on cold-start /
- // SSR'd login pages the hydrate effect may not have fired yet — call
+ // SSR'd login pages the hydrate effect may not have fired yet: call
// bootstrap defensively here so a freshly-loaded login page can submit
// immediately without race-conditioning on the hydrate fetch.
if (!document.cookie.includes('re_csrf=')) {
try {
await fetch('/api/session', { method: 'GET', credentials: 'include' });
- } catch { /* fall through — POST will surface the error if cookies still missing */ }
+ } catch { /* fall through: POST will surface the error if cookies still missing */ }
}
const res = await fetchWithCsrf('/api/session', {
method: 'POST',
@@ -133,7 +133,7 @@ async function clearSessionCookies(): Promise {
}
}
-/** Check current session via /api/session GET — never returns raw tokens. */
+/** Check current session via /api/session GET - never returns raw tokens. */
async function getSessionInfo(): Promise<{
authenticated: boolean;
has_api_key: boolean;
@@ -302,7 +302,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setAccessTokenState(COOKIE_MANAGED_PLACEHOLDER);
apiClient.setAccessToken(COOKIE_MANAGED_PLACEHOLDER);
} else if (!loginCompletedRef.current) {
- // Definitive unauthenticated answer — the cookie session expired or
+ // Definitive unauthenticated answer - the cookie session expired or
// was cleared server-side. Drop the localStorage-hydrated user (and
// ignore any session.user echoed back from a stale re_user cookie)
// so pages can't render an authenticated shell from stale state.
@@ -316,7 +316,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setApiKeyState(COOKIE_MANAGED_PLACEHOLDER);
}
} else {
- // The session check itself failed (network error or non-2xx —
+ // The session check itself failed (network error or non-2xx -
// /api/session GET otherwise always answers 200 with an
// `authenticated` boolean). Indeterminate: keep the
// localStorage-hydrated state rather than logging the user out of
@@ -335,7 +335,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const setApiKey = useCallback(async (key: string | null) => {
if (key) {
- // MUST await — middleware checks this cookie on the next request.
+ // MUST await - middleware checks this cookie on the next request.
// Setting state before the cookie is written causes a race condition
// where the app appears authenticated but middleware rejects the request.
const cookiesOk = await setSessionCookies({ apiKey: key });
@@ -351,7 +351,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const setTenantId = useCallback(async (id: string | null) => {
if (typeof window !== 'undefined') {
if (id) {
- // Await cookie write before updating state — middleware needs the
+ // Await cookie write before updating state - middleware needs the
// tenant cookie in place before any navigation triggers a request.
await setSessionCookies({ tenantId: id });
localStorage.setItem(STORAGE_KEYS.TENANT_ID, id);
@@ -395,7 +395,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
logoutInProgressRef.current = false;
const normalizedLoginUser = normalizeUserProfile(loginUser);
- // Non-React state — these don't trigger re-renders or effects.
+ // Non-React state - these don't trigger re-renders or effects.
apiClient.setAccessToken(COOKIE_MANAGED_PLACEHOLDER);
apiClient.setUser(normalizedLoginUser);
if (loginTenantId) apiClient.setCurrentTenant(loginTenantId);
@@ -409,13 +409,13 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
//
// React state updates below can trigger navigation to /dashboard (or the
// ?next= path). The middleware runs on that navigation and checks
- // re_access_token — if the cookie isn't in the browser yet, middleware
+ // re_access_token - if the cookie isn't in the browser yet, middleware
// rejects and redirects back to /login?next=/dashboard.
//
// Awaiting setSessionCookies first lets the Set-Cookie response be
// processed by the browser before any navigation can occur.
//
- // #535: Check the return value — if the /api/session POST fails (network
+ // #535: Check the return value - if the /api/session POST fails (network
// error, server error) we must throw rather than silently continue.
// A false return means the re_access_token cookie was never written, so
// the very next middleware check would reject the user and redirect back
@@ -434,7 +434,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
loginCompletedRef.current = true;
- // React state updates — triggers re-renders and the navigation useEffect.
+ // React state updates - triggers re-renders and the navigation useEffect.
// Cookie should be stored in the browser at this point.
setAccessTokenState(COOKIE_MANAGED_PLACEHOLDER);
setAuthMethodState(null);
diff --git a/frontend/src/lib/csrf.ts b/frontend/src/lib/csrf.ts
index ac87643d4..28c01a312 100644
--- a/frontend/src/lib/csrf.ts
+++ b/frontend/src/lib/csrf.ts
@@ -1,5 +1,5 @@
/**
- * CSRF Protection — Double-Submit Cookie Pattern
+ * CSRF Protection - Double-Submit Cookie Pattern
*
* Defense-in-depth on top of SameSite=Lax cookies. State-changing requests
* (POST/PUT/PATCH/DELETE) to /api/* must include an X-CSRF-Token header
@@ -7,8 +7,8 @@
*
* Token flow:
* 1. POST /api/session sets two cookies:
- * - re_csrf (httpOnly: false, JS-readable) — random token
- * - re_csrf_sig (httpOnly: true) — HMAC-SHA256(token, secret)
+ * - re_csrf (httpOnly: false, JS-readable) - random token
+ * - re_csrf_sig (httpOnly: true) - HMAC-SHA256(token, secret)
* 2. Client reads re_csrf from document.cookie and sends it as X-CSRF-Token header
* 3. Middleware verifies: HMAC(headerValue, secret) === re_csrf_sig cookie
*/
@@ -25,7 +25,7 @@ export { CSRF_COOKIE, CSRF_SIG_COOKIE, CSRF_HEADER };
/** Get the CSRF signing secret.
*
- * Production REQUIRES a dedicated CSRF_SECRET — reusing AUTH_SECRET_KEY (the
+ * Production REQUIRES a dedicated CSRF_SECRET - reusing AUTH_SECRET_KEY (the
* JWT signing key) for HMAC violates cryptographic key separation
* (NIST SP 800-57 §5.2). The AUTH_SECRET_KEY fallback is preserved only for
* dev/test convenience. RE-SEC-005.
@@ -111,7 +111,7 @@ export const CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']
/** Routes exempt from CSRF checks (pre-auth ceremonies, signed webhooks, and API-key routes).
*
* Keep this list narrow. Broad prefixes like /api/tools/ silently exempt
- * every future handler placed there — list the specific public endpoints
+ * every future handler placed there - list the specific public endpoints
* instead so adding a new /api/tools/* route is a deliberate decision.
*
* /api/session is intentionally NOT exempt. GET /api/session bootstraps the
@@ -121,17 +121,17 @@ export const CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']
* like every other mutating endpoint. The Origin allowlist on POST
* /api/session (RE-SEC-003) remains as defense-in-depth.
*
- * #2885 MATCHING RULE — read this before adding an entry. isCsrfExempt() is
+ * #2885 MATCHING RULE - read this before adding an entry. isCsrfExempt() is
* called from src/proxy.ts with `request.nextUrl.pathname`, i.e. the path the
* BROWSER requested, before any rewrite or proxy runs. An entry only ever
- * matches if it is a real frontend path — either a next.config.js rewrite
+ * matches if it is a real frontend path - either a next.config.js rewrite
* source or a route under src/app/api. A backend path does NOT match the
* same-origin BFF path that proxies to it: '/api/v1/webhooks/' does not
* prefix-match '/api/ingestion/api/v1/webhooks/ingest'. That mismatch is what
* 403'd every developer-playground POST (#2885); the fix was to send the CSRF
* header via fetchWithCsrf, NOT to widen this list.
*
- * Verified 2026-08-26 — each entry against next.config.js and src/app/api:
+ * Verified 2026-08-26 - each entry against next.config.js and src/app/api:
* /api/auth/ rewrite source (next.config.js:229) ✓
* /api/admin/auth/ src/app/api/admin/[...path] ✓
* /api/admin/v1/auth/accept-invite src/app/api/admin/[...path] ✓
@@ -143,7 +143,7 @@ export const CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']
* /api/inflow-lab/ src/app/api/inflow-lab/[...path] ✓
* /api/tools/check-access src/app/api/tools/check-access ✓
* /api/tools/verify src/app/api/tools/verify ✓
- * /api/webhooks/ DEAD — no rewrite source and no handler
+ * /api/webhooks/ DEAD - no rewrite source and no handler
* under src/app/api/webhooks. It matches
* nothing today, so it grants nothing;
* it is kept only because removing an
@@ -152,7 +152,7 @@ export const CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']
* src/__tests__/lib/csrf-exempt-prefixes.test.ts.
* If you add a local webhook handler
* there, that handler becomes CSRF-exempt
- * silently — decide then, on purpose.
+ * silently - decide then, on purpose.
*/
export type CsrfExemptionRule = Readonly<{
methods: readonly string[];
diff --git a/frontend/src/lib/customer-readiness.ts b/frontend/src/lib/customer-readiness.ts
index 9443503fb..9cbd77427 100644
--- a/frontend/src/lib/customer-readiness.ts
+++ b/frontend/src/lib/customer-readiness.ts
@@ -397,7 +397,7 @@ export const SUPPORT_CHANNELS: SupportChannel[] = [
];
// Sample export-job configurations rendered on the Trust Center page as
-// examples of supported configurations — NOT live production telemetry.
+// examples of supported configurations - NOT live production telemetry.
// Timestamps and manifest hashes below are placeholder strings and must
// not be presented as real run data; the Trust Center renderer hides
// timestamps for this reason. If you add a renderer that surfaces
diff --git a/frontend/src/lib/fsma-enforcement.ts b/frontend/src/lib/fsma-enforcement.ts
index a09861412..59f3ab472 100644
--- a/frontend/src/lib/fsma-enforcement.ts
+++ b/frontend/src/lib/fsma-enforcement.ts
@@ -2,7 +2,7 @@
// the Continuing Appropriations Act of 2026 (Nov 2025) directed FDA not to
// enforce the Food Traceability Rule before July 20, 2028, and FDA has stated
// it intends to comply. The Aug 2025 compliance-date-extension rule is still
-// only a PROPOSED rule — never state the compliance date "was extended" as
+// only a PROPOSED rule - never state the compliance date "was extended" as
// settled fact. The requirements themselves are unchanged.
export const FSMA_ENFORCEMENT_DATE = 'July 20, 2028';
diff --git a/frontend/src/lib/ftl-data.ts b/frontend/src/lib/ftl-data.ts
index e887fe72d..5140c67e0 100644
--- a/frontend/src/lib/ftl-data.ts
+++ b/frontend/src/lib/ftl-data.ts
@@ -2,7 +2,7 @@
* FDA Food Traceability List (FTL) category data.
*
* Shared between the full FTL Checker tool and the onboarding quick-check.
- * Source: 21 CFR Part 1, Subpart S — FDA Food Traceability Rule (FSMA 204)
+ * Source: 21 CFR Part 1, Subpart S - FDA Food Traceability Rule (FSMA 204)
*/
export interface FTLCategory {
diff --git a/frontend/src/lib/proxy-factory.ts b/frontend/src/lib/proxy-factory.ts
index b0fdbcb8c..db73aacdb 100644
--- a/frontend/src/lib/proxy-factory.ts
+++ b/frontend/src/lib/proxy-factory.ts
@@ -1,5 +1,5 @@
/**
- * Proxy factory — shared scaffolding for Next.js catch-all proxy route
+ * Proxy factory - shared scaffolding for Next.js catch-all proxy route
* handlers (the files under src/app/api//[...path]/route.ts).
*
* The frontend fronts several backend services (admin, ingestion, compliance,
@@ -458,7 +458,7 @@ export function createStreamProxy(config: StreamProxyConfig): MethodHandlers {
}
// ---------------------------------------------------------------------------
-// Shared helpers — used by proxy `buildHeaders` implementations
+// Shared helpers - used by proxy `buildHeaders` implementations
// ---------------------------------------------------------------------------
/** Strip trailing slashes from a URL base. */
diff --git a/frontend/src/lib/roi-calculator-data.ts b/frontend/src/lib/roi-calculator-data.ts
index 456b9cc71..829974e63 100644
--- a/frontend/src/lib/roi-calculator-data.ts
+++ b/frontend/src/lib/roi-calculator-data.ts
@@ -65,7 +65,7 @@ export const calculateROI = (answers: Record) => {
const manualHours = Number(answers['manual-hours'] || 0);
const annualRevenue = Number(answers['annual-revenue'] || 0);
- // ILLUSTRATIVE COEFFICIENTS — not forecasts, not industry benchmarks. Surfaced
+ // ILLUSTRATIVE COEFFICIENTS - not forecasts, not industry benchmarks. Surfaced
// honestly in the user-facing Methodology Note. Adjust here if assumptions change.
//
// 1. Modeled labor-time avoided: ManualHours * $75/hr loaded rate * 52 weeks * 0.85 capture rate