Skip to content
Work

leffloard.wtf

This site, and the private system behind it that runs my client work.

A rebuild of my site as one Next.js app: a public portfolio outside, and inside an admin for inquiries, projects, meetings and invoices, guarded like a bank login.

01

Context

The first version was a portfolio template with a request form: React on the front, FastAPI and MongoDB behind it, and a small admin to read requests. It worked, but my actual work (briefs, calls, revisions, invoices) still lived in chat threads and notes.

The goal of the rebuild: one place for all of it, with a public side simple enough for clients and an admin that I trust with money and client data.

02

Approach

One Next.js application replaces both the React frontend and the Python backend. The old request data is copied into the new inbox without the original being modified.

Everything ships in milestones, each with its own tests, and database changes are forward-only so any release can be rolled back by switching a folder.

03

Security

The admin assumes the password will leak one day, and plans for it:

  • argon2id passwords plus a mandatory authenticator code, or a passkey (Windows Hello, Touch ID) on its own.
  • Progressive lockouts per email address, and passkeys keep working while password sign-in is locked.
  • Sessions stored as hashes, ended after 30 idle minutes; a fresh identity check before any security change.
  • Authenticator secrets encrypted with AES-256-GCM; recovery codes stored only as keyed hashes.
  • A nonce-based Content Security Policy on every admin page, and an audit log of every sign-in and change.

04

Testing

Every milestone arrives with tests: unit tests for the pure parts (the TOTP code is checked against the RFC 6238 vectors), integration tests against a real MongoDB replica set, and browser tests that fail on any console error or CSP violation, including a passkey sign-in through a virtual authenticator.

Next step

Have a project in mind? Tell me what it needs to do.

A few sentences are enough to start. You get an honest answer: a rough estimate, the questions that matter, or a recommendation for someone better suited.