Vefapp
A studio site with a TOTP-locked admin and a Claude-powered concierge.
Overview
Vefapp is the division's own site, and also a working case study. On the surface, an editorial layout, variable display serif, asymmetric grid, pure-CSS grain, but underneath is a full business backend: Edda, a concierge powered by with a cached system prompt, an -locked admin for the inboxes and cost tracking, and inside that admin a Project Starter that turns client enquiries into Code prompts. Server-rendered everywhere on with and the doing its quiet memoisation work, all written in CSS-first config and hosted on .
Software division
Problem
Studio sites usually end as a shop window: hero word, three-up grid, fade-in on scroll. That says little about what the studio actually does. We wanted ours to read like a printed quarterly on the surface while also carrying its own backend, an inbox for enquiries, a cost ledger for the chatbot, and a tool that turns those enquiries into a working spec, because the studio is the work behind the marketing, not the marketing alone.
Approach
The public surface is calm on the network: on the , statically generated case studies via , between the work index and the case study. Edda, the Vefapp concierge running on with a prompt-cached system prompt and a 30-req/min rate limit, sits embedded in the site. The /admin tree is gated by mandatory two-factor on every sign-in, and in requires in the for every read. Inside the admin is Project Starter: a architect with and tool use that takes a paste of a client brief and returns a structured build plan plus a ready-to-use Code prompt.
Outcome
A site that stands on its own typography rather than its animations, fast on the network because most of it is by the time it reaches the reader, and with a backend designed to support the work from the first enquiry email all the way to a finished build plan.
Key features
- 01Edda, a site-wide concierge with a cached system prompt and a lead-capture intro form
- 02An /admin tree gated by mandatory two-factor on every sign-in
- 03Project Starter: a architect returning a structured build plan and a Code prompt
- 04 on every table requires in the for every read
- 0530 req/min on /api/chat via an
- 06 streaming with a session-cookie ownership check per conversation
- 07 between the work index and case study with shared-element morphs
- 08Bilingual (Icelandic / English) with and strict message-key parity
- 09Built-in cost ledger for usage, broken down by model
- 10Pure-CSS film grain, no image asset shipped
Chatbot, Edda
- 01Site-wide concierge powered by ( by default; and selectable from the admin)
- 02Prompt-cached system prompt over the studio corpus, 5-minute TTL, big savings on the repeated prefix
- 03Lead-capture intro form: name + email before the first message, 7-day TTL in localStorage
- 04Streamed output, word by word, over
- 05Session-token cookie binds the conversationId to a specific session, stops UUID copy-paste between tabs
- 06Rate limited via an (30/min per IP hash); a per-instance in-memory bucket as fallback
- 07Markdown rendering with -sanitised links
- 08Tunable from the admin: model, effort, max tokens, extra guidance fenced in <admin_guidance> XML
Admin & Project Starter
- 01Mandatory two-factor on every sign-in ( Auth )
- 02Auto-generated QR code at first enrolment
- 03Inboxes for contact + quote enquiries with a status workflow (new → in progress → replied → archived)
- 04Chat conversations browsable with visitor name + email, cost shown per turn
- 05 cost ledger rolled up across 30 days, broken down by model and token kind
- 06Project Starter: a architect with and tool use that returns a structured BuildPlan
- 07Pattern-card library with a cache_control prefix so reruns cost a fraction
- 08Chatbot settings, persona, model, effort, max tokens, extra guidance, editable from the admin
Security
- 01Mandatory two-factor on every admin account
- 02 on every table requires in the for every read
- 03 re-check session + inside the action body, a leaked Next-Action id is inert
- 04Bounds on max-tokens and extra-guidance length prevent runaway spend
- 05 sliding-window rate limit on /api/chat, fail-closed in production when is unset
- 06, X-Frame-Options DENY, Permissions-Policy lockdown, in report-only ahead of enforcement
- 07-compliant cookie consent (four categories)
- 08 key isolated to the production environment
Performance & tooling
- 01Server-rendered everywhere on the , most of the page is by the first paint
- 02Statically generated case studies via , no database call per visit
- 03 in build (~8 seconds for a full production build)
- 04 removes manual memoisation, no useMemo / memo() in the codebase
- 05 on the system prompt, ~30k tokens read at 0.1× rate from the second turn on
- 06 CSS-first config, no tailwind.config.js
- 07ESLint 9 with flat config and the plugin
- 08Pure-CSS film grain, no image asset shipped
Stack
- Next.js 16.2
- Turbopack
- React 19.2
- React Compiler
- TypeScript
- Tailwind CSS v4
- next-intl
- View Transitions
- Supabase Postgres
- Supabase Auth (TOTP MFA)
- Anthropic Claude (Sonnet 4.6, Opus 4.7, Haiku 4.5)
- Anthropic SDK
- Upstash Redis
- Server-Sent Events
- react-markdown
- ESLint 9
- Vercel



