Finance Portal · Systems Runbook · Working Draft

Carbotura Finance Portal — How It's Built

The investor-facing platform at /finance/: how someone gets in, what each access level unlocks, and where the confidential material actually lives. This is the surface where a mistake reaches an outside investor under a securities offering, so the gating rules here are stricter than anywhere else on the site.

Version 1.0 Updated 2026-08-19 Status Working Draft — Internal Companion Mega-Site + Deal Room

The three runbooks

  • Mega-Site — architecture, data stores, routing, forms, deploys, canon.
  • This one — the finance portal: access levels, the gate, deal-room tiers, compliance rules.
  • Deal Room — task-oriented: adding documents, creating rooms, sending links, the access review.

§ 00New Features

Newest first.

2026-08-19 — Deal Room: real, watermarked PDF downloads

The pre-existing "Allow download" toggles never actually worked — the only Content-Disposition header in the system sat on the route the PDF.js viewer fetches via XHR, which the browser never sees. There's now a distinct /api/doc/:doc_id/download route the viewer's real ⬇ Download button navigates to, gated by a single room-level setting (Edit Room → Download allowed), watermarking the viewer's email + date into the actual PDF bytes server-side (not just the on-screen overlay), and logging every download to the room's Views tab.

First production use: the Wells Fargo deal room, enabled at their request. Full detail in the Deal Room runbook and admin/dr/DEAL_ROOM_MODEL.md §6b.

2026-08-19 — Investor Qualification Questionnaire

A public, ungated 10-question form at /finance/qualify/ that scores every submission deterministically against a fixed 100-point rubric (proven capacity, check-size fit, decision-maker access, 90-day timeline, sector fit, structure understanding, transaction history, diligence clarity) and tiers it — Chairman (80–100), IR/Diligence (65–79), Nurture (50–64), Automated (<50). Built to stop "I'm interested" submissions from consuming data-room access and management time before anyone has confirmed they can actually close.

  • Notification: only Chairman and IR/Diligence tiers email Shannon + the Architect immediately. Everything else lands silently in the admin queue.
  • Two scores, never blended: the qualification score (the rubric above) is stored separately from form-guard's generic spam/bot risk score — a submission can be low-risk but low-qualification, or vice versa.
  • Admin surface: admin/js/tabs/investor-qualifications.js, under the Finance tab group. master_admin+ scoped to finance — same tier as the deal-room admin surface, not looser. List + detail view (score breakdown, the two comparable-deals card, review status/notes).
  • AI dossier — on-demand only, never automatic. An admin clicks "Run Dossier" to have Claude web-search-verify the entity's legitimacy and the two claimed comparable deals. Writes verified / unverified / contradicted findings per claim; never mutates the score or tier — it's a separate human-judgment artifact, not a scoring input.
  • Schema: investor_qualifications (own table — see schema/investor-qualification-v1.sql), not form_submissions.
No data-retention/erasure path yet. This table stores full investor identity plus AI-generated web research about named individuals — flagged to the Architect as a policy gap, not a blocker to the build.

2026-08-13 — Deal Room sessions last 90 days

Viewer sessions went from 24 hours to 90 days; manual grant links from 1 hour to 7 days (up to 30). A counterparty working through weeks of diligence no longer requests a fresh code every morning.

The trade: expiry no longer removes access — you do. The 90-day access review is now the operative control. Nothing reminds you it's due. An unreviewed session simply lives its full 90 days.

2026-08-13 — Manual Access Grant

For a recipient whose own email security quarantines the access code — common at banks. After verifying identity out-of-band, an admin issues a single-use link containing no code at all. Used successfully for a Wells Fargo contact whose bank filtered every OTP.

Check the Access-code attempts log first. If it shows masked_not_allowed rather than sent, no code was ever sent and the real problem is the allow-list — a grant won't fix that. That exact misdiagnosis happened; the recipient simply wasn't on the room's recipient list.

2026-08-13 — /finance/api/verify hardened

