v1.0.10 légal item 2. The signup endpoint /api/v1/auth/register and
its frontend form now require a date of birth and refuse registrations
where the registrant would be < 16 years old at registration time.
Threshold rationale :
COPPA (US, < 13 forbidden) + RGPD strict (< 16 needs parental
consent in every EU member state at the highest interpretation).
16 is the conservative single cutoff that satisfies both regimes
without per-jurisdiction branching. If a future market needs a
different threshold, change MinRegistrationAgeYears in
internal/core/auth/service.go ; the frontend reads the same
constant so they stay aligned.
Backend changes
* dto.RegisterRequest gets a `Birthdate string` field, validated
`required,datetime=2006-01-02` so swaggo / orval emit the right
OpenAPI schema and the validator catches malformed values
before the handler even runs.
* AuthService.Register signature is now
(ctx, email, username, password, birthdate *time.Time). The
pointer lets internal seed paths / tests pass nil while the
public handler always supplies a parsed value.
* Age check uses a yearsBetween helper that handles the "anniversary
hasn't passed yet this year" case correctly (someone born
2008-05-01 is 16 on 2008+16-05-01, not on 2008+16-01-01).
* New sentinel auth.ErrUnderage ; handler maps it to 400 with a
friendly message ("You must be at least 16 years old to register")
so the SPA can render the right copy without parsing the message.
* 11 test call sites updated : test-only paths pass nil ; the
public-handler test (TestRegister_Success) and the in-package
handler test pass a fixture Birthdate "2000-01-15".
Frontend changes
* RegisterFormData type + zod schema in RegisterForm.tsx + initial
form state get a `birthdate` field.
* RegisterPageForm.tsx renders an `<AuthInput type="date">` with a
`max=` attr 16 years ago today (UX guard ; legal floor stays in
the API).
* useRegisterPage's validate() computes age client-side with the
same algorithm as backend ; emits localised errors
`birthdateRequired` / `birthdateInvalid` / `birthdateUnderage`
so the user gets immediate feedback.
* services/api/auth.ts RegisterRequest interface + register()
body include the new field.
Tests : `go test ./internal/core/auth ./internal/handlers -short`
passes ; `tsc --noEmit` clean ; `eslint src` 754 (baseline unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>