Commit Graph

16 Commits

Author SHA1 Message Date
curo1305 3248607790 Add service health checks and dynamic Apps page
Backend polls each registered service's /health endpoint every 30 s via a
background asyncio task. GET /api/services exposes the live status snapshot.
The Apps page now renders from this endpoint — showing "Unavailable" (dimmed,
non-clickable) when a service is registered but its container is unreachable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 17:31:36 +02:00
curo1305 bc7a74062d Add reset-to-default button and how-to docs to system prompt editor
Each service prompt card now shows:
- A collapsible how-to panel with placeholder docs, required JSON
  response keys, and usage notes
- A "Reset to Default" button (with confirmation step) that restores
  the built-in prompt without saving, letting the admin review first
- A "Using the built-in default prompt" indicator when unchanged

Backend includes default_system / default_user_template in the
system-prompts API response so the frontend never duplicates defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 15:17:55 +02:00
curo1305 1d01cc3b0e Add per-service system prompts with AI Settings tab view
Each feature service owns its system prompt in its config JSON on the
shared volume. The AI Settings page now has General and System Prompts
tabs — admins can view and edit any service's prompts at runtime with
changes taking effect within 30 s (config cache TTL).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 15:11:40 +02:00
curo1305 0b92db87d1 Fix proxy response causing false upload failures
StreamingResponse + forwarded content-length header was causing a
content-length mismatch (chunked vs explicit length), which made axios
reject the response even though doc-service had already saved the file.
Switch to Response, strip content-length/content-type from forwarded
response headers (FastAPI recalculates them correctly), and strip
accept-encoding from forwarded requests to prevent decompression
mismatches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:20:31 +02:00
curo1305 88c1ea297e Add shared ai-service container as AI provider intermediary
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>
2026-04-14 12:30:45 +02:00
curo1305 1cdc532fff Add doc-service tests, AI category suggestions, LM Studio default
- pytest suite for doc-service: 20+ tests covering category CRUD,
  document upload/get/delete/patch, ownership isolation, category
  assignment, AI processing (mock), and live PDF tests (auto-skipped
  when tests/pdfs/ is empty)
- Minimal in-memory PDF builder in conftest so tests run without any
  fixture files; real PDFs can be dropped into tests/pdfs/ to activate
  live extraction tests
- AI prompt updated to return suggested_categories (2–5 short names)
- Frontend: SuggestionChip component in DocumentRow shows AI-suggested
  categories after processing; "Assign" links to an existing category,
  "Create & Assign" creates it first, ✕ dismisses locally
- Default AI provider changed to LM Studio at
  http://host.docker.internal:1234/v1 (host.docker.internal resolves
  to the macOS host from inside Docker Desktop)
- tests/pdfs/ directory tracked via .gitkeep; *.pdf excluded by .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:27:57 +02:00
curo1305 b8238e03ea Fix prod startup: add start.sh for backend, fix documents proxy base route
- 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>
2026-04-14 05:32:43 +02:00
curo1305 0d34867a69 Add PDF document service with AI extraction and per-app settings
- New `features/doc-service` FastAPI microservice: PDF upload, async
  text extraction (pdfplumber), AI classification via Anthropic/Ollama/
  LM Studio, per-user categories, file download
