Coloriginz Design Systemshadcn custom registry

@col/auth-pages-starter

Versie: 1.1.0 Toegevoegd: 2026-08-03

Herkomst

Geëxtraheerd uit supplier-onboarding-vercel: de vier auth-pagina's (app/login, app/activate/[token], app/forgot-password, app/reset-password/[token]) en de drie bijbehorende API-routes (app/api/auth/{activate,forgot-password,reset-password}). Elke nieuwe Coloriginz-app met eigen gebruikersaccounts (dus niet uitsluitend SSO) heeft dezelfde vier schermen en dezelfde drie routes nodig — tot nu toe alleen als compositie binnen de onboarding-portal aanwezig.

De onboarding-portal is meteen ook consument #1: stap 1 van de extractie verving de losse <img>-logo's op drie van de vier pagina's door @col/brand-logo (de loginpagina deed dat al), zodat de bron die naar de registry gekopieerd is identiek is aan wat live staat.

Waarvoor

Vier complete pagina's en drie API-routes voor wachtwoord-gebaseerde authenticatie: inloggen (met optionele Microsoft SSO-knop erboven), accountactivatie via een tokenlink, "wachtwoord vergeten" en "wachtwoord resetten". Gebruik dit als startpunt voor elke app die eigen gebruikersaccounts met wachtwoord nodig heeft. Gebruik het niet als de app uitsluitend SSO gebruikt — dan is alleen @col/sso-button nodig, niet de wachtwoordvelden en de drie routes eromheen.

Dit is nadrukkelijk glue, geen component: alle zeven bestanden zijn van de consumer zodra ze geïnstalleerd zijn (registry:page / registry:file, niet registry:component). Een update van dit item overschrijft ze nooit — npx shadcn add @col/auth-pages-starter --overwrite is alleen voor de eerste installatie.

Je hoeft dit niet over te nemen

Wat hier de standaard is, is hoe het eruitziet: de opbouw van de kaart, de volgorde van logo, titel, SSO-knop en velden, de tussenruimtes. Dat hoort tussen apps hetzelfde te zijn.

De code is een startpunt, geen voorschrift. Past hij niet bij je stack, bouw hem dan na op basis van de preview op /auth-pages-starter — dat is precies waarvoor die preview bestaat. Ook een gedeeltelijke overname is prima: alleen de loginpagina, of alleen de vier schermen zonder de API-routes.

Dat is geen theorie. floriday-app draait op base-ui in plaats van Radix en kon de componenten van @col/demo-mode daarom niet letterlijk gebruiken; die app heeft ze nagebouwd met hetzelfde uiterlijk en gedrag. Precies de bedoeling.

Twee dingen zijn wél bindend, omdat ze anders per app uiteenlopen:

Wat je app moet leveren

Elk van de zeven bestanden gaat uit van modules die in col-design-system niet bestaan. Zonder onderstaande bouwt de app niet.

UI / i18n

Componenten uit dit design system

@col/auth-shell (schermlayout), @col/brand-logo (logo-weergave), @col/sso-button (Microsoft-knop) en, sinds 1.1.0, @col/rate-limit (de limiter achter de drie routes hieronder) zijn registryDependencies en worden automatisch meegeïnstalleerd — landt op lib/rate-limit.ts, zie docs/items/rate-limit.md.

Daarnaast staan de shadcn-primitives alert, button, card, input, label en separator in de dependencies. Let op bij een bestaande app: die worden opgehaald in hun huidige upstream-versie en overschrijven de kopie die de app al heeft. Bij de onboarding-portal zou dat AlertTitle van een <h5> naar een <div> brengen, met een andere layout — die kopie is ouder dan stock shadcn. Controleer na installatie dus ook git diff src/components/ui/.

Auth

Backend-contract van de drie routes

