mwn

NODE_02

KastMe

An interactive portfolio at one address, for artists, models and photographers.

Role
Founder, design and development
Period
2025 to date
Status
Building
Stack
Next.js 16 · React 19 · TypeScript · Firebase Auth · Firestore · Cloud Storage · Tailwind 4 · Zod · Vitest · Vercel
Links
Visit
KastMe demo public page: a fictional wildlife photographer's photos float in a sphere around the profile card and a booking button.

The problem

KastMe home page: the headline “Your work deserves better than a list of links” above a gallery of images tilted in perspective.
The marketing site: one address, one sphere, not a list of links.

A photographer or a model puts a link-list in their bio. Their best image is three taps away. KastMe replaces the list with a public page at kastme.fr/their-slug where images and videos float in a sphere the visitor spins with a finger. The product is live and still being built: the marketing site, sign-up, editor and public pages run; billing is not wired yet.

The constraints

  • The public page must be fast and shareable: it will be opened from Instagram or TikTok, on a phone, on 4G, and its preview has to look good in messaging apps.
  • Every creative owns their address. The slug is a scarce resource and must be unique, with no race between two simultaneous sign-ups.
  • Client-side Firebase keys are public by design. Security can only rest on the rules.

Architecture decisions

Server-rendered public page with revalidation and a dynamic share image

The [slug] route is rendered on the server and cached with ISR. Each page generates its own Open Graph image from the creative's media, so the shared link shows their work rather than a logo. The older p/[id] URL form is permanently redirected to the slug.

Never turn a database outage into a 404

This is the most important rule in the repository. An ISR page answering notFound() because Firestore is briefly unavailable freezes a 404 in the CDN for every visitor of that creative. Infrastructure errors therefore surface as exceptions, hence uncached 500s, and only a genuinely missing document produces a 404.

Reserve route names, and prove it with a test

app/[slug] lives at the root, and a static route always beats a dynamic one. Adding app/blog/ without reserving blog would silently replace the page of the creative who owns that slug. The reserved list is shared between the router and the Firestore rules, and a unit test fails if a route segment is missing from it.

Slug uniqueness through a create-only collection

A slugs/{slug} collection accepts creation and refuses updates. Two simultaneous sign-ups for the same name cannot both succeed: the second write is rejected by the rules, not by an application check a race could slip past.

Architecture

Architecture KastMe : page publique SSR + ISR, Firestore, Storage, image OG, éditeur Un visiteur ouvre kastme.fr/slug. Le serveur rend la page et la met en cache par ISR, lit le portfolio dans Firestore et les médias dans Cloud Storage, et génère l'image de partage. L'éditeur sauvegarde via l'API validée par Zod et revalide la page. VISITEURkastme.fr/slug app/[slug] · SSR + ISRrevalidate 3600 · 404 si absent FIRESTOREportfolios · slugs · users ÉDITEURPATCH /api/portfolios/[id] · Zod CLOUD STORAGEimages 10 Mo · vidéos 50 Mo opengraph-imagegénérée depuis les médias revalidation de la page publique après sauvegarde

Security through rules

users/{uid} is never writable by the client: plan and role only change server-side through the Admin SDK. Portfolios are publicly readable and writable by their owner only. Storage confines writes to the user's folder, with whitelisted file types and caps of 10 MB per image and 50 MB per video. Every rules change runs against the emulator test suite before deployment.

What remains

Next system · NODE_03Capsule Manufacturing