Template
Signoff
An internal requests-and-approvals system that replaces email chains: employees submit typed requests via admin-defined forms, managers approve their reports' requests, and admins see everything with status tracking and an audit trail. It suits HR, IT and ops teams handling time off, equipment and service requests.
Internal request approval system · 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.
Start from this templateRead the build prompt
Typefaces
Chivo is a sharp, high-contrast-friendly grotesk with firm weights, suiting a pure-black enterprise console where weight is the only hierarchy.
- ChivoHeadings: card titles ~24px, 600-700
- ChivoBody: body and UI 14-16px, 400/500
Who it is for
- Operations teams
- IT service desks
- HR teams handling leave and equipment
- Managers approving direct reports
Layout
- Pure-black full-screen auth page with a faint dotted grid background
- Centered square-cornered card with thin border: dark tile holding a green clipboard-check icon, title, grey subtitle
- Segmented Login / Sign Up switcher
- Labelled email and password fields on dark grey inputs
- Full-width mint-green 'Sign In' button
- App: sidebar (Dashboard, My Requests, All Requests, Pending Approvals, Users, Settings, Profile); dashboard metric cards and charts; request tables with filter chips; request detail sheet with activity timeline; form-schema builder
Palette
Sharp, serious, minimal, enterprise, high-contrast. A pure-black console with one mint accent that signals 'approved'.
- background
#000000 - surface / inputs
#1f1f1f - border
#242424 - text
#fafafa - muted text
#a3a3a3 - primary mint
#33cc99 - icon tile
#0b1f18
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on background | 20.12:1 | 4.5:1 |
| Aa | muted text on background | 8.33:1 | 4.5:1 |
| Aa | muted / placeholder text on input surface | 6.53:1 | 4.5:1 |
| Aa | input text on input surface | 15.79:1 | 4.5:1 |
| Aa | mint primary text / focus ring on background | 10.24:1 | 4.5:1 |
| Aa | dark text on mint button | 9.65:1 | 4.5:1 |
| Aa | submitted status text | 8.26:1 | 4.5:1 |
| Aa | in-review status text | 12.58:1 | 4.5:1 |
| Aa | changes-requested status text | 9.28:1 | 4.5:1 |
| Aa | rejected status text | 7.59:1 | 4.5:1 |
| input border on background | 3.04:1 | 3: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
- Chivo 600-700, ~24px card title
- Body
- Chivo 400/500 at 14-16px
Single-family Chivo; utilitarian enterprise hierarchy with weight contrast only. Accessibility: body copy 16px or larger at 1.5+ line height with a ~70ch max measure; no text below 12px; weights under 400 only at 32px+; uppercase reserved for short labels with 0.05em+ tracking.
Spacing and imagery
Compact, grid-aligned, zero border radius everywhere (sharp corners), ~440px auth card, 16-24px internal padding, 1px hairline borders.
None beyond a single line icon and a subtle dot-grid texture; in-app bar and pie charts for volume and status.
Components
- Dot-grid background
- Auth card with segmented tabs
- Labelled inputs
- Mint primary button
- Collapsible sidebar / mobile slide-in nav
- Metric cards
- Volume and status charts
- Requests data table with filter chips
- Status badges (Draft → Rejected)
- Request detail sheet / bottom drawer
- Activity timeline
- Approve / reject / request-changes actions
- Dynamic form renderer
- Form schema builder
Interactions
- Login/Sign Up tab switch
- Filter chips for status, type, date range
- Global search
- Approve/reject with comment dialog
- Request changes returns item to submitter
- Sheet becomes bottom drawer on mobile
- Drag-and-drop field ordering in form builder
- Toasts for status changes
Data
Profile{user_id, full_name, department, manager_id}UserRole{user_id, role: employee|manager|admin}RequestType{id, name, form_schema(json), active}Request{id, type_id, requester_id, data(json), status: draft|submitted|in_review|changes_requested|approved|rejected, submitted_at}RequestEvent{request_id, actor_id, action, comment, created_at}
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 a template'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 templates) - 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.
### Goal
Build **Signoff**, an internal request and approval hub for small and mid-size organisations. Employees submit requests (time off, equipment, access, purchases) through forms that admins design; managers approve or push back on requests from their direct reports; admins oversee everything. Every step is recorded so there is always an audit trail.
### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix), lucide-react. react-hook-form + zod with a schema-driven renderer for dynamic forms, dnd-kit for ordering fields in the form builder, TanStack Query + TanStack Table for request lists, Recharts for dashboard charts, date-fns. Supabase: Auth (email/password), Postgres with RLS, and database functions for status transitions.
### Pages & layout
1. **Auth**: pure-black page with a subtle dot grid; centered sharp-cornered card with an icon tile, title, subtitle, Login/Sign Up segmented control, labelled inputs, full-width mint button.
2. **Dashboard**: metric cards (open, awaiting me, approved this month, median turnaround), volume-over-time bars, status distribution, requests by type.
3. **My Requests**: table of own requests with status badges; "New request" chooses a type then renders its form.
4. **Pending Approvals** (managers): queue of direct reports' submissions with approve / reject / request changes.
5. **All Requests** (admins): search, filter chips for status, type and date range.
6. **Request detail**: side sheet (bottom drawer on phones) showing fields, status, and activity timeline.
7. **Users** (admin): roles and manager assignment.
8. **Settings** (admin): request types and a visual form builder (text, number, date, select, checkbox, textarea; required toggles).
9. **Profile**.
Include a demo switcher that loads HR, Ops or IT sample data.
### Design system
Dark only, square corners. Tokens: `--background: #000000`, `--card: #000000`, `--foreground: #fafafa`, `--muted: #1f1f1f`, `--muted-foreground: #a3a3a3`, `--border: #242424`, `--primary: #33cc99`, `--primary-foreground: #0a0a0a`, `--radius: 0`. Status colours: submitted blue `#60a5fa`, in review amber `#fbbf24`, changes requested orange `#fb923c`, approved mint, rejected `#f87171`. Font: Chivo 400/500/600. Scale 12/14/16/20/24/32. 4px spacing grid; dense tables with 44px rows. Motion minimal: 150ms fades and sheet slides. Inputs use `--input-border: #5a5a5a` (the `#242424` border is for dividers only) and placeholders use `--muted-foreground`.
### Components & interactions
Buttons: primary mint, outline, ghost, destructive; loading spinner and disabled states. Filter chips toggle with a check. Approve/reject dialogs require a comment for rejection or change requests. Tables: skeleton rows, empty state per view ("Nothing waiting on you"), error banner with retry. Form builder: add, reorder, edit field; live preview.
### Data & state
Profile(manager_id), UserRole(employee|manager|admin), RequestType(form_schema JSON), Request(data JSON, status enum), RequestEvent(action, comment). Transitions happen through a `transition_request(id, action, comment)` function that checks the allowed state machine and writes an event. Seed three departments, ~15 fictional users and ~60 requests.
### Accessibility
Verify mint (#33cc99) on black and dark text on mint both exceed 4.5:1. Square focus outlines 2px mint with offset. Status badges include text labels. Dynamic forms generate `label`/`aria-describedby` for errors. Sheets trap focus and restore it on close. Charts get tabular alternatives. Type: body 16px+, line height 1.5+, max ~70ch, nothing under 12px. Verified contrast: body text #fafafa on #000000 = 20.12:1; muted text #a3a3a3 on #000000 = 8.33:1; muted / placeholder text #a3a3a3 on #1f1f1f = 6.53:1; input text #fafafa on #1f1f1f = 15.79:1.
### Security
Roles in a separate `user_roles` table read via a security-definer `has_role()` function. RLS: employees read and edit only their own drafts; managers read requests where requester's `manager_id = auth.uid()`; admins read all. Status changes only through the transition function (no direct UPDATE of status). Validate submitted data against the type's schema on the client with zod and again in the function. Events are append-only. Never expose other users' emails beyond what the role needs.
### Performance & SEO
Server-side pagination and indexes on status, requester and type. Code-split admin settings and charts. Entire app `noindex`; auth page has a simple title.
### Guardrails
- Original copy and fictional users only.
- Don't collect sensitive personal data in default forms (no medical detail for leave).
- Typed components, no `any`, visible errors.
- Done when: an admin creates a type with custom fields; an employee submits it; their manager (and only their manager or an admin) approves or requests changes; the timeline shows each step; dashboards reflect counts.