The investor verification endpoint now runs the shared form guard: length caps, email validation, rate limits, risk scoring and the review queue. Previously it validated presence only, and raw values reached a Teams card that renders markdown.

§ 01The investor journey

One path from cold visitor to executed subscription. Each step raises an access level, and every level is checked server-side on every request — never in the browser.

INVESTOR JOURNEY Public /finance/thesis/ /finance/access/ /finance/verify/ identity → accreditation → pitch → NDA 5-step wizard Admin grants level /admin/investors/ audited + reversible HUMAN DECISION Portal · Intelligence Deal Room PPM Subscription execute WHERE THE GATES ARE No gate Thesis, access, public deck pages. Rule 506(c) disclosure applies. OTP + NDA Portal, intelligence hub, T1 docs. Session is server-side, not a cookie flag. OTP + NDA + per-doc grant Tier 2 vault: financial model, cap structure, unsigned pipeline. NEVER DISCLOSED — NO TIER UNLOCKS THESE Vendor identities · full FMEA · URVS-2026 methodology inputs Commercial Canon §3.4.2. Permanent exclusions, no override, at any level.
Every level transition is a human decision recorded in the grant history. Nothing auto-promotes.

§ 02Access levels

One ladder, used everywhere access is checked. An investor resolves to exactly one row regardless of whether they arrived via the finance gate or CF Access.

LevelMeaningTypically unlocks
L0PublicThesis, access page, public decks
L1NDA signedPortal, Intelligence Hub, Tier 1 documents
L2QualifiedBroader diligence material
L3AccreditedCornerstone Preferred — required for the equity round
L4Lead / institutionalCap table, pipeline, deployment finance
L5ClosingExecution documents
L6Post-closeOngoing reporting
L7Trustee / bondholderBond programme material
L8BoardBoard-level material
L9ArchitectEverything

Managed at /admin/investors/. Every promotion and demotion writes a grant-history row with who, when and why.

Levels are not the whole story. A level sets a ceiling. A Tier 2 document additionally needs its own per-document grant, independent of the level — see §04.

§ 03The gate

Access is a server-side session, not a browser flag. Everything below is enforced in functions/api/finance/[[path]].js.

How someone gets in

  1. They request access — email entered at /finance/verify/.
  2. A one-time code is emailed (Resend, DKIM-signed).
  3. They verify; a server-side session is created.
  4. An admin grants an access level. This is a human decision — nothing auto-promotes on verification alone.

Rate limits, all in rlOverGate: code requests capped 6/hour per email and 20/hour per IP; verification attempts 10 per 10 min per email and 20 per 10 min per IP.

Enumeration-safe by design. Requesting a code for an address that isn't recognised returns the same response as one that is. Don't "improve" this by reporting unknown addresses — it would let anyone test whether a given investor is in the system.

§ 04What's behind it

The surfaces

PathWhat it is
/finance/Hub. Capital architecture, links to everything else.
/finance/thesis/Public, no NDA. The investment argument.
/finance/portal/Logged-in home. Rounds, compliance status, updates.
/finance/intelligence/Multi-module diligence hub — technology, IP, operating model, valuation.
/finance/data-room/Document library. View-only, watermarked, logged.
/finance/ppm/Private Placement Memorandum — index, condensed, full, viewer.
/finance/urvs/Urban Reserve Valuation Standard + scenario analysis.
/finance/portal/rounds/CLN · Cornerstone · Master Trust (stub).

ADeal Room tiers

Canon §3.4.2. Document tier and investor level are two separate checks — both must pass.

TierRequiresContains
T0 PublicNothing — shown pre-OTPPitch deck, market thesis
T1 ConfidentialOTP + NDACSA terms, regulatory, technical summary, ESG, risk
T2 VaultOTP + NDA + per-document grantFinancial model, capital structure, unsigned pipeline
A room ceiling of T2 does not reveal vault documents. Each one still needs an explicit, logged per-document grant with a named reason. Attaching a T2 doc to a T2 room discloses nothing by itself — that separation is deliberate and must not be "simplified".

