- Pond model with pond-level trash columns (ADR 0013) and settings jsonb
holding only deviations from the defaults (sidebar sort, font slots per
ADR 0016); migration 20260705090100_ponds
- shared: pond schemas/views and slugify (German transliteration,
URL-safe, length-capped); deterministic -2/-3 suffixes for collisions
- InterimAccessService: single place answering pond access questions
until the real role model lands in M5
- POST/GET /ponds, GET /ponds/:slug, PATCH/DELETE /ponds/:id, Site-Admin
trash + restore; personal pond auto-created on e-mail verification and
for active seed fixtures; personal ponds cannot be trashed
- e2e pack covering verify-flow pond creation, slug suffixes, rename,
foreign-pond 404s, trash/restore; slugify unit tests
Closes#21
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpQz6ypHJsLfMf4S6fyQEB
The web app grows its account surface: login (with next-redirect,
unverified-hint + resend), signup (react-hook-form + shared Zod
schemas, field-level api errors, closed-registration state fed by the
new public GET /auth/registration), e-mail verification, forgot/reset
password; a settings page with profile (locale applies immediately),
password change, and active-session management; a Site-Admin page for
instance name, default locale, and registration mode. AuthProvider
holds /auth/me, applies the profile locale, and backs route guards
(RequireAuth/RequireAnonymous/RequireSiteAdmin); the top bar gains a
user menu. All strings ship in the new auth/settings namespaces (de+
en); the exception filter now preserves handler-specific error codes.
Verified live: signup → Mailpit → verify → login → profile through
the Vite proxy.
Closes#16Closes#17Closes#18Closes#19
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MailService renders transactional mails (verify-email, reset-password)
from the new de/en `mails` i18n namespace — text plus minimal HTML
with escaped interpolation — and enqueues them into mail_outbox.
MailWorker delivers pending rows every 15s through an injectable
transport (nodemailer; faked in tests) with quadratic backoff and a
permanent FAILED state after five attempts, logged as a warning.
SMTP_* and APP_BASE_URL join the environment schema with defaults
matching the new Mailpit container in the dev overlay.
Closes#12
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Translation resources live in packages/shared/i18n/<lang>/<ns>.json
(common, errors) and ship with de and en. The web app initializes
react-i18next with bundled resources (?lng= wins, then the browser
language); all shell components use useTranslation and the temporary
t() stub is gone. The api localizes its uniform error bodies via a
minimal i18next instance negotiated from Accept-Language. `pnpm
i18n:check` fails CI when any key is missing in any language, backed
by tested helpers in @dorfteich/shared.
Closes#5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>