Platform/06stackbilt-web

stackbilt-web

GitHub: Stackbilt-dev/stackbilt-web (private) · TypeScript

The Astro 6 + React islands frontend that powers stackbilder.com. Part of the Stackbilt ecosystem — the user-facing surface that composes TarotScript (scaffold + agents), img-forge (image generation), worker-observability (Observe dashboard), and evidence-core (Trust Verifier) via Cloudflare service bindings.


Stack

Layer Technology
Framework Astro 6 (SSR, Cloudflare adapter)
UI React 19 islands
Styling Tailwind CSS (ind-* design tokens)
Runtime Cloudflare Workers + D1 + KV + R2
Auth edge-auth (service binding RPC)
Types TypeScript throughout

Architecture

Island discipline — one React island per complex page; Astro components for everything else. Server Islands stream personalized content (credit balance, recent activity) without client-side fetch.

Route tiers:

Tier Routes Auth
Public SSR / prerendered /, /pricing, /login, /register None
Anonymous preview POST /api/scaffold/preview None (TarotScript Phase 1)
Authenticated app /dashboard, /flows/*, /images/*, /observe, /settings Session cookie or Bearer ea_*
Trust verifier trust.stackbilder.com/… Public read

Edge auth middleware validates sessions at the nearest POP via AUTH_SERVICE RPC — no origin round-trip.


Domain Strategy

Domain Service Repo
stackbilder.com Platform frontend (this repo) stackbilt-web
api.stackbilt.dev Backend API edgestack-v2 (deprecated)
auth.stackbilt.dev Auth + billing edge-auth
docs.stackbilt.dev Documentation Stackbilt-dev/docs
blog.stackbilt.dev Blog roundtable
trust.stackbilder.com Trust page verifier stackbilt-web (subdomain)
mcp.stackbilt.dev/mcp MCP gateway stackbilt-mcp-gateway

Tools

Tool Routes Tier
Stackbilder — scaffold generator /flows/*, hero preview Free + Pro
img-forge — multi-provider AI images /images/* Free + Pro
Observeworker observability /observe, /api/observe/* Pro
Consultations — CTO + CISO AI advisors /agents/{cto,ciso} Pro (dogfood-gated)
Operator Playbooks /app/playbooks Pro
Trust Verifier trust.stackbilder.com/… Public

Sidebar groups: Build (Flows, Images) · Operate (Observe, Playbooks) · Advise (CISO, CTO).


Service Bindings

Binding Service Purpose
AUTH_SERVICE edge-auth Session/API-key validation, billing, entitlements
TAROTSCRIPT tarotscript-worker Default/CISO agent runtime + scaffold/Oracle engine
IMG_FORGE img-forge-gateway AI image generation
CODEBEAST codebeast Code review + signed /decide receipts (Trust Page)
OBSERVE_DB D1: stackbilt-observe Worker observability telemetry
TRUST_DB D1: stackbilt-trust Trust page publications + evidence receipts
AGENT_RECEIPTS_DB D1: stackbilt-agent-receipts First-party local agent runtime receipts
EVIDENCE_DB D1: stackbilt-evidence Evidence library assets
TRUST_BUNDLES R2: trust-bundles Trust Bundle storage
SESSION KV Rate-limit state + Oracle result caching

Bindings accessed via getEnv() in src/lib/bindings.ts. Do not use locals.runtime.env — removed in Astro v6.


Auth

Two paths in validateSession() (src/lib/auth.ts):

  1. API keyAuthorization: Bearer ea_*AUTH_SERVICE.validateApiKey() RPC
  2. Session cookiebetter-auth.session_token (dev) / __Secure-better-auth.session_token (prod) → AUTH_SERVICE.validateSession() RPC

Billing

Stripe is in live mode as of 2026-04-11 (acct_1T8cxHL8cDQ0gdtT). All Stripe API calls live in edge-auth — stackbilt-web holds no Stripe credentials and reaches billing exclusively via AUTH_SERVICE RPC.

Flows:

  • CheckoutPOST /api/billing/checkout → pre-flight getEntitlements() check returns 409 {code: "already_subscribed"} for paid tiers → AUTH_SERVICE.createCheckoutSession() → Stripe Checkout URL.
  • PortalPOST /api/billing/portalAUTH_SERVICE.createPortalSession() → Stripe Billing Portal URL. Returns 422 with actionable copy if the tenant has no Stripe customer (comp/admin/lapsed).
  • DowngradePOST /api/billing/downgradeAUTH_SERVICE.downgradeToFree() → three outcomes:
    • canceled — active sub scheduled to cancel at period end; tier stays Pro/Team until effectiveAt
    • no_subscription — admin/comp account; immediate tier flip
    • already_canceled — dangling stripe_subscription_id; immediate tier flip

Webhooks are handled entirely by edge-auth — there is no webhook handler in this repo.

Upgrade surfaces (/pricing, /dashboard, /settings, UsageCard) POST directly to /api/billing/checkout for authed Free users. /pricing SSR-branches CTAs on session state: anonymous → signup, authed Free → direct checkout, authed on current tier → disabled “Current plan” badge.


Security

Headers

Middleware (src/middleware/index.ts) sets on all responses:

Header Value
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy camera=(), microphone=(), geolocation=()
Strict-Transport-Security max-age=31536000; includeSubDomains
Content-Security-Policy-Report-Only Full policy; report-uri /api/csp-report

CSP is currently Report-Only. Flip to enforcing Content-Security-Policy after a clean 24–48h window. Policy allows 'self', GA4, Cloudflare Analytics, and Google Fonts. img-src is permissive (https:) until all image origins are audited.

POST /api/csp-report logs browser-reported violations to console.error (visible via wrangler tail).

Asset Proxy

/v2/assets/[...path] proxies authenticated img-forge asset requests:

  • Rejects paths containing .. or \ (400)
  • Requires validateSession() (401 for unauthenticated)
  • Cache-Control: private, max-age=3600 (no cross-identity edge caching)

The /img-forge showcase page bypasses the proxy — images resolve at SSR time via the service binding as base64 data URIs so anonymous visitors can see the gallery.


Evidence Engine (Pro)

The hosted Evidence Engine wraps evidence-core with D1-backed storage, a gap-fill LLM loop, tamper-evident receipts, and a Pro-gated UI. OSS library docs are in evidence-core; this section covers only the stackbilt-web layer.

Routes

Route Purpose
/app/evidence Workspace — compose, attest, manage drafts
/app/evidence/compose Lazy-human pipeline: validate → gap-fill → attest
/app/evidence/library Asset CRUD (Pro-gated; free → /pricing?gate=evidence-library)
/api/v1/evidence/* REST API backing all three UI surfaces

Pipeline

Compose → gap-fill → attest → trust page:

  1. Validateevidence-core scores content 0–100 against the selected Google policy version; detects gaps per EEAT pillar.
  2. Gap-fill — LLM polish loop (shared helper src/lib/evidence-gap-fill.ts). Injects library assets, redrafts, re-validates. Each run costs 1 evidence_gap_fills reservation. Monthly cap: 50 runs/mo for Pro/Team; free tier is gate-closed.
  3. Attest — creates an evidence_publications row with a receipt_version hash chain. /api/v1/evidence/attest accepts runGapFill: true to merge steps 2 + 3 in one call.
  4. Trust page — verifiable at trust.stackbilder.com/evidence/:hash. Re-hashes the row on render; surfaces as tampered on mismatch.

Receipt versions

Version Product label Adds
v1 Baseline
v2 critique_hash
v3 v2.1 plan_hash (Collaborative Planning)
v4 v2.2 gap_fill_hash binding the gap-fill pass

Unknown receipt versions surface as tampered — never silently downgrade to v1. See src/lib/evidence-receipts.ts:verifyRow.

Evidence library

Pro-gated (free → /pricing?gate=evidence-library). Dogfood users on free-tier org get the Pro cap. Asset content shape: { text: "..." } for all 8 types.

Tier Asset cap
Free 0
Pro 50
Team 50

LIBRARY_ASSET_LIMITS in src/lib/evidence-library.ts is the single source of truth.

Domain vocabulary

Evidence library assets are tagged with a domain. Food content uses three:

Tag Covers
food Recipes, cuisine, food history, grocery content, creator-facing food narratives
food_science Flavor chemistry, nutrition, food technology, academic research
food_regulation FDA/USDA/CFR citations, labeling law, food-safety regulation

Internal telemetry

Gap-fill runs write a trace row to OBSERVE_DB under the internal:evidence-gap-fill worker name. The INTERNAL_WORKER_SQL_FILTER prevents these rows from surfacing in tenant Observe UIs.


Observe (Pro)

The Observe dashboard wraps worker-observability with D1-backed storage and a Pro-gated live UI. OSS client docs are in worker-observability; this section covers the server side.

ODD architecture

Three pillars define the D1 schema and query surfaces:

Pillar Purpose Tables
Observability Execution-level visibility traces, metrics
Debugging Causal trace + log correlation spans, logs
Diagnostics Failure patterns + alerting alert_incidents

Two cost-guard tables: registered_workers (worker cap) and ingest_quotas (daily event budget).

COGS containment

D1 writes cost $1.00/M rows; each user request generates ~10 rows. Caps enforced at ingest:

Tier Workers Events/day/worker Retention Worst-case COGS
Free 1 10K 24h ~$0.10/mo
Pro ($29) 5 500K 30d ~$15/mo
Team ($99) 20 2M 30d ~$60/mo

checkAndRegisterWorker() returns 403 on worker cap; checkAndIncrementEventBudget() returns 429 on daily budget exceeded. Caps are defined in TIER_LIMITS in src/lib/observe.ts.

API endpoints

Method Path Description
POST /api/observe/ingest Unified batch ingest: { service, metrics?, spans?, logs?, alerts? }. Pro-gated. 64KB limit.
GET /api/observe/summary Per-worker stats: error rate, p95, request count
GET /api/observe/traces Paginated trace list with filters
GET /api/observe/traces/:id Trace detail with spans + correlated logs
GET /api/observe/alerts Alert incidents list

All read endpoints apply INTERNAL_WORKER_SQL_FILTER (worker_name NOT LIKE 'internal:%') — internal rows never appear in tenant UIs. Any new Observe query touching traces/spans/logs by worker_name must apply this filter.

Retention

Hourly cron trigger → src/worker.ts:handleScheduled() batch-deletes expired rows across all 5 telemetry tables (cap: 10K deletes per table per run). All rows carry expires_at for tier-aware TTL.


Consultations (CTO + CISO)

CTO and CISO AI advisors. Live as of 2026-04-20, Pro + dogfood-gated.

Route tree

/agents/[role] is the canonical public entry point. It resolves auth and entitlement, then redirects:

State Redirect
Entitled (Pro/Team/dogfood) /app/consult/[role]
Unauthenticated /consult/[role]
Authenticated but not entitled /consult/[role]?gate=<reason>

/app/consult/[role] is the authenticated session UI. /consult/[role] is the public marketing/gate page. /agents/[role] should be used in all external links — it handles the redirect logic so the destination stays stable as entitlement rules change.

Consultations is one tools registry entry (src/lib/tools.ts) but renders as two sidebar leaves under Advise: CISO and CTO, each pointing to /agents/ciso and /agents/cto respectively.


Development

pnpm dev              # Local dev (Astro + workerd)
pnpm build            # Production build
pnpm deploy           # Build + deploy to Cloudflare
pnpm typecheck        # tsc --noEmit

Local dev requires a valid Cloudflare auth token (Wrangler remote proxy). If the dev server is slow, deploy to preview instead — pnpm deploy is faster in practice.

Secrets are managed via wrangler secret put. Each secret rotation triggers a worker redeploy — plan secret rotations accordingly.


Testing

Playwright E2E against production (stackbilder.com). Two browser projects: chromium (1280×800) and mobile (390×844).

Suite Command Coverage
All pnpm test Full suite
Hero pnpm test:hero Scaffold flow + error states
Hero evals pnpm test:hero-evals Deterministic quality gate
Navigation pnpm test:nav Navigation, SEO, 404, OG tags
Funnel pnpm test:funnel Signup → paid conversion
Visual pnpm test:visual Golden screenshot regression
API key pnpm test:api-key API key auth (needs STACKBILT_API_KEY env)

Run pnpm test:update-snapshots after any intentional visual change.


Key Conventions

Scaffold starter presets/flows/new accepts ?starter=<key> to pre-fill the CreateFlow form. Keys: saas_api, dashboard_app, ai_chatbot, edge_api. Used by the dashboard welcome grid, RecentActivity empty state, and CreateFlow chips row.