Commit Graph

66 Commits

Author SHA1 Message Date
Gitea Actions
a49e191999 Bump build to 0.9.0.9 [skip ci] 2026-04-15 08:31:16 +00:00
CTO
2594d78613 fix: cast AnalyseMode enum to string literal union for Drizzle pgEnum insert
All checks were successful
Deploy to VPS / deploy (push) Successful in 50s
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-15 08:31:11 +00:00
Gitea Actions
2feca358cc Bump build to 0.9.0.8 [skip ci] 2026-04-15 08:22:38 +00:00
CTO Agent
41fcc5be42 feat: extend skills with dynamic resolution and RBAC, add API docs
Some checks failed
Deploy to VPS / deploy (push) Failing after 49s
- Add resolveAnalysisMode() to modes/index.ts for dynamic skill lookup
- Extend structured-analysis.ts to use resolveAnalysisMode (supports custom skill prompts and skillId persistence)
- Update structured analyses route to use resolveAnalysisMode instead of hardcoded VALID_MODES set
- Add skills:read/create/edit/delete RBAC permissions to rbac.ts
- Add docs/API_GUIDE.md with full endpoint reference

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-15 08:22:33 +00:00
Gitea Actions
da2a81f081 Bump build to 0.9.0.7 [skip ci] 2026-04-13 21:58:18 +00:00
CTO
622d0bee34 fix: handle missing ENCRYPTION_KEY in API key save routes and fix openrouter provider type
All checks were successful
Deploy to VPS / deploy (push) Successful in 33s
The encrypt() call threw an unhandled error when ENCRYPTION_KEY env var was missing,
causing a 500 that the frontend displayed as "Netzwerkfehler beim Speichern des Schlüssels".
Now returns a clear error message. Also fixed provider type cast that excluded 'openrouter'.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 21:58:11 +00:00
Gitea Actions
f4ad3da3ec Bump build to 0.9.0.6 [skip ci] 2026-04-13 21:30:37 +00:00
CTO
2caf7d1229 fix: remove broken CROSS JOIN from migration 0005
All checks were successful
Deploy to VPS / deploy (push) Successful in 48s
The CROSS JOIN referenced s.system_prompt which didn't exist in the
VALUES alias, causing the entire migration transaction to fail.
This prevented the skills table from being created at all.

Seed is now handled entirely by migration 0006.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 21:30:33 +00:00
Gitea Actions
f73a97e696 Bump build to 0.9.0.5 [skip ci] 2026-04-13 21:15:34 +00:00
CTO
f0a7d6837b fix: use withTenantDb for skills API routes (RLS fix) and seed default skills
All checks were successful
Deploy to VPS / deploy (push) Successful in 40s
All skills API routes were using `db` directly instead of `withTenantDb`,
causing RLS to block all operations since `app.tenant_id` was never set.
This caused "Netzwerkfehler" when creating/reading skills.

Also fixes the broken seed migration (0005) which referenced a non-existent
column in the CROSS JOIN, preventing default system skills from being inserted.
New migration 0006 properly seeds the 4 default skills with full system prompts.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 21:15:24 +00:00
Gitea Actions
b665f530e0 Bump build to 0.9.0.4 [skip ci] 2026-04-13 20:44:23 +00:00
a5e58aa142 Merge pull request 'feat: Dynamic skill selection for analysis (AIIA-98)' (#4) from feat/aiia-98-dynamic-skill-selection into master
All checks were successful
Deploy to VPS / deploy (push) Successful in 46s
2026-04-13 20:44:20 +00:00
Gitea Actions
abc6a259f0 Bump build to 0.9.0.3 [skip ci] 2026-04-13 20:43:18 +00:00
445491654b Merge pull request 'feat: Skills management settings UI and API routes (AIIA-97)' (#3) from feat/aiia-97-skills-settings-ui into master
Some checks failed
Deploy to VPS / deploy (push) Failing after 35s
2026-04-13 20:43:16 +00:00
Frontend Engineer
aec4a39d10 feat: refactor analysis to use DB-driven skills (AIIA-96)
Replace hardcoded ANALYSIS_MODES lookups with database-driven skill loading:
- Add skills table to Drizzle schema with tenant-scoped, configurable skills
- Add analyses.skill_id FK and structured_result JSONB column
- Refactor runAnalysis()/runAnalysisSync() to resolve skills from DB
- Support skillId, skillSlug, or legacy mode enum (with fallback)
- Add structured data output via generateObject() + jsonSchema() for
  skills with output_type = structured_data
- Update /api/analyses POST to accept skillId/skillSlug alongside mode
- Migration 0005: creates skills table, seeds system skills, backfills

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 19:59:52 +00:00
Frontend Engineer
e521b8e338 feat: replace hardcoded Analysemodus with dynamic skill selection (AIIA-98)
- Add GET /api/skills read-only endpoint for fetching active tenant skills
- Update analyse-form.tsx to fetch skills dynamically, show description
  as helper text, and render structured data results as table
- Extract SkillCards client component for the skill info cards
- Send skillId alongside mode slug for forward compatibility

Depends on: AIIA-97 (skills schema/API) and backend analysis integration.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 19:52:43 +00:00
Frontend Engineer
d15476f5e9 feat: add Skills management settings UI and API routes (AIIA-97)
- Skill types (src/types/skill.ts) with form data, slugify helper
- Skills settings component with list view (drag-and-drop reorder),
  editor form (name, slug, prompt, output type, JSON schema, context
  requirements, active toggle), system skill protection
- API routes: GET/POST /api/settings/skills, GET/PATCH/DELETE
  /api/settings/skills/[id], PATCH /api/settings/skills/reorder
- Integrated into /einstellungen page (admin only)
- API routes depend on `skills` table from AIIA-94 schema migration

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 19:46:38 +00:00
Gitea Actions
817a0da714 Bump build to 0.9.0.2 [skip ci] 2026-04-12 20:54:11 +00:00
CTO (LegalAI)
86f4ef9012 feat: add auto-incrementing version number (0.9.0.X) in footer
All checks were successful
Deploy to VPS / deploy (push) Successful in 38s
- Added version.json to track base version and build number
- Updated Gitea Actions workflow to bump build number on each deploy
- Footer now shows version number alongside commit hash
- Version passed as build arg through Docker build pipeline

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-12 20:54:01 +00:00
CTO (LegalAI)
27132aa383 feat: add OpenRouter as an AI provider (AIIA-86)
All checks were successful
Deploy to VPS / deploy (push) Successful in 41s
Integrate OpenRouter via its OpenAI-compatible API so users can select
and use OpenRouter models alongside existing Anthropic/OpenAI/Ollama
providers. Adds provider to type system, DB enum, API validation,
buildModel switch, and settings UI.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-12 20:50:20 +00:00
CTO
e60b27cbd4 feat: persistent document viewing, archive page, and multi-format export (AIIA-83)
All checks were successful
Deploy to VPS / deploy (push) Successful in 1m7s
- Add document download, view, and text export endpoints via ?action= query param
- Add /dokumente archive page with category filtering, pagination, and text viewer modal
- Add /analyse/[id] detail page for viewing analysis results with text export
- Make analysis list items clickable (link to detail view)
- Add download/export buttons to existing document upload component
- Add Dokumente nav item to sidebar

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-12 19:57:17 +00:00
CTO
d10a2453d2 fix: persist uploads across container rebuilds with Docker volume (AIIA-74)
All checks were successful
Deploy to VPS / deploy (push) Successful in 52s
Uploaded documents were lost on every redeploy because /app/uploads
had no persistent volume. Add uploads_data volume to docker-compose.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:50:59 +00:00
CTO
8dc71448d7 fix: add DOMMatrix/Path2D/ImageData polyfills for pdfjs-dist in Node.js (AIIA-74)
All checks were successful
Deploy to VPS / deploy (push) Successful in 48s
pdfjs-dist v5 requires DOMMatrix even in legacy build. Add minimal
polyfills so PDF text extraction works in the Node.js Docker container
without @napi-rs/canvas.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:41:20 +00:00
CTO
af219c38d8 fix: register 0004_document_source_scope migration in drizzle journal
All checks were successful
Deploy to VPS / deploy (push) Successful in 31s
The migration file was added by feat/aiia-66-source-selection but was not
registered in _journal.json, so it never runs on deploy. This caused
'source_scope' column-missing errors on document insert.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:28:11 +00:00
CTO (Paperclip)
b4ad27ad02 Merge feat/aiia-70-document-delete into master
All checks were successful
Deploy to VPS / deploy (push) Successful in 32s
Resolves conflicts with feat/aiia-66-source-selection merge:
- route.ts: keep both GET and DELETE endpoints
- dokument-upload.tsx: keep IngestionProgress + delete button

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:22:50 +00:00
e5d9d3cef3 Merge pull request 'feat: implement AI source selection and toggle for document-based knowledge (AIIA-66)' (#2) from feat/aiia-66-source-selection into master
All checks were successful
Deploy to VPS / deploy (push) Successful in 32s
2026-04-10 21:21:37 +00:00
CTO
79191c3810 fix: replace pdf-parse with direct pdfjs-dist to fix DOMMatrix error in production
All checks were successful
Deploy to VPS / deploy (push) Successful in 1m10s
pdf-parse v2 depends on @napi-rs/canvas (native module) which fails in
Next.js standalone Docker builds — native binaries aren't traced/copied
to the standalone output, causing DOMMatrix is not defined at runtime.

Replaced pdf-parse entirely with pdfjs-dist legacy build which works
natively in Node.js without canvas or DOM API dependencies:

- New src/lib/pdf.ts: extractTextFromPdf() using pdfjs-dist/legacy/build
- Worker file explicitly imported so Next.js file tracer includes it
- Updated all call sites: documents, norms/parse, contracts
- Removed pdf-parse from dependencies, added pdfjs-dist directly
- Changed serverExternalPackages from pdf-parse to pdfjs-dist

Verified: build succeeds, both pdf.mjs and pdf.worker.mjs present in
.next/standalone, text extraction works in standalone context.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:19:20 +00:00
CTO (LegalAI)
17c1b6587a feat: add document deletion endpoint and UI button (AIIA-70)
All checks were successful
Deploy to VPS / deploy (push) Successful in 34s
Add DELETE /api/documents/:id endpoint that removes the DB record,
cleans up the stored file from disk, and logs an audit event. Add a
"Loeschen" button to the DokumentUpload component with confirmation
dialog.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:08:00 +00:00
CTO
4e74e4b5c9 fix: pass git commit hash as Docker build arg so footer shows correctly
All checks were successful
Deploy to VPS / deploy (push) Successful in 35s
git is not available inside the node:20-alpine Docker image, so
git rev-parse in next.config.ts falls back to 'dev'. Now the commit
hash is passed as a COMMIT_HASH build arg from the host where git
is available, ensuring the footer displays the real commit hash.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:06:04 +00:00
CTO
3e0efd10e9 feat: add visible build commit hash footer to dashboard layout
All checks were successful
Deploy to VPS / deploy (push) Successful in 35s
The build hash was only in the sidebar which could be hidden or cut off.
Added a proper footer to the main content area so the commit hash is
always visible at the bottom of every dashboard page.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 20:43:14 +00:00
CTO
1e431145dd fix: migrate pdf-parse from v1 to v2 API to resolve DOMMatrix error
All checks were successful
Deploy to VPS / deploy (push) Successful in 37s
The old v1 API (`pdfParse(buffer)`) triggered DOMMatrix dependency via
pdfjs-dist canvas rendering path. The v2 API (`new PDFParse({ data })` +
`getText()`) uses a text-only code path that works in Node.js without
DOM/canvas polyfills.

Updated all three call sites:
- src/lib/documents/index.ts (generic document extraction)
- src/app/api/norms/parse/route.ts (norm PDF parsing)
- src/lib/contracts/index.ts (contract text extraction)
- src/types/pdf-parse.d.ts (updated type declarations for v2)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 20:39:27 +00:00
CTO (LegalAI)
5ff2347aac feat: add document deletion endpoint and UI button (AIIA-70)
Add DELETE /api/documents/:id endpoint that removes the DB record,
cleans up the stored file from disk, and logs an audit event. Add a
"Loeschen" button to the DokumentUpload component with confirmation
dialog.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 20:28:18 +00:00
a89bf8380d ci: simplify deploy workflow to run directly on VPS host runner
All checks were successful
Deploy to VPS / deploy (push) Successful in 56s
2026-04-10 20:27:02 +00:00
CTO
94b89cb1e2 fix: improve document ingestion robustness and add progress/debug UI
Some checks failed
Deploy to VPS / deploy (push) Failing after 2s
- Fix PDF extraction: detect scanned documents (no text layer), encrypted PDFs,
  empty files, and missing files with clear German error messages
- Add error logging to extraction pipeline (was silently swallowed)
- Return errorMessage in document list API so UI can display failure reasons
- Add GET /api/documents/[id] endpoint for status polling
- Rewrite DokumentUpload component with:
  - Auto-polling every 2s while documents are processing
  - Visual step-by-step progress indicator (Hochgeladen → Extrahiere Text → Fertig)
  - Error message display when extraction fails
  - Debug toggle showing document ID, MIME type, size, timestamps

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 19:56:12 +00:00
CTO (LegalAI)
d7bdeb7da2 feat: implement AI source selection and toggle for document-based knowledge (AIIA-66)
Add source scope (case/global) to documents, enabling users to select
which uploaded documents the AI considers during analysis. Includes
schema migration, API support, reusable source selection UI component,
and integration into the analyse form.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 19:54:23 +00:00
CTO (LegalAI)
fe838d5916 fix: rewrite migrate.mjs to bypass missing drizzle-orm migrator module
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
drizzle-orm v0.45.2 declares a migrator export but does not ship the
actual .js file, causing all migrations to silently fail on every deploy.
This was the root cause of the missing "documents" table (AIIA-62).

The new script reads the drizzle journal and executes SQL files directly
via pg, with its own tracking table for idempotent re-runs.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 10:12:08 +00:00
CTO
8172872329 fix: coerce empty FormData strings to null for UUID columns (AIIA-59)
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
Document upload failed with "invalid input syntax for type uuid" when
decision_id or norm_instrument_id were sent as empty strings from
FormData. The ?? operator only catches null/undefined, not "".

Added emptyToUndefined() to sanitize all optional UUID fields at the
API boundary before they reach the DB insert.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 07:43:43 +00:00
CTO (LegalAI)
23a66f92fc fix: resolve upload EACCES and analysis start failure
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
- Dockerfile: create /app/uploads with correct ownership before switching
  to the non-root nextjs user, fixing EACCES: permission denied on mkdir
- analyse-form.tsx: send 'title' and 'query' fields (not 'question') to
  match the /api/analyses endpoint contract, fixing 400 rejection that
  showed "Analyse konnte nicht gestartet werden"

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 22:01:45 +00:00
CTO (LegalAI)
d7ab827b74 fix: rename middleware.ts to proxy.ts for Next.js 16 compatibility
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
Next.js 16 deprecated the "middleware" file convention in favor of "proxy".
This fixes the build warning reported during manual deploy.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 21:03:19 +00:00
CTO (LegalAI)
6f80cadbd4 feat: add build hash to sidebar footer and Gitea CI/CD deploy workflow
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
- Inject git commit short hash at build time via NEXT_PUBLIC_BUILD_HASH
- Display build hash in sidebar footer for version tracking
- Add Gitea Actions workflow to auto-deploy on push to master (SSH → pull → rebuild)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 20:58:50 +00:00
CTO (LegalAI)
2509b907ae fix: chunk large law texts to prevent truncated AI JSON output
Texts >10k chars are now split at § boundaries and parsed in separate
AI calls, then merged.  This prevents maxOutputTokens truncation that
caused "AI returned invalid JSON" on large imports (~50k+ chars).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 16:20:35 +00:00
CTO (LegalAI)
1493b84787 fix: extract tenantId from session auth instead of request body/headers
AI routes now use requirePermission() + ctx.tenantId to get the tenant,
ensuring getModelForTenant() is always called with the correct tenant ID
so that stored API keys are used. Fixes norms/parse (was falling back to
getModel()) and analyses/structured (was trusting x-tenant-id header).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:55:20 +00:00
CTO (LegalAI)
73cd71b1f6 fix: make entrypoint migration non-fatal so app starts even if migrate.mjs fails
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:48:50 +00:00
CTO (LegalAI)
09b0022b02 fix: include drizzle-orm and pg in serverExternalPackages for standalone migration
The entrypoint.sh migration script (migrate.mjs) imports
drizzle-orm/node-postgres/migrator which is never imported by app code.
Next.js standalone trace therefore omits it from node_modules, causing
the container to crash on startup before server.js runs.

Adding drizzle-orm and pg to serverExternalPackages ensures the full
packages are copied into the standalone output, fixing the migration
crash.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:41:18 +00:00
CTO (LegalAI)
b22bdd8425 fix: API key save network error — add ENCRYPTION_KEY env and auto-migrate
The "Netzwerkfehler beim Speichern des Schlüssels" was caused by two issues:
1. ENCRYPTION_KEY env var was not passed to the Docker container, so
   AES-256-GCM encrypt() threw at runtime on every POST/PATCH.
2. The 0003_tenant_api_keys migration was not in the drizzle journal
   and no migration runner existed in the Docker image.

Changes:
- docker-compose.yml: pass ENCRYPTION_KEY to app container
- .env.example: document ENCRYPTION_KEY with generation command
- .gitignore: allow .env.example to be tracked
- Dockerfile: include drizzle/ migrations and entrypoint script
- entrypoint.sh: run migrations before starting the app
- migrate.mjs: runtime migration script using drizzle-orm migrator
- drizzle journal: register 0003_tenant_api_keys migration

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:28:19 +00:00
CTO (LegalAI)
2a7db07d46 fix: add API key input field to AI provider settings form
When selecting Anthropic or OpenAI as provider, the form now shows
an inline API key input field that creates or replaces the key via
the existing CRUD API. Includes key hint display and status indicator.

Resolves AIIA-49

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 13:42:57 +00:00
CTO (LegalAI)
4473e32f9c fix: API-Key Status-Anzeige fuer Anthropic/OpenAI im AI-Provider Bereich
Zeigt im AI-Provider Formular einen Status-Indikator an, ob ein API-Schluessel
fuer den gewaehlten Provider (Anthropic/OpenAI) hinterlegt ist. Entfernt Ollama
aus dem API-Key Dropdown, da Ollama keine API-Keys benoetigt.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 13:18:38 +00:00
CTO (LegalAI)
362627981d feat: implement per-tenant API key management with AES-256-GCM encryption
Add encrypted API key storage for AI providers (Anthropic, OpenAI, Ollama)
with admin-only CRUD endpoints, tenant isolation, and audit logging.

- DB migration: tenant_api_keys table with RLS policy
- AES-256-GCM encryption utility (ENCRYPTION_KEY env var)
- CRUD API: GET/POST /api/settings/api-keys, PATCH/DELETE /api/settings/api-keys/[id]
- Provider integration: getModelForTenant() checks tenant keys before env fallback
- Frontend: API key management section in Einstellungen page
- Audit logging on all key CRUD operations (DSGVO)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 12:08:40 +00:00
CTO (LegalAI)
34047739cf feat: add PDF upload support to Fliesstext-Import
The import page now accepts PDF files in addition to TXT.
Backend uses pdf-parse to extract text from uploaded PDFs
before sending to AI for paragraph parsing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 11:52:58 +00:00
CTO (LegalAI)
c86ff8d151 feat: Fliesstext-Import fuer Gesetze mit KI-Parsing
Neuer /normen/import Bildschirm: Gesetzestext als Fliesstext einfuegen
oder TXT-Datei hochladen, KI zerlegt automatisch in Paragraphen,
Vorschau mit Bearbeitungsmoeglichkeit, dann Import ins Regelwerk.

- POST /api/norms/parse: AI-gestuetztes Parsing von Gesetzestexten
- /normen/import: Mehrstufiges Frontend (Eingabe -> Vorschau -> Import)
- Link zum Fliesstext-Import auf der Normen-Uebersichtsseite

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 11:46:44 +00:00