doc-service and ai-service no longer use local filesystem directories —
all file and config I/O goes through storage-service. Update README and
CLAUDE.md to reflect 6-service architecture, new volumes, and add
storage-service step to the "Adding a new resource" checklist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All feature containers now POST messages to ai-service (port 8010) instead
of calling AI providers directly. ai-service routes to LM Studio, Ollama,
or Anthropic based on /config/ai_service_config.json. doc-service AI
providers removed; replaced by httpx ai_client.py. Backend settings
restructured to /api/settings/ai. Frontend gets dedicated AIAdminSettingsPage
and AI Service card in AppsPage.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- backend/Dockerfile: run migrations via start.sh before uvicorn instead
of launching uvicorn directly (prod was skipping Alembic)
- backend/scripts/start.sh: alembic upgrade head + uvicorn exec
- documents_proxy.py: add explicit "" route so GET /api/documents (no
trailing slash) returns 200 instead of 307 redirect
- README.md: update Containers table, volumes section, and Current State
to reflect the new 4-container architecture with doc-service
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- backend-net (internal: true): db ↔ backend ↔ frontend reverse proxy
- frontend-net: frontend only; single host port binding (80 prod / 5173 dev)
- Remove ports: from db (5432) and backend (8000) — unreachable from host
- Security auditor: hard rule to never add host ports to db or backend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- schemas/user.py: is_admin (validation_alias=is_superuser) on UserOut and
UserAdminOut; UserAdminCreate extends UserCreate with is_admin flag
- deps.py: get_current_admin dependency — 403 for non-superusers
- routers/admin.py: GET/POST /api/admin/users, DELETE and PATCH /active per
user; self-delete and self-deactivate blocked
- main.py: register /api/admin router
- scripts/seed.py: seed test user with is_superuser=True; promotes existing
user if already created without the flag
Frontend:
- api/client.ts: UserData type with is_admin, admin API functions
- components/Nav.tsx: Admin link visible only when user.is_admin is true
- pages/AdminPage.tsx: user table with add-user form, delete, toggle active
- App.tsx: AdminRoute guard (403-redirects non-admins to /); /admin route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- frontend prod: USER root for adduser, then USER appuser (1001:1001); fixes
build failure caused by nginx-unprivileged already setting USER nginx
- docker-compose: frontend user updated to 1001:1001 (was 101:101)
- CLAUDE.md: add infrastructure change protocol (update README + test both
stacks after any Dockerfile/compose/nginx change); fix stale passlib ref
- README: container table shows nginx-unprivileged image, UID column, internal
port 8080 note; Current State notes all containers run as non-root
Both dev and prod stacks tested and verified (health, login, /users/me,
frontend serving, all containers confirmed non-root via docker inspect).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>