Files
Business-Management/backend/STATUS.md
T
curo1305 94901fc30f Redesign doc service UX for scale + add group-based document sharing
- Three-column layout: Sidebar + SourcePanel (views + searchable category tree) + main
- DocumentSlideOver (480px right panel): inline editing, type picker, AI suggestion confirm/reject,
  categories combobox, tags editor, sharing section, raw text, re-analyse/delete actions
- ManageCategoriesDialog: inline rename, delete with confirm, search filter
- DocumentsPage rewrite: filter chip system, multi-file upload queue, drag-and-drop overlay,
  bulk actions bar (share/delete), smart TanStack Query polling, URL-driven view state
- Sidebar simplified: per-category NavLinks removed; Documents = single NavLink under Apps
- Backend: document_shares table (migration 0004), share CRUD endpoints, shared-with-me view,
  N+1-safe share_count via GROUP BY, recipient download access, X-User-Groups header enforcement
- Gateway proxy: injects X-User-Groups header into all document + category proxy requests
- Backend users: GET /api/users/me/groups endpoint for share picker combobox
- CLAUDE.md, STATUS.md files, and changelog updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 12:46:43 +02:00

8.3 KiB

Backend — Status

What it is

Central FastAPI gateway. Handles authentication, user management, admin settings, and proxies feature-service traffic. It is the only container that has host-level port exposure (8000, internal) — all browser traffic arrives via the Vite/nginx frontend proxy.

Port: 8000 (on backend-net, no direct host binding in prod). Database: PostgreSQL 16 (postgres_data named volume).


Current functionality

Auth (/api/auth)

Method Path Description
POST /api/auth/register Create account; password policy enforced (uppercase, special char, no "test")
POST /api/auth/login OAuth2 password flow; returns RS256 JWT (8-hour expiry)

JWT signing uses a 4096-bit RSA key pair (RS256). Keys are generated by scripts/generate_jwt_keys.py and stored in backend/.env (gitignored). Token stored in localStorage on the client.

Users (/api/users)

Method Path Description
GET /api/users/me Current user info
GET /api/users/me/preferences User's dashboard preferences (app_ids list)
PATCH /api/users/me/preferences Update pinned app IDs (max 50; validated as safe slugs)
GET /api/users/me/groups List groups the current user belongs to (for share picker)

Profile (/api/profile)

Method Path Description
GET /api/profile Fetch profile (separate profiles table)
PUT /api/profile Update profile fields

Admin (/api/admin)

Method Path Description
GET /api/admin/users List all users (admin only)
PATCH /api/admin/users/{id} Update user (role, active flag)

Groups (/api/admin/groups)

Method Path Description
GET /api/admin/groups List all groups with member count
POST /api/admin/groups Create a new group
GET /api/admin/groups/{id} Get group detail with member list
PATCH /api/admin/groups/{id} Update group name / description
DELETE /api/admin/groups/{id} Delete group (cascades memberships)
POST /api/admin/groups/{id}/members/{user_id} Add user to group
DELETE /api/admin/groups/{id}/members/{user_id} Remove user from group

Services (/api/services)

Method Path Description
GET /api/services Returns health status of all registered feature services

A background task (service_health.py) polls each service's /health endpoint every 30 s and stores the result in memory. The first check runs immediately on startup. Any authenticated user may call GET /api/services; the frontend uses it to drive app card visibility.

Settings (/api/settings)

Method Path Description
GET /api/settings/ai AI service config (masked) — superuser OR ai-service-admin member
PATCH /api/settings/ai Update AI provider / credentials — same access
POST /api/settings/ai/test Test AI connection — same access
GET /api/settings/documents/limits Doc service upload limits — superuser OR doc-service-admin member
PATCH /api/settings/documents/limits Update max PDF size — same access
GET /api/settings/system-prompts All editable system prompts — superuser OR ai-service-admin member
PATCH /api/settings/system-prompts/{id} Update system prompt — same access