Full operating detail is in the Deal Room runbook. That book is task-oriented; this one just places it in the wider picture.

BPPM

The offering document for the Cornerstone Preferred raise. Four surfaces: an index with all ten Parts, a condensed 5-page summary, the complete document, and an in-portal viewer that wraps it in a sandboxed iframe with ?s=part-N deep-linking.

carbotura.com/finance/ppm/* shows "Temporarily Unavailable" on purpose. That holding page is intentional and stays until the Architect explicitly removes it. Removal replaces it with an auth system — not with raw public access.

§ 05Compliance rules

This is a live securities offering. These constraints are legal, not stylistic.

  • Rule 506(c). General solicitation is permitted, but every investor must be verified accredited — self-certification alone is not enough for the equity round. That's why L3 exists as a distinct level.
  • Permanent exclusions. Vendor identities, the full FMEA, and URVS-2026 methodology inputs are never disclosed at any tier. No override exists. Don't add one.
  • URVS methodology. Summary and outputs may be disclosed under executed NDA, deal-room-gated, with the §3.4.1 legend. Formulas, model, proprietary inputs and calibration never are.
  • Third-party firms. No named professional-service firms in investor-facing content — generic descriptors only. Aon plc is the sole permitted named firm, as Insurance Broker of Record.
  • Deal-room access logs are the disclosure register. There is no separate register to maintain; the logs are it. That's why view logging must never be disabled.
  • Canon governs the numbers. Royalty mechanics, fee structures and per-ton figures come from carbotura-commercial-canon. Never hand-edit a figure in a finance page — check canon first.
Option A/B, Asset Swap and PARR are retired (Release 43). There is one CSA structure — Beneficiation Fee plus Circular Royalty™, no election. Any investor-facing surface presenting an election, under any framing including "a future option being considered", is a hard canon failure.

§ 06Operating it

Routine tasks and where they live

TaskWhere
Grant or change an access level/admin/investors/ — audited, reversible
Create a deal room, attach documents, mint a share link/admin/dr/ — see its runbook
Recipient didn't get their codeRoom → Access-code attempts. Read it before resending.
Recipient's email security blocks codesManual Access Grant — after out-of-band identity check
Review who still has accessRoom → Attendees. Do this ~90-daily; nothing prompts you.
An access request from the public form/admin/queue/ if it was held

Diagnosing "I can't get in"

  1. Check Access-code attempts. sent means it left us — their side is filtering. masked_not_allowed means we never sent it and the allow-list is the problem. These need completely different fixes.
  2. Check their screening status. Must be clear, not pending or blocked.
  3. Check both allow-lists. Room recipient list and the specific link's list — a link minted for one person doesn't work for another.
  4. Check their level against the document tiers. If every document is T2 and they cap at T1, they'll see an empty room rather than an error.
Most "the code never arrived" reports are not delivery failures. The commonest cause is an address that isn't on that specific link's allow-list — the system deliberately masks that to avoid confirming membership, so it looks like silence. Read the log first.

§ 07Known traps

TrapWhat happensWhat to do
Masked ≠ delivery failure An address not on the allow-list gets no code and no error, by design. Looks identical to a mail problem. Read Access-code attempts before resending or issuing a grant.
Duplicate share links Retry loops leave several live links on one room — each is a working front door. Revoke stale links during the access review.
Approving a queued submission Approve writes to live Attio. It is not a "mark as read". Judge legitimacy first; reject deletes.
Editing figures by hand Royalty and fee figures are canon-governed; a hand edit silently diverges from the model. Check carbotura-commercial-canon; flag for a model rerun.
PPM holding page Looks like a broken deploy. It isn't — it's deliberate. Leave it until the Architect says otherwise.
90-day sessions Access now persists far longer than most people assume. Revoke on deal death or personnel change; don't wait for expiry.