Anticode Open builder

A Next.js website template with admin and 2FA, generated from your design

Anticode's Next.js export isn't a starter you fill in. It's your designed site rewritten as an App Router project, with a server route behind every form, a middleware that issues a fresh Content-Security-Policy nonce on each request, four roles from owner to customer, authenticator-app sign-in for anyone who can see data, and an append-only audit log.

Updated · By the Anticode team

Where the design lives

Each part of the page becomes a typed server component in components/sections/ (Header.tsx, Hero.tsx, Services.tsx, Book.tsx, Contact.tsx and so on) with the words written into the JSX. app/page.tsx sets their order. The stylesheet becomes app/globals.css, opening with named tokens such as --color-accent and --radius-card, and lib/site.ts holds the name, the font and the services and times the booking form offers. A front-end developer can read the whole page in an afternoon. Most people looking for a nextjs website template with admin and 2FA end up restyling someone else's demo; here the starting point is a page you already approved.

Every form posts to a route handler

The public site ships no client JavaScript of its own. Forms are plain HTML posts to route handlers in app/api/, and the result comes back as a message at the top of the form that was sent (the <Flash> component). Each handler follows the same order:

  1. Refuse the request unless it came from this site (a same-origin check, the CSRF defence).
  2. Apply a rate limit stored in Postgres, keyed by the visitor's address. The contact route, for example, allows five messages per ten minutes.
  3. Validate the fields with Zod in lib/validate.ts.
  4. Write through Prisma inside a transaction that declares which role it acts for.
  5. Notify the owner by email through Resend, or print the email to the terminal if no key is set, then redirect back to the page.
The public routes
RouteWhat it does
/api/bookingsAccepts only the services and times in lib/site.ts, with a per-slot capacity that holds under simultaneous requests
/api/contactSaves the message and alerts the owner
/api/subscribeAdds a newsletter sign-up
/api/auth/magic-linkEmails a sign-in link to a customer

A nonce for every request

middleware.ts generates a random nonce per request and sends a policy with script-src 'self' 'nonce-…' 'strict-dynamic', so only the scripts Next.js renders with that nonce can run. It also sets frame-ancestors 'none', form-action 'self', object-src 'none' and, beyond the site itself, lets fonts and stylesheets load from Google Fonts alone. next.config.ts adds HSTS, X-Frame-Options: DENY, nosniff, a referrer policy and no-store caching for admin and account pages.

This is the pattern Next.js documents in its Content Security Policy guide: the middleware sets the policy and an x-nonce header, and Next.js attaches the nonce to its own scripts while rendering. The same guide spells out the cost: nonces require dynamic rendering, so pages are rendered per request rather than served as static files from a CDN cache. Newer Next.js releases call this file proxy; the export pins Next.js 15, where it is middleware.ts.

Four roles, enforced twice

Who can do what in the export
RoleCan
OwnerEverything, including inviting and removing team members and reading the audit log
AdminSee full booking and message details and change booking status
StaffSee bookings and messages with emails and phone numbers masked
CustomerSign in by email link and see only their own bookings

Roles are checked in the route code, and again by Postgres. The second migration turns on row-level security for every table, and each transaction sets the role it acts for, so a query that forgets a filter returns nothing rather than someone else's rows. Masking for staff happens on the server, so the full address never reaches a staff member's browser.

Two-factor sign-in and the audit log

Owners and admins must set up an authenticator app (TOTP, RFC 6238) on first sign-in before they can see any data, and a code can't be replayed. TOTP secrets are encrypted with ENCRYPTION_KEY; rotating that key resets everyone's two-factor set-up. npm run db:seed creates the first owner from OWNER_EMAIL and OWNER_PASSWORD, and owners invite admins and staff with a link that expires after 48 hours. Sign-ins, team changes and two-factor events go into an append-only log only owners can read.

Tests that guard the promises

npm test runs unit tests (scrypt hashing, encryption, TOTP against the RFC vectors, masking, validation) and guardrails that fail when a form posts to a route that doesn't exist, a section embeds a script or event handler, a route skips the same-origin or role check, a hard-coded secret appears, or a table loses row-level security.

Limits

  • It leaves Anticode behind. Connectors, analytics, CMS editing in the dashboard and the security report stay with the hosted site; the export has its own email alerts instead.
  • Prisma is pinned to version 6. Moving to a later major is a deliberate upgrade.
  • The day picker shows the next six days, rather than the hosted calendar's range.
  • Hosting is yours. It needs Node 20.12 or later and a Postgres database; see deploying to Vercel.

How to get the code out is covered in exporting an AI website to Next.js; the feature overview is on the Next.js export page.

Questions people ask

Does the exported site need JavaScript in the browser?

Its own pages don't: forms are plain HTML posts. The nonce policy exists to cover the Next.js runtime scripts.

Can staff see customers' email addresses?

No. Staff see bookings and messages with emails and phone numbers masked on the server. Admins and owners see them in full.

What happens if I lose ENCRYPTION_KEY?

Stored two-factor secrets can't be decrypted, so owners and admins set up their authenticator again.

Is it locked to Anticode?

No. There's no Anticode runtime in it. It's a standard Next.js app you can change and host anywhere Node runs.

Sources

  1. Next.js Docs: Content Security Policy, checked