document password reset flow in CLAUDE.md and reset-password page

This commit is contained in:
Davide Scaini
2026-04-14 22:34:15 +02:00
parent 8fbd9a95e8
commit 9419bd0c20
2 changed files with 19 additions and 1 deletions
+17
View File
@@ -235,6 +235,23 @@ Key facts:
`fetch('/api/me')` auth wall; `/login/` and `/register/` have `public={true}` to skip it `fetch('/api/me')` auth wall; `/login/` and `/register/` have `public={true}` to skip it
- Incremental rebuild: `POST /api/activity/{id}` triggers `bincio render --handle {user}` - Incremental rebuild: `POST /api/activity/{id}` triggers `bincio render --handle {user}`
as a fire-and-forget subprocess (only if `--site-dir` was passed to `bincio serve`) as a fire-and-forget subprocess (only if `--site-dir` was passed to `bincio serve`)
### Password reset (no email — out-of-band code)
There is no email infrastructure. Password resets work via admin-generated one-time codes:
1. **Admin** opens `/admin/` → clicks **"Reset pwd"** next to the user → a code appears
inline (monospace, click to copy). Valid for **24 hours**, tied to that handle.
2. **Admin** sends the code out-of-band (Signal, Telegram, etc.).
3. **User** goes to `/reset-password/`, enters handle + code + new password → done.
API:
- `POST /api/admin/users/{handle}/reset-password-code` (admin) → `{code, expires_in_hours: 24}`
- `POST /api/auth/reset-password` (public) → body `{handle, code, password}`
DB: `reset_codes` table `(code, handle, created_by, created_at, expires_at, used_at)`.
Generating a new code invalidates any prior unused code for the same handle.
Used codes are kept for audit. `change_password()` in `db.py` updates the bcrypt hash.
- Write API in `bincio serve` delegates to `bincio.edit.server._apply_sidecar_edit`; the - Write API in `bincio serve` delegates to `bincio.edit.server._apply_sidecar_edit`; the
Strava sync delegates to `bincio.edit.server.strava_sync` with a temporary data_dir swap Strava sync delegates to `bincio.edit.server.strava_sync` with a temporary data_dir swap
+2 -1
View File
@@ -4,7 +4,8 @@ import Base from '../../layouts/Base.astro';
<Base title="Reset password — BincioActivity" public={true}> <Base title="Reset password — BincioActivity" public={true}>
<div class="max-w-sm mx-auto mt-16 px-4"> <div class="max-w-sm mx-auto mt-16 px-4">
<h1 class="text-2xl font-bold text-white mb-2 text-center">Reset password</h1> <h1 class="text-2xl font-bold text-white mb-2 text-center">Reset password</h1>
<p class="text-zinc-500 text-sm text-center mb-6">Enter the reset code you received from the admin.</p> <p class="text-zinc-500 text-sm text-center mb-2">Enter the reset code you received from the admin.</p>
<p class="text-zinc-600 text-xs text-center mb-6">Don't have a code? Contact the instance admin — they can generate one for you from the admin panel. Codes expire after 24 hours.</p>
<form id="reset-form" class="space-y-4"> <form id="reset-form" class="space-y-4">
<div> <div>