Template
Courierform
An app for developers who want form submissions without building a backend: create an endpoint with a field schema, point any site's form at it, and see leads, errors and webhook deliveries in one dashboard. Leads can be routed to email and a webhook.
Headless form endpoints and lead-routing dashboard · App · Small tools and apps · full-stack app (auth + DB)
A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.
Add app screens
Pick up to 6 screens, such as a dashboard, settings or an empty state. Each is built in this design’s own palette and typefaces, with its states and guardrails.
Start from this templateRead the build prompt
Typefaces
Libre Franklin is a workmanlike grotesk that stays clear in tables and labels, and Cousine is a plain, neutral monospace for endpoint ids and JSON.
- Libre FranklinHeadings: page titles 20px 600, stat numbers 24px 600 tabular
- Libre FranklinBody: body 16px/1.5 400, tables 15px, labels 12px uppercase +0.05em
- CousineFigures and code: endpoint ids and JSON 14px
Patterns
- persistent left sidebar with account block
- breadcrumb top bar
- overview card with line chart and stat boxes
- three quick-link cards
- filterable recent-leads table
- endpoint schema builder
- log list with status dots
States it is designed for
- loading skeleton for chart and table
- no endpoints yet (create-first empty state)
- no leads for filter
- endpoint disabled (submissions rejected)
- webhook failure logged with retry
- validation error when a submission misses required fields (shown in logs)
- theme dark/light
Who it is for
- marketing-minded developers
- agencies running many landing pages
- growth teams
Layout
- Sidebar 220px: wordmark, nav (Dashboard, Endpoints, Leads, Logs, Support), account block and theme toggle at bottom; collapses to icons under 1280px and a sheet under 768px
- Top bar: breadcrumb (Home / Dashboard)
- Page header: title + one-line description
- Overview card: title and subtitle left, two stat boxes right (leads, errors), line chart of daily leads and errors for 30 days
- Quick links: three cards (Endpoints, Leads, Logs) with one-line descriptions
- Recent leads: filter input, endpoint select, column view menu, table with pagination
Palette
Clean, neutral, workmanlike. White cards on off-white with one warm red chart line.
- app background
#fafafa - card
#ffffff - primary text
#0a0a0a - secondary text
#737373 - input border
#8f8f8f - card dividers
#e5e5e5 - chart line: leads
#d9363e - chart line: errors
#6b7280 - primary button fill
#171717 - success log dot
#15803d - error text
#b91c1c
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text | 19.80:1 | 4.5:1 |
| Aa | muted text on card | 4.74:1 | 4.5:1 |
| Aa | muted text on app bg | 4.54:1 | 4.5:1 |
| Aa | button label | 17.93:1 | 4.5:1 |
| input border | 3.23:1 | 3:1 | |
| chart leads line | 4.62:1 | 3:1 | |
| chart errors line | 4.83:1 | 3:1 | |
| success dot | 5.02:1 | 3:1 | |
| Aa | error text | 6.47:1 | 4.5:1 |
As vibld’s tokens
The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.
- background
- card
- muted
- primary
- secondary
- accent
- destructive *
Type scale
- Display
- Libre Franklin 600, 20px/1.4 page titles
- Body
- Libre Franklin 400, 15px/1.5 in tables, 16px elsewhere
Stat numbers Libre Franklin 600 24px tabular; labels 12px uppercase with 0.05em tracking; Cousine 14px for endpoint ids and JSON.
Spacing and imagery
Dense app layout; 8px base; cards 16px padding; radius 8px; 1px hairline borders; no shadows; table rows 44px.
No photos; a single-series line chart with a hover tooltip; lucide icons in the sidebar.
Components
- AppSidebar
- Breadcrumb
- OverviewCard
- StatBox
- LineChart with tooltip
- QuickLinkCard
- LeadsTable
- EndpointSelect
- ColumnMenu
- EndpointForm with SchemaFieldList
- CodeSnippet (form action URL)
- LogList
- ThemeToggle
- DeleteEndpointDialog
Interactions
- Chart tooltip follows pointer and keyboard focus on points
- Table filter debounced 250ms; endpoint select filters server-side
- Schema builder: add field (name, type, required), drag to reorder with dnd-kit
- Copy endpoint URL and sample HTML form
- Toggle webhook/email routing with immediate save and toast
Data
Endpoint{id, user_id, name, schema[{key, type (string|email|number|boolean|date|url|phone), required}], format (json|form), enabled, email_to, webhook_url, webhook_enabled, token}Lead{id, endpoint_id, data jsonb, created_at}Log{id, endpoint_id, kind (success|error), message, created_at}Profile{id, email, plan (free|pro)}
Guardrails
Experience
- Show errors next to leads so failures are never hidden
- Every endpoint page shows a copy-paste HTML form snippet
- Disable rather than delete by default; deletion needs confirmation and warns about lost leads
- Filters persist in the URL
- Chart shows both leads and errors with a legend and text totals
Accessibility
- Chart has a data-table alternative and labelled series
- Table uses proper headers, sortable columns announce sort state
- Status dots always pair with text
- Sidebar nav uses aria-current
- Drag reordering has keyboard alternatives (move up/down buttons)
- Focus ring 2px near-black
Security
- RLS: endpoints, leads and logs selectable only by the endpoint owner (user_id = auth.uid() via endpoint join)
- Public ingest route validates the endpoint token and payload against the schema with zod; reject unknown fields
- Rate-limit ingest per endpoint and IP; add honeypot support and optional CORS allowlist
- Webhook targets validated against private-network ranges to prevent SSRF; signed webhook payloads
- Minimise PII: allow per-endpoint retention period and bulk delete
Build prompt
The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.
The baseline
### How to use these prompts Paste an entry's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project. ### Engineering baseline - TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind). - Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone. - Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only. - Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables. ### Data and auth baseline (full-stack entries) - Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views. - Store roles in a separate table checked by a security-definer function, never in a user-editable profile field. - Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs. - Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms. - Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data. ### Accessibility and UX baseline - Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change. - Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels. - Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images. - Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives. - Build mobile-first and test at 375px, 768px and 1280px. ### Content guardrails - Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text. - Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs. ### SaaS screen baseline - Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs. - Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible. - Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy. - Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke. - Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal Build **Courierform**, a headless form backend with a dashboard. A developer creates an endpoint, defines its fields, copies an HTML snippet into any site, and watches leads arrive. Each endpoint can email new leads and post them to a webhook. The dashboard makes volume, errors and recent leads visible at a glance. ### Stack Next.js (App Router), React, TypeScript, Tailwind CSS, shadcn/ui (Radix), lucide-react, Recharts for the line chart, TanStack Table for leads, dnd-kit for schema field ordering, react-hook-form + zod, TanStack Query. Supabase Auth and Postgres; a public ingest route handler (or Edge Function). A transactional email service for lead notifications. ### Pages & layout Shell: 220px sidebar (wordmark, Dashboard, Endpoints, Leads, Logs, Support; account block and theme toggle at the bottom) and a top bar with a breadcrumb. 1. **/dashboard**: title and description; overview card with two stat boxes (leads, errors) and a 30-day line chart; three quick-link cards; recent leads table with filter input, endpoint select and column menu. 2. **/endpoints**: list with enabled switch, lead count, last lead time; "New endpoint". 3. **/endpoints/[id]**: form (name, format, email_to, webhook url + switch), schema field list with drag handle, copyable endpoint URL and sample HTML form. 4. **/leads**: full table with pagination and JSON detail drawer. 5. **/logs**: list with status dot + text, endpoint, message, time. Sidebar collapses to icons under 1280px and a sheet under 768px; tables scroll horizontally inside their card. ### Design system - Colors: `--bg: #fafafa` (app background), `--surface: #ffffff` (card), `--fg: #0a0a0a` (primary text), `--muted: #737373` (secondary text), `--border: #8f8f8f` (input border), `--hairline: #e5e5e5` (card dividers), `--chart-leads: #d9363e` (chart line: leads), `--chart-errors: #6b7280` (chart line: errors), `--btn: #171717` (primary button fill), `--success: #15803d` (success log dot), `--danger: #b91c1c` (error text). - Fonts: Libre Franklin 600 titles 20px, 400 body 16px/1.5 (15px in tables), stat numbers 24px tabular; labels 12px uppercase, 0.05em tracking; Cousine 14px for ids and JSON. - Spacing: 8px base; card padding 16px; 16px grid gap; 44px table rows. - Radius: 8px cards and inputs, 6px buttons. - Shadows: none; hairlines `#e5e5e5` inside cards, `#8f8f8f` on inputs. - Motion: 150ms hovers; drawer slides 200ms; reduced motion removes slides. ### Components & interactions AppSidebar, Breadcrumb, OverviewCard, StatBox, LineChart (two series, legend, tooltip, keyboard-focusable points, "View as table"), QuickLinkCard, LeadsTable, EndpointSelect, ColumnMenu, EndpointForm, SchemaFieldList (dnd-kit with move up/down buttons), CodeSnippet with copy, LogList, ThemeToggle, DeleteEndpointDialog (type the endpoint name). ### Data & state Tables `endpoints(user_id, name, schema jsonb, format, enabled, email_to, webhook_url, webhook_enabled, token)`, `leads(endpoint_id, data jsonb, created_at)`, `logs(endpoint_id, kind, message, created_at)`. The ingest route looks up the endpoint by id + token, validates the body against a zod schema built from `schema`, inserts a lead or an error log, then fans out email and webhook. Daily counts come from a SQL view. Seed three endpoints and forty invented leads. ### Accessibility Chart has a data table alternative. Sortable headers announce direction. Status always includes text. Drag reordering has buttons. Focus ring 2px `#0a0a0a`. Verified contrast: body text: #0a0a0a on #ffffff = 19.8:1; muted text on card: #737373 on #ffffff = 4.74:1; muted text on app bg: #737373 on #fafafa = 4.54:1; button label: #ffffff on #171717 = 17.93:1; input border: #8f8f8f on #ffffff = 3.23:1; chart leads line: #d9363e on #ffffff = 4.62:1; chart errors line: #6b7280 on #ffffff = 4.83:1; success dot: #15803d on #ffffff = 5.02:1; error text: #b91c1c on #ffffff = 6.47:1. ### Security - RLS: `endpoints` owner-only for all operations; `leads` and `logs` select/delete only when the parent endpoint's `user_id = auth.uid()`; inserts only via the service role in the ingest route. - Ingest validates token and payload, rejects unknown fields, caps body size, rate-limits per endpoint and IP, supports a honeypot and an origin allowlist. - Webhook URLs must be HTTPS and not resolve to private ranges; sign payloads with an HMAC secret per endpoint. - Per-endpoint retention and bulk delete to minimise stored PII. ### Performance & SEO All app routes noindex. Paginate leads server-side; lazy-load Recharts. Aggregate counts in SQL, not in the browser. ### Guardrails - Invent all lead data; never ship real personal data in seeds. - Never drop a submission silently: success or error log for each. - Acceptance criteria: (1) a plain HTML form posts a lead that appears within seconds; (2) missing required fields create an error log; (3) webhook and email fire when enabled; (4) other users cannot see your leads; (5) chart and table are usable by keyboard and screen reader.