Settings are persisted to JSON files on the app_config Docker named volume and read by the respective feature services.

Access to service-specific settings endpoints is enforced by get_service_admin(service_id) in deps.py — grants access to superusers OR members of the {service_id}-admin group.

Feature proxies

All /api/documents/* and /api/documents/categories/* requests are transparently proxied to doc-service:8001 via httpx.AsyncClient. The proxy:

  • Validates the JWT (get_current_user)
  • Injects x-user-id header (UUID from users.id)
  • Strips hop-by-hop headers + content-length, accept-encoding, content-type
  • Returns Response (not StreamingResponse) to avoid content-length/chunked conflicts

Plugin system (/api/plugins)

Generic extension/plugin infrastructure — zero feature-specific code in backend. Feature containers self-describe via GET /plugin/manifest.

Method Path Auth Description
GET /api/plugins user List plugins accessible to current user
GET /api/plugins/{id}/manifest user Cached manifest for a plugin (404 if not accessible)
GET /api/plugins/{id}/settings user Proxy to feature GET /plugin/settings
PATCH /api/plugins/{id}/settings user Proxy to feature PATCH /plugin/settings

Access is controlled by the manifest: allow_superuser for admins; required_groups for group members. check_plugin_access(plugin_id, user, db) in deps.py enforces this.

During each health poll, service_health.py also fetches GET /plugin/manifest from healthy services and caches it. New feature containers that expose /plugin/manifest automatically appear in the plugin list — no backend code changes required.

Service admin group bootstrap: On every startup, group_bootstrap.py creates a {service-id}-admin group for every registered service (idempotent). Admins add users to these groups via the Admin → Groups UI to delegate service-level administration.

Database models

Model Table Notes
User users email, hashed_password, role (user|admin), is_active, dashboard_app_ids (JSON)
Profile profiles one-to-one with User; full_name, phone, etc.
Group groups name (unique), description, created_at
GroupMembership group_memberships group_id + user_id (unique pair); joined_at

Alembic migrations in backend/alembic/versions/ — version table: alembic_version.


Architecture

Browser (port 5173 dev / 80 prod)
    │
    └── Vite dev proxy / nginx
            │
            └── /api/*  →  backend:8000  (FastAPI)
                                │
                    ┌───────────┼────────────┬──────────────┐
                 /auth       /settings    /documents/*   /services
                 /users       (JSON        │              │
                 /admin        volume)     └── proxy →   health-check loop
                 /profile                  doc-service:8001  (30s poll)

Security notes

  • JWT stored in localStorage — XSS risk. Migration to httpOnly cookie planned.
  • No refresh token — after 8h the user must log in again.
  • Admin routes use get_current_admin dependency (checks role == "admin").
  • All backend routes require authentication except /api/auth/*.
  • backend-net is marked internal: true — containers on it cannot reach the internet directly.

Known limitations / not implemented

  • No refresh tokens — 8h hard expiry; adding refresh requires httpOnly cookie + rotation
  • No httpOnly cookie — JWT in localStorage is XSS-exposed
  • App permissions — no per-user, per-app access control. Currently all authenticated users can use all apps. Planned: user_app_permissions table, admin UI to grant/revoke
  • Groups / sharing — groups + memberships exist; app permission hooks not yet wired up
  • Email verification — accounts are active immediately after registration
  • Password reset — no flow implemented

Future work

  • Groups system: groups, group_memberships tables; admin CRUD; add/remove members
  • Generic plugin infrastructure: manifest contract, /api/plugins proxy router, check_plugin_access
  • App permissions registry: group_app_permissions table; AppsPage filtered by group grants
  • Doc sharing via group membership
  • App permissions registry: user_app_permissions (user_id, app_key); AppsPage filtered by grants
  • httpOnly cookie migration for JWT
  • Refresh token flow (paired with cookie migration)
  • Email verification on registration
  • Password reset flow
  • Rate limiting on auth endpoints