Adds an audit trail per board, visible from a new clock-icon button on the
toolbar. Useful for review-style work where someone wants to see who
contributed which references and when.
Logged events (high-signal only — canvas-edit noise intentionally skipped):
- image / video / pdf added (whether dropped, pasted, or pulled from a URL)
- board created / renamed / deleted
- thread started, resolved, reopened
- comment posted on a thread
Backend:
- new activity_logs table (id, board_id, user_id, denormalised actor name +
email, action, target_type/id/label, metadata JSON, created_at) with an
index on (board_id, created_at DESC).
- logActivity helper resolves the user once at log time and stores their
display name + email so entries survive deactivation/rename.
- recordActivity wraps logActivity + a Socket.IO emit to the board's room
so the panel updates live without polling.
- GET /api/boards/:id/activity?limit=&before= for pagination
(collection-membership gated, viewer+).
Frontend:
- ActivityPanel side-drawer: time-grouped feed (Today / Yesterday / older),
per-action icons + tone colours (add/remove/edit/comment), pagination
via "Load older", live append on Socket.IO 'activity:new'.
- Relative timestamps refresh every 30s.
- Wired into Editor + Toolbar.
README updated; roadmap entry checked off.
Self-registration is now controlled at runtime from the admin panel rather
than at build time via an env var. Default: off.
- New `settings` table (key/value/updated_at) plus getSetting/setSetting
helpers. Idempotent first-boot migration seeds allow_self_registration
from the ALLOW_SELF_REGISTRATION env var; after first boot the env var
is ignored and admins control the toggle from the UI.
- New public GET /api/auth/config (no auth) — returns
{ allowSelfRegistration, hasUsers }. The Login page polls this on mount
to decide whether to show a Register link, and to render
"Create the first admin account" mode when the install is empty.
- New admin GET /api/admin/settings + PUT /api/admin/settings/:key for
the dashboard. Constrained to a known-keys allowlist with type coercion
so unrecognized keys can't be stored.
- POST /api/auth/register now reads the toggle from the database instead
of process.env. The first user is still always allowed and is auto-
promoted to admin.
- Admin.tsx grows a "Settings" card with a labelled toggle switch and
toast feedback. The card sits above the user table.
- VITE_ALLOW_SELF_REGISTRATION dropped — runtime fetch replaces it.
Docs: README + .env.example clarify that ALLOW_SELF_REGISTRATION is now
an initial seed only, the going-public checklist points at the dashboard
toggle, and the features list calls out runtime control.
Adds an /admin route, visible only to users with role=admin, that lets an
operator manage the user base from the UI:
- list / search users (active + inactive)
- create new accounts (with role and optional display name)
- reset a user's password
- promote/demote between admin and member
- deactivate / reactivate (soft-delete via is_active flag)
Backend changes:
- New adminOrApiKeyMiddleware accepts EITHER a Bearer JWT belonging to a
role=admin user (UI path) OR the existing X-API-Key (bot/server-to-server).
- Existing /api/admin/* routes switched to the hybrid middleware, so the same
endpoints serve both the dashboard and any external scripts.
- Added PUT /api/admin/users/:id/role and PUT /api/admin/users/:id/reactivate.
- Self-deactivation and self-demotion are explicitly blocked so an admin can't
lock themselves out.
Frontend changes:
- New Admin.tsx page (table view, modals for create + reset, toast feedback).
- Admin button in CollectionList header, only rendered for admin role.
- Wired into App.tsx routing.
Also: friendly error when poppler-utils is missing on the host (PDF uploads
return 501 POPPLER_MISSING with a one-line install hint instead of crashing
the request); README clarifies poppler is required for the manual install.
Cover Cloudflare Tunnel (the path I run myself), Caddy + Let's Encrypt,
nginx with WebSocket headers, Tailscale for tailnet-private access, and
a 'going public' checklist (JWT_SECRET, CORS, registration, MinIO scope,
backups).
- Remove Mattermost integration (OAuth, channel bridge, file sync watcher,
frontend import modal). RefBoard now ships as a self-contained app.
- Replace SSO Login screen with email/password form (+ optional register link
gated by ALLOW_SELF_REGISTRATION).
- Add SEED_ADMIN_EMAIL / SEED_ADMIN_PASSWORD env-var bootstrap so a fresh
install ships with an admin account on first boot (idempotent).
- ALLOW_SELF_REGISTRATION flag (default false) gates POST /api/auth/register.
First user can always register (auto-promoted to admin).
- Drop mattermost_id and mm_file_id columns + board_channel_links table
from the schema; remove related db helpers and exports.
- Add MIT LICENSE, comprehensive README, .env.example, docker-compose.yml
(bundles MinIO so one command boots a working stack).
- Expand .gitignore for typical Node + Docker dev artefacts.