Alle drie routes zijn POST, ratelimiten via rateLimit(key, max, windowMs) uit @col/rate-limit (@/lib/rate-limit, sinds 1.1.0 een registryDependency van dit item — je hoeft er niets voor te doen), en valideren de body met een Zod-schema uit @/lib/validations. De sleutel is ${ip}:<route> — het IP komt uit x-forwarded-for / x-real-ip, de route-naam is de vaste string uit de tabel hieronder.

Vóór 1.1.0 riepen deze routes een rateLimit(ip, key, max, windowMs) aan uit een @/lib/rate-limit dat niet in dit item zat. Dat compileerde in de bronapp (die had zelf zo'n bestand geschreven) maar niet in een nieuwe app die alleen @col/auth-pages-starter installeerde — precies het gat dat @col/rate-limit als registryDependency dicht. Zie docs/items/rate-limit.md voor de beperkingen van de limiter zelf (in-memory, per serverless-instantie op Vercel).

Route Zod-schema Body → Succes Faalstatussen
POST /api/auth/activate activateSchema { token, password } { success: true } 400 ongeldige input / onbekend token, 410 verlopen token, 429 rate limit
POST /api/auth/forgot-password forgotPasswordSchema { email } altijd { success: true, message } (voorkomt account-enumeratie) 429 rate limit
POST /api/auth/reset-password resetPasswordSchema { token, password } { success: true } 400 ongeldige input / onbekend token, 410 verlopen token, 429 rate limit

Prisma User

De routes gaan uit van minimaal:

Veld Type Gebruikt door
email String forgot-password (opzoeken, case-insensitive)
passwordHash String? forgot-password (alleen versturen als gezet)
activationToken String? @unique activate + reset-password (hergebruikt veld — reset is een tweede toepassing van dezelfde tokenflow)
activationExpiresAt DateTime? activate + forgot-password + reset-password
isActive Boolean activate (zet op true)
firstName String forgot-password (in de e-mail)
preferredLanguage String? forgot-password (taal van de e-mail, valt terug op 'nl')
labels String[]? forgot-password (user.labels?.[0], merk voor de e-mail-branding)

Dit is de kale set die de gekopieerde routes nodig hebben. Een app zonder merken of i18n kan labels/preferredLanguage negeren, maar moet dan de route-code aanpassen — de schema's noch de route zelf maken die velden optioneel in gedrag, alleen in het Prisma-type.

Overig

Demo-mode blok op de loginpagina (optioneel, bron-specifiek)

Onder process.env.NEXT_PUBLIC_DEMO_MODE === 'true' toont de loginpagina een blok met vier hardcoded demo-accounts (admin@demo.nl / demo123, enz.) en een Ethereal-testmailbox-verwijzing. Dat is onboarding-portal-specifieke demo-content, geen generiek onderdeel van dit item — verwijder of vervang dit blok in login-page.tsx zodra de app eigen demo-accounts heeft, of laat de env var simpelweg altijd false als er geen demo-mode is.

Bestanden

Bestand Landt in Soort
login-page.tsx app/login/page.tsx glue — van de app
activate-page.tsx app/activate/[token]/page.tsx glue — van de app
forgot-password-page.tsx app/forgot-password/page.tsx glue — van de app
reset-password-page.tsx app/reset-password/[token]/page.tsx glue — van de app
activate-route.ts app/api/auth/activate/route.ts glue — van de app
forgot-password-route.ts app/api/auth/forgot-password/route.ts glue — van de app
reset-password-route.ts app/api/auth/reset-password/route.ts glue — van de app

Upstream shadcn-afhankelijkheden: alert, button, card, input, label, separator. Registry-afhankelijkheden: @col/auth-shell, @col/brand-logo, @col/sso-button, @col/rate-limit (sinds 1.1.0). Geen cssVars.

Gebruikt door

App Sinds versie Opmerkingen
supplier-onboarding-vercel (Onboarding Portal) 1.0.0 Bronapp. De vier pagina's op productie zijn de basis van dit item; ze zijn niet via shadcn add geïnstalleerd (dit item bestond nog niet toen ze gebouwd werden) maar wel byte-voor-byte de bron ervan.

Bewuste keuzes

Bekende beperkingen