Commit Graph

3 Commits

Author SHA1 Message Date
a073ee7fb9 perf+style: grid subscription hygiene, a11y, shadcn-style consistency
Perf / a11y (high-impact review items)
- Timeline arrow-key handler binds once per (viewMode, currentSection)
  and reads fresh state via navStateRef instead of an 8-element dep
  array of new-each-render values.
- usePhotosQuery collapses 14 individual Zustand selectors into one
  useShallow selector returning the params object.
- PhotoThumbnail no longer subscribes to the search query directly;
  Timeline subscribes once and passes it down as a prop.
- PhotoThumbnail gains role="button", tabIndex, aria-label, aria-pressed,
  Enter/Space key handlers and a focus-visible ring. Timeline marked
  role="grid"; RightSidebar marked role="region".

Style consistency
- Swap clsx for cn (tailwind-merge aware) across 17 files so
  conflicting utility classes collapse correctly.
- New Badge primitive (ui/badge.tsx) with default/neutral/overlay/
  outline variants; adopted in ColorsView, RatedView, TagsView for
  the repeated count overlay pill.
- Fix palette drift: text-amber-400 -> text-star, text-green-*
  -> text-pick, text-red-* -> text-reject (5 files).
- Button gains an xs size (h-6 px-1.5 text-[11px]) for the repeated
  compact-button pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:30:16 +02:00
7efac4354e ui: migrate to shadcn/ui primitives across dialogs, filters, and forms
Adopts shadcn/ui components (Dialog, Button, Input, Select, Popover,
Command, Checkbox, Switch, Toggle, Calendar, etc.) across the app,
replacing hand-rolled modals, dropdowns, and form controls. Adds a
reusable cmdk-backed MultiSelect for the Type, Tags, and Flag filters
so all multi-value filter popovers share one component and layout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:07:20 +02:00
348e9c3585 feat: multi-user auth with per-user media isolation
Introduce username/password authentication with admin and user roles.
Each user gets their own media directory under /photos/{username}/ with
isolated photos, folders, heaps, and tags. Admins manage users and
observe the full library from a dedicated Settings page.

Backend:
- User model with bcrypt passwords and JWT access/refresh tokens
- Auth router (login, refresh, setup, change-password, status)
- Admin router (user CRUD with last-admin protection)
- user_id FK added to photos, folders, source_roots, heaps, tags
- All data routers scoped by authenticated user
- Scanner inherits user_id from source root owner
- Thumbnails stored under user-prefixed paths for isolation
- Library endpoints accept ?scope=global for admin cross-user view
- Alembic migration 0009 with data migration for existing installs
- Defensive bootstrap.py handles fresh vs existing DB startup

Frontend:
- AuthContext with token lifecycle, auto-refresh, login/logout
- Login page, first-run setup page, auth gate in App.tsx
- Bearer token interceptor on all API requests
- User identity + logout in left sidebar
- Admin-only Settings page with Library Management and Users tabs
- UserManagement panel (add, edit role, reset password, deactivate)
- Settings shows global stats across all users for admin
- Filter bar, right sidebar, keyboard hints hidden on settings page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:47:43 +02:00