Add paginated users/roles, user status, frontend permissions, profile pictures, identifier file storage

- Users page: paginated, searchable, sortable with inline roles (no N+1)
- Roles page: paginated, searchable, sortable + /roles/all for dropdowns
- User is_active field with migration, PATCH toggle, auth check (disabled=401)
- Frontend permission checks: auth store loads permissions, sidebar/buttons conditional
- Profile pictures via file storage for users and members, avatar component
- Identifier images use file storage API instead of base64
- Fix TypeScript errors across admin UI
- 64 API tests passing (10 new)
This commit is contained in:
Ryan Moon
2026-03-29 08:16:34 -05:00
parent 92371ff228
commit b9f78639e2
48 changed files with 1689 additions and 643 deletions

View File

@@ -40,7 +40,7 @@
- `bun run format` — format all files with Prettier
## API Conventions
- All list endpoints support server-side pagination, search, and sorting via query params:
- **Every endpoint that returns a list must support pagination, search, and sorting** — no exceptions unless the endpoint is explicitly a lightweight lookup (see below)
- `?page=1&limit=25` — pagination (default: page 1, 25 per page, max 100)
- `?q=search+term` — full-text search across relevant columns
- `?sort=name&order=asc` — sorting by field name, asc or desc
@@ -48,6 +48,15 @@
- Search and filtering is ALWAYS server-side, never client-side
- Use `PaginationSchema` from `@forte/shared/schemas` to parse query params
- Use pagination helpers from `packages/backend/src/utils/pagination.ts`
- **Lookup endpoints** (e.g., `/roles/all`, `/statuses/all`) are the exception — these return a flat unpaginated list for populating dropdowns/selects. Use a `/all` suffix to distinguish from the paginated list endpoint for the same resource.
## Frontend Table Conventions
- **Every table that displays data must use the shared `DataTable` component** (`components/shared/data-table.tsx`)
- All tables must support: **search** (via `?q=`), **sortable columns**, and **server-side pagination**
- Use the `usePagination()` hook (`hooks/use-pagination.ts`) — it manages page, search, and sort state via URL params
- All data columns that make sense to sort by should be sortable (e.g., name, email, date, status) — don't limit to just 1-2 columns
- Sub-resource tables (e.g., members within an account, payment methods) follow the same rules — use `DataTable` with pagination, not raw `<Table>` with unbounded queries
- Loading states should use skeleton loading (built into `DataTable`), not plain "Loading..." text
## Conventions
- Shared Zod schemas are the single source of truth for validation (used on both frontend and backend)