- Alembic migration isolated with `alembic_version_doc_service` table
- Main backend: httpx proxy routers for /api/documents/* and
  /api/documents/categories/*, admin settings API at /api/settings/*
- Runtime config in /config/doc_service_config.json (shared Docker
  volume); api_key masking on reads; atomic write with os.replace()
- Frontend: DocumentsPage, DocumentAdminSettingsPage, updated AppsPage
  launcher hub, simplified Nav (removed Settings link), new routes
- docker-compose: doc-service service, doc_data + app_config volumes,
  removed internal:true from backend-net for outbound AI API calls
- Fix pre-commit hook: probe Docker socket path so git subprocess picks
  up Docker Desktop on macOS
- Fix security_check.py: use sys.executable for bandit so venv python
  is used instead of system python

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 05:28:11 +02:00
curo1305 e2c55556ac Switch JWT signing from HS256 to RS256 (4096-bit RSA)
- Replace symmetric SECRET_KEY with JWT_PRIVATE_KEY / JWT_PUBLIC_KEY (PEM)
- Add iat claim to every token
- Add expand_newlines validator in config for single-line .env PEM values
- Add scripts/generate_jwt_keys.py key-generation helper
- Update security-auditor agent JWT checklist with RS256 enforcement rules
- Mark RS256 as done in TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 23:00:35 +02:00
curo1305 0af5e8cc24 Harden JWT: 8-hour expiry, add JWT vulnerability checks
- Reduce ACCESS_TOKEN_EXPIRE_MINUTES from 24h to 8h (no permanent sessions)
- Add JWT_PATTERNS to security_check.py: algorithm=none, verify_exp=False,
  multi-day timedelta, oversized EXPIRE_MINUTES, hardcoded secret
- Add JWT security checklist to security-auditor agent
- Document auth/session security items in TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 22:54:53 +02:00
curo1305 87c7cc193a Harden admin route visibility: 404 not 403, redirect to /login
- deps.py: get_current_admin returns 404 Not Found for non-superusers instead
  of 403 Forbidden — hides endpoint existence from unauthorised callers
- App.tsx: AdminRoute redirects non-admins to /login instead of /, making
  the route indistinguishable from a non-existent page

Layer 3 (network-level IP restriction via Traefik) tracked in TODO.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 18:46:33 +02:00
curo1305 456681fdfa Add admin user management with role-gated access
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>
2026-04-13 18:40:05 +02:00
curo1305 343f12259c Add profile feature, input sanitization, and stronger security checks
Backend:
- app/core/sanitize.py: shared sanitize_str, normalize_email, validate_phone,
  validate_date_of_birth — applied to every user-supplied DB-bound input
- app/schemas/user.py: sanitize full_name, normalize email on UserCreate
- app/models/profile.py: profiles table (position, phone, dob, address, updated_at)
- app/models/user.py: Profile back-ref, is_superuser admin-role comment
- app/schemas/profile.py: ProfileRead/ProfileUpdate with full sanitization
- app/routers/profile.py: GET+PUT /api/profile/me (lazy profile creation)
- app/main.py: register /api/profile router
- alembic migration 676084df61d1: create profiles table

Frontend:
- components/Nav.tsx: shared nav (Dashboard | Profile | Logout)
- pages/ProfilePage.tsx: profile view + inline edit form with error handling
- pages/DashboardPage.tsx: use Nav component
- api/client.ts: ProfileData type, getProfile, updateProfile
- App.tsx: /profile private route

Security:
- scripts/security_check.py: tighter SQL injection patterns (f-string/format/%
  in execute/query/text()), new SANIT category for raw request→DB patterns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 18:15:47 +02:00
curo1305 e6d7888513 Fix dev stack startup: seed path, missing migration, passlib/bcrypt incompatibility
- python -m scripts.seed (module mode) fixes ModuleNotFoundError
- Add scripts/__init__.py to make scripts/ a proper package
- Generate initial Alembic migration for users table
- Replace passlib with direct bcrypt>=4.0 (passlib unmaintained, broken with bcrypt 4.x)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 16:03:03 +02:00
curo1305 61cef2eacd Add test user seed, password validation, and pre-commit security hook
- backend/scripts/seed.py: creates test@example.com on dev startup
- backend/scripts/start_dev.sh: runs migrations + seed + uvicorn --reload
- backend/app/schemas/user.py: password validator (length, case, digit, special char, forbidden words)
- scripts/security_check.py: Docker-based scanner for secrets, dangerous patterns, weak crypto, bandit
- .githooks/pre-commit: runs security_check.py in python:3.12-slim on every commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 15:54:23 +02:00
curo1305 606b7bd6b3 Initial project scaffold: FastAPI + React/Vite + PostgreSQL SaaS starter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 15:00:44 +02:00