AI / Multi-tenant SaaS

CSS custom properties + CVA variants drive little/kid/tween/teen tap targets, density, and reading level. No per-age fork.
Every Prisma query and AI call scoped by familyId in extension code. A missed scope is a type error, not a security incident.
Chicknz is a multi-tenant family management app built around an age-adaptive UI: one codebase that serves four distinct complexity tiers (little, kid, tween, teen) so a four-year-old and a fourteen-year-old get experiences tuned to their reading level, motor skills, and motivation patterns.
The stack is Next.js 15, Prisma + PostgreSQL, Better Auth for parent/kid auth (OAuth + PIN), Vercel AI SDK with Anthropic Claude for background intelligence (chore rotation, summaries, NL task creation), Ably for realtime, and a Vercel Blob layer for media.
Family-management apps either ship a single generic UI that doesn't fit any age group, or shard into multiple apps and lose the shared family state. The goal was to keep one shared multi-tenant data model (every query scoped by `familyId`) while presenting four parallel UI tiers driven by CSS custom properties and CVA variants.
Four UI tiers (little / kid / tween / teen) driven by CSS custom properties and CVA variants. Tap targets, icon size, density, and reading level all flex per age group from a single component library.
Anthropic Claude (Haiku for fast paths, Sonnet for generation) powers natural-language chore creation, fair-rotation scheduling, and weekly family summaries. Embedded in the workflow, not bolted on as a chatbot.
Every database query and AI call is scoped to a familyId. Better Auth handles parent OAuth and kid PIN flows; Ably broadcasts realtime updates inside a family without crossing tenant boundaries.
A four-year-old and a fourteen-year-old can't share one UI, and I refused to fork the app to give each their own. So I pushed the whole age gap into CSS tokens and component variants: one library, four reading levels. The right abstraction turns a product decision into a styling decision, so a whole age tier becomes something you configure instead of rebuild.
Four age groups need genuinely different interfaces, but forking into four apps would shatter the shared family state and kill velocity.
I drove every age difference (tap target, icon size, density, reading level) through CSS custom properties and CVA variants on a single component library.
Age-adaptive UI is engineering, not just design. Get the tokens right and shipping a new tier costs a config, not a fork.
In multi-tenant data, one missed scope leaks one family's kids to another, and middleware checks are easy to forget on the next new query.
I scoped every query by familyId inside the Prisma extension layer, not in the route handlers.
Push tenancy down to the data layer and a missed scope becomes a type error at compile time instead of a security incident in production.
Parents wanted the app to feel intelligent, but I will not put a chat surface in front of a child.
I wired Claude into the workflow (chore rotation, fair scheduling, weekly summaries) as background intelligence, never as a chatbot.
AI as orchestrator beats AI as chat for most products. The intelligence should show up in the outcome, not in a text box.