Skip to content
Corngate

Documentation centre

Decision log

Architecture decision records — every consequential choice, with its reasoning, in the open.

Rendered from docs/DECISIONS.md in the repository — the file is the source of truth. All documents

Short records of decisions with consequences. Newest last. Reversible decisions are marked ↺; hard-to-reverse ones ⚠.


ADR-001 — One Passport Engine with asset-type extension tables ↺

Date 2026-07-12 · Status accepted

One passports core table (identity, status, location, visibility, history hooks) with land_details / tree_details / farm_details extension tables, rather than three parallel schemas.

Why Claims, evidence, inspections, versions, disputes and certificates behave identically across asset types; duplicating them 3× guarantees drift. Extensions keep asset-specific fields typed and let new asset types (warehouse, equipment) join later without touching the core.

Consequence Queries join one extension table; the registry_public view flattens for the public site.

ADR-002 — Ownership modelled as claims, never as token-holdership ⚠

Date 2026-07-12 · Status accepted (product boundary, non-negotiable)

claims rows carry role (9 roles incl. customary interest holder), independent verification status, evidence links, effective dates and supersession. Certificate tokens are non-transferable and admin-migratable only.

Why Ghana land reality: statutory + customary tenure, stools, families, lessees, operators. Reducing this to "wallet owns NFT" would be legally wrong and harmful. The whitepaper and blueprint both fix this boundary.

Consequence More schema than an NFT mint; correct by construction. UI copy on every passport: token possession ≠ legal ownership.

ADR-003 — Six-state verification workflow with public failure states ↺

Date 2026-07-12 · Status accepted

unverified_claim → document_verified → field_verified with disputed, superseded, revoked as first-class public states. Seed data deliberately includes a disputed parcel (CG-LND-0002), a superseded tree (CG-TRE-0005) and a revoked tree (CG-TRE-0013).

Why A registry that only ever shows green badges is marketing. Auditability — including our mistakes and open disputes — is the product.

ADR-004 — Fixture-first data layer for demo resilience ↺

Date 2026-07-12 · Status accepted

Phase 1–2 serves the seeded registry from typed fixtures behind the exact function signatures the Supabase implementation will use (src/lib/data/passports.ts). No env vars, keys or network needed to run the full public site.

Why Demo resilience is a stated requirement; the founder must be able to npm run dev and present without secrets. It also forces a clean data-access seam before Supabase arrives.

Consequence Phase 3 swaps implementations behind the seam; pages don't change. Fixtures then become the SQL seed.

ADR-005 — Schematic SVG map first; Mapbox GL behind a token flag ↺

Date 2026-07-12 · Status accepted

The registry map is a server-rendered, survey-sheet-style SVG projected from public generalised geometry, with parcel polygons and status-coloured points, linked to passports. When NEXT_PUBLIC_MAPBOX_TOKEN is set, an interactive Mapbox GL view replaces it (Phase 2.1) behind the same props.

Why Spec requires Mapbox GL JS, but the site must never show a broken grey map tile in a demo because a token is missing or offline. The SVG renders always, is fast, accessible and honest ("schematic map" label).

ADR-006 — Public geometry generalised by default ⚠

Date 2026-07-12 · Status accepted (privacy boundary)

Public centroids ~1 km precision; public tree points ~100 m; public boundaries simplified. Precise geometry lives in columns with no anon RLS path and is released only to staff/granted institutions.

Why Exact farm coordinates + publicly listed asset values is a theft/targeting risk and a data-protection problem. Whitepaper §13 requires it.

ADR-007 — Honest simulation labelling for blockchain certificates ⚠

Date 2026-07-12 · Status accepted (honesty boundary)

Without Amoy credentials, certificates are simulated: labelled prominently, no invented tx hashes (enforced by DB check simulated_has_no_tx), no explorer links. Real issuance (Phase 5) flips simulated=false and requires a tx hash.

Why "Actual Amoy demo certificates where credentials are supplied; otherwise honest simulation labels" — and fabricated hashes would be exactly the kind of fake proof Corngate exists to eliminate.

ADR-008 — Mainnet excluded at the schema and flag level ⚠

Date 2026-07-12 · Status accepted (regulatory gate)

certificates.network has check (network = 'polygon-amoy'); flags.MAINNET defaults false; no mainnet RPC config exists in .env.example. Enabling mainnet requires a new migration + explicit founder decision recorded here.

ADR-009 — Payment abstraction with mock mode; no provider hard-coded ↺

Date 2026-07-12 · Status accepted

payments.provider is a string adapter name; mode ∈ {mock, live}. Phase 6 implements the adapter interface (Stripe-compatible shape) + a Ghana adapter interface (e.g. MoMo aggregator) behind PAYMENT_PROVIDER env.

Why Ghana payment rails differ from Stripe's coverage; the blueprint forbids hard-coding a provider before pilot rates/providers are chosen.

ADR-010 — Founding Forest conveys recognition only ⚠

Date 2026-07-12 · Status accepted (regulatory boundary)

Sponsorship rows require accepted disclosures (accepted_no_ownership, accepted_no_return — DB-enforced) and record the disclosure text version. Disclosures appear at selection, checkout and on the passport.

ADR-011 — Grow is a waitlist and nothing else in v0.1 ⚠

Date 2026-07-12 · Status accepted (regulatory boundary)

Schema stores waitlist + jurisdiction + suitability answers + mandatory "no offer" acknowledgement. There is no table for units, balances or distributions, and no code path that accepts funds. Sample data room (Phase 8) uses clearly-labelled fictional data.

ADR-012 — System font stacks in v0.1 ↺

Date 2026-07-12 · Status superseded by ADR-016 (2026-07-13)

Editorial serif display stack (Iowan Old Style → Palatino → Georgia) + system sans, defined as design tokens. No build-time font downloads (offline builds, faster cold start). Revisit with self-hosted fonts (e.g. Fraunces/Inter via next/font local) in Phase 2 polish.

ADR-016 — Self-hosted Fraunces + Inter via next/font local ↺

Date 2026-07-13 · Status accepted

The Phase 2 polish planned in ADR-012 is done: Fraunces (variable, opsz/wght/SOFT/WONK axes, roman + italic) is the display face and Inter (variable, wght) the text face, vendored as woff2 in src/fonts/ under the SIL OFL (licence files alongside) and loaded with next/font/local. No network is touched at build or runtime — the offline-build property that motivated ADR-012 is preserved — and the previous system stacks remain as fallbacks in the token definitions (@theme inline in globals.css). Display headings set font-optical-sizing: auto with SOFT 20 / WONK 0: editorial warmth without the wonky look.

ADR-017 — Amoy contract deployed from a funded burner; fees pinned ↺

Date 2026-07-13 · Status accepted

CorngatePassportRegistry is live on Polygon Amoy at 0xf1b7a49A4EB1D35c161b941B85c9dD4A903dd6c0 (deploy tx 0x26e4aebe…4ea0c9dd, 18/18 tests passing at deploy). The deployer/issuer key is the faucet-funded burner in contracts/.env (never committed); in Vercel it exists as a sensitive, production-only env var so preview builds cannot spend gas. Issuance pins maxPriorityFeePerGas to Amoy's 25 gwei floor (maxFee 30) — the public RPC suggests ~90 gwei, which would triple gas spend for no inclusion benefit. Chain-mode issuance now also records the certificate row in the registry DB in the same action (chain first, then DB; a DB failure surfaces the tx hash for manual reconciliation). This key is testnet-only: the mainnet key ceremony remains gated by MAINNET_READINESS.md §B.

ADR-018 — Interactive map: MapLibre GL + OpenFreeMap, keyless, schematic SVG as the permanent fallback ↺

Date 2026-07-13 · Status accepted

The registry map is now a real interactive map — MapLibre GL JS v5 (BSD, community-governed successor to Mapbox GL v1) rendering OpenFreeMap Positron vector tiles: no API key, no usage limits, production use explicitly permitted, OSM attribution shown on-map. This replaces the planned "Mapbox behind a token" (the token requirement was the reason the map stayed schematic; keyless removes the reason).

Progressive enhancement, not replacement. The server-rendered schematic SVG remains the first paint, the no-JS experience, the offline/demo-mode map, and the fallback whenever style or tile loading fails. MapLibre loads as a lazily-imported client chunk and swaps in only when the basemap is actually ready, so First Load JS on every page is unchanged and demo resilience (a core Phase 9 property) is preserved.

Privacy is enforced in the camera, not just the data. The map renders only the public read model (generalised centroids and simplified boundaries — precise geometry never reaches the client, migration 0004). Additionally maxZoom is capped at 16 so the map cannot imply survey precision the data does not have.

Interaction grammar (patterns from current cadastral/parcel viewers — Regrid, state parcel portals, MapLibre feature-state examples): status-coloured parcels and points using the exact design-token colours; per-feature hover highlight via setFeatureState; a hover card with name, reference, status and key facts; click-through to the passport; dashed outlines for disputed parcels; cooperative gestures so page scroll is never hijacked; prefers-reduced-motion respected; zoom capped 8–16; compact attribution. Single-feature mode (passport pages) renders a non-interactive locator at a fixed generalised zoom.

Satellite imagery is a config slot, not a bundled default. Keyless satellite sources carry licence conditions (Esri World Imagery requires an account and non-revenue use; EOX Sentinel-2 is non-commercial). NEXT_PUBLIC_SATELLITE_STYLE_URL accepts any licensed raster style URL and adds a layer toggle when present; nothing ships enabled. The Mapbox token flag is removed. Future option if offline interactive maps are ever needed: a PMTiles extract of the pilot district served from public/.

ADR-019 — Real media policy + the first real records enter as unverified claims ↺

Date 2026-07-13 · Status accepted

Real Corngate Farms media (maize operations, Aperade & Kubenta, Achiase District) now appears on the site under three rules. (1) No faces: only shots without identifiable faces are published until written consent is collected (tracked in GROUND_TRUTH_INTAKE.md); crops are used where needed. (2) No location leakage: images are re-encoded on export, which strips EXIF GPS; registry locations stay locality-level (Aperade: village centroid; Kubenta: district centroid until GPS capture — Kubenta has no OSM entry). (3) No false attribution: photos are shown at operation level in the homepage "From the field" section, not attached to specific parcels, until the founder maps photo→farm in the intake. Consequently the per-record photo slots on the two new records still render labelled placeholders (ADR-013 stands).

The two real farms enter the registry as CG-FRM-0002 (Aperade) and CG-FRM-0003 (Kubenta) at unverified_claim, founder-entered, with explicit disclosures that the registry operator's own farms receive no verification shortcuts. This makes the honesty architecture demonstrable on real records: the lifecycle now starts where every future registrant starts. Rows exist in both the live DB and the demo fixtures (seed count 23 → 25).

ADR-014 — Dual-mode platform: live (Supabase) with an honest demo fallback ↺

Date 2026-07-12 · Status accepted

Every authenticated workflow runs in two modes behind one seam (src/lib/mode.ts): live when Supabase env vars exist (real auth via magic link, persistence via register_asset/decide_registration RPCs), and demo otherwise (labelled persona sessions via cookie, in-process store, submissions reset on restart). Demo mode is loudly labelled everywhere — banners on sessions, disclosures on demo-created passports.

Why The founder must be able to run and present the complete cycle — register → verify → passport appears in the public registry — with zero external services, and nothing on the site may pretend to be what it isn't.

Consequence Demo store code is exercised daily; live RPC paths are written to spec and marked "needs live verification pass" in STATUS.md until tested against a real Supabase project.

ADR-015 — Registration is an application, not a passport ↺

Date 2026-07-12 · Status accepted

Wizard submission creates an application (demo: CG-REG-…; live: a passport row at unverified_claim). Only a verifier decision — with a mandatory written note, logged and attributed — produces a document-verified passport. Approval in demo mode inserts the new passport into the running public registry so the full loop is demonstrable.

ADR-013 — Seed photographs are labelled illustrative placeholders ↺

Date 2026-07-12 · Status accepted — founder action required before public launch

The spec requires real field photographs; none exist yet in the repo. Rather than fake them, every image slot renders an SVG placeholder stamped "Illustrative — photo pending". Launch checklist blocks public launch until real photos replace placeholders via the content entry workflow.

ADR-020 — Institutional identity: crest-anchored navy/gold, civic type, restrained motion ↺

Date 2026-07-14 · Status accepted

The site's visual identity is re-anchored to the official Corngate Farms master crest: navy #0f1f3b becomes the authority colour (display headings, primary actions) and crest gold #d9ad45 the accent, both sampled from public/brand/corngate-farms-logo.png. Forest remains the field/verification colour; the status scale is untouched. Type moves from Fraunces/Inter to Libre Franklin (display) + Public Sans (text) — Franklin Gothic lineage and the U.S. Web Design System typeface respectively: deliberately civic, regulator-adjacent voices. Font token names (--font-fraunces/--font-inter) are kept so components are untouched. The homepage is restructured as a What/How/Why story: sparse copy, full-bleed real photography (face-free throughout, per the ADR-019 consent rule), and a motion system (scroll-reveal, count-up, CSS scroll-driven image drift) that collapses to a fully-visible static layout without JavaScript or under prefers-reduced-motion.

Why The audience is regulators, banks and institutions; the previous editorial-serif voice read more journal than registry. Anchoring to the crest makes brand and product tell one story, and honest photography sells the real-world half better than prose was doing.

Consequence Fraunces/Inter woff2 files retire from src/fonts once no page references them; any page relying on serif display inherits Franklin automatically via the kept token names. Depth of copy moved to /docs and the whitepaper — the homepage argues, the documents prove.