# KanzlAI-mGMT: Full System Roadmap **Author:** cronus (inventor) **Date:** 2026-03-28 **Status:** Design proposal — awaiting review --- ## Vision KanzlAI-mGMT becomes the **first Kanzleimanagement system built for UPC patent litigation** — with full general-purpose law firm management that rivals RA-MICRO and Kleos, plus a UPC-specific intelligence layer that no competitor can match. The competitive moat: m's existing infrastructure (youpcms scraper, 1,600+ structured UPC cases, legal knowledge graph, mLex research tools) feeds directly into KanzlAI, making it the only software that **understands** UPC proceedings — not just manages them. --- ## What Exists (MVP — Shipped) | Area | Status | |------|--------| | Multi-tenant auth (Supabase Auth + RLS) | Done | | Case management (CRUD, parties, timeline) | Done | | Deadline management (CRUD, UPC+ZPO rules, calculator, holiday adjustment) | Done | | Appointments (CRUD, list + calendar view) | Done | | AI extraction (Claude API — PDF/text to deadlines) | Done | | Dashboard (traffic lights, timeline, AI summary, quick actions) | Done | | CalDAV bidirectional sync (deadlines as VTODO, appointments as VEVENT) | Done | | Document upload (Supabase Storage, 50MB max) | Done | | Notes system (polymorphic, attached to cases/deadlines/appointments/events) | Done | | Detail pages with breadcrumbs and URL-based navigation | Done | | Team management (invite by email, owner/admin/member roles) | Done | | Settings page (CalDAV config, tenant info) | Done | --- ## Priority Tiers - **P0 (Must-Have)** — Without these, it's not a real Kanzleimanagement. Required for any law firm to consider adopting. - **P1 (Should-Have)** — Makes KanzlAI competitive with established players. Required to win against RA-MICRO/Advoware. - **P2 (Differentiator)** — UPC-specific intelligence and advanced AI. What makes a patent lawyer say "I need THIS, not RA-MICRO." - **P3 (Nice-to-Have)** — Polish, integrations, and extended capabilities. --- ## P0: Must-Have Features ### 1. Audit Trail (Revisionsprotokoll) **Why:** Legal requirement. § 50 BRAO mandates orderly file-keeping. DSGVO Art. 5(2) requires demonstrable compliance. Professional liability insurance (Berufshaftpflicht) expects change traceability. Without this, no serious firm will adopt the software. **Design:** The existing `case_events` table handles case-level events but is not a proper audit log. We need a dedicated, **append-only** audit log that captures every mutation across the system. **New table: `kanzlai.audit_log`** ```sql CREATE TABLE kanzlai.audit_log ( id BIGSERIAL PRIMARY KEY, tenant_id UUID NOT NULL REFERENCES kanzlai.tenants(id), user_id UUID, -- auth.users, NULL for system actions action TEXT NOT NULL, -- 'create', 'update', 'delete', 'view', 'export' entity_type TEXT NOT NULL, -- 'case', 'deadline', 'appointment', 'document', ... entity_id UUID, -- ID of affected entity old_values JSONB, -- Previous state (for updates/deletes) new_values JSONB, -- New state (for creates/updates) ip_address INET, -- Client IP user_agent TEXT, -- Browser/client info created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Append-only: NO UPDATE or DELETE policies -- Partitioned by month for performance at scale -- Index on (tenant_id, entity_type, entity_id) for entity history -- Index on (tenant_id, user_id, created_at) for user activity -- Index on (tenant_id, created_at) for chronological browsing ``` **What to log:** | Event | entity_type | Details | |-------|-------------|---------| | Case create/update/archive | `case` | Full old/new state diff | | Deadline create/update/complete/delete | `deadline` | Including calculated vs manual source | | Appointment CRUD | `appointment` | Time changes especially | | Document upload/download/delete | `document` | File name, size, who accessed | | Party add/remove/update | `party` | Name changes, role changes | | Note create/update/delete | `note` | Content diff | | Conflict check performed | `conflict_check` | Query, results, clearance decision | | beA message sent/received | `bea_message` | Sender, recipient, subject | | Invoice generated/sent | `invoice` | Amount, recipient | | User login/logout | `auth` | IP, success/failure | | Data export (DATEV etc.) | `export` | What was exported | | Settings change | `settings` | CalDAV config, tenant settings | | Team member invite/remove | `membership` | Who, role | **Backend implementation:** - Middleware-based: wrap all handlers with an audit logger that captures before/after state - `AuditService.Log(ctx, action, entityType, entityID, oldValues, newValues)` — used by all services - `GET /api/audit-log?entity_type=X&entity_id=Y&from=DATE&to=DATE` — paginated query - `GET /api/audit-log/entity/{type}/{id}` — full history of one entity **Frontend:** - "Verlauf" (History) tab on every detail page showing change log - Global audit log page at `/protokoll` for admins/owners - Each entry shows: timestamp, user, action, human-readable diff **Retention:** 6 years per § 50 BRAO, with automated cleanup jobs for expired data. --- ### 2. Conflict of Interest Checks (Interessenkollisionsprüfung) **Why:** Statutory obligation under § 43a Abs. 4 BRAO. Failure to check = professional misconduct. Every competitor has this. A law firm cannot ethically operate without it. **Design:** **Trigger points:** 1. New case creation — check all party names against the database 2. New party added to existing case — re-run check 3. Manual check from a search interface **New table: `kanzlai.conflict_checks`** ```sql CREATE TABLE kanzlai.conflict_checks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES kanzlai.tenants(id), case_id UUID REFERENCES kanzlai.cases(id), -- which case triggered the check query_names TEXT[] NOT NULL, -- names that were checked results JSONB NOT NULL, -- matched parties with scores status TEXT NOT NULL DEFAULT 'pending', -- 'pending', 'cleared', 'conflict_found' cleared_by UUID, -- user who approved cleared_at TIMESTAMPTZ, notes TEXT, -- explanation for clearance created_by UUID NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **Search algorithm (phased):** | Phase | Method | Coverage | |-------|--------|----------| | 1 | Exact name match (case-insensitive) | Direct hits | | 2 | Trigram similarity (`pg_trgm` extension, threshold 0.3) | Typos, variations | | 3 | Cologne phonetic algorithm | Sound-alike German names | | 4 | Corporate relationship graph | Subsidiaries, affiliated entities | PostgreSQL `pg_trgm` is already available in Supabase. Cologne phonetic can be implemented as a PL/pgSQL function or in Go. **API:** - `POST /api/conflict-check` — run check against names, return matches with confidence scores - `POST /api/conflict-check/{id}/clear` — mark as cleared (partner/admin only) - `GET /api/conflict-checks?case_id=X` — list checks for a case **Frontend:** - Automatic check on case creation: after saving, show results in a modal before the case can be worked on - Manual check page at `/kollision` with a multi-name search form - Results display: matched party name, matched case (case number + title), role on that case, match confidence, match method (exact/fuzzy/phonetic) - "Freigeben" (clear) button for authorized users with mandatory notes field **Corporate relationships (Phase 4 — later):** New table for tracking corporate structures: ```sql CREATE TABLE kanzlai.party_relationships ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, party_id UUID NOT NULL REFERENCES kanzlai.parties(id), related_party_id UUID NOT NULL REFERENCES kanzlai.parties(id), relationship TEXT NOT NULL, -- 'subsidiary', 'parent', 'affiliate', 'successor' created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` --- ### 3. Role-Based Permissions (Rollenverwaltung) **Why:** Law firms have strict hierarchies. A Sekretärin should not modify fee agreements. A Referendar should not clear conflict checks. The current system has owner/admin/member, but no **functional** role differentiation. **Design:** Extend the existing `user_tenants.role` from simple owner/admin/member to a proper permission system: **Roles:** | Role | German | Permissions | |------|--------|-------------| | `partner` | Partner/Sozius | Full access, clear conflicts, approve invoices, manage team, view audit log | | `associate` | Anwalt/Anwältin | Case work, create/edit cases/deadlines/documents, time tracking, view own cases | | `paralegal` | Rechtsanwaltsfachangestellte/r | Create/edit cases, manage deadlines, upload documents, no billing access | | `secretary` | Sekretär/in | Manage appointments, deadlines, upload documents, no case creation | | `trainee` | Referendar/in | View access, add notes, limited editing (supervised) | | `extern` | Externer Zugang | Read-only view of assigned cases (for client portal) | **New table: `kanzlai.permissions`** ```sql CREATE TABLE kanzlai.permissions ( role TEXT NOT NULL, resource TEXT NOT NULL, -- 'cases', 'deadlines', 'billing', 'audit', 'team', 'conflicts' action TEXT NOT NULL, -- 'view', 'create', 'edit', 'delete', 'approve' allowed BOOLEAN NOT NULL DEFAULT false, PRIMARY KEY (role, resource, action) ); ``` Seed with a sensible default permission matrix. Tenants can override per-role if needed (stored in `tenants.settings.permissions` JSONB). **Backend changes:** - Authorization middleware checks `(role, resource, action)` before handler execution - Replace simple `role == "owner" || role == "admin"` checks with permission lookups - `GET /api/permissions` — list permissions for current user - `PUT /api/permissions` — update role permissions (owner only) **Frontend changes:** - Settings page gets a "Rollen & Berechtigungen" section - UI elements hidden/disabled based on user permissions - Permission-aware API client that prevents unauthorized requests --- ### 4. Email Notifications & Reminders (Benachrichtigungen) **Why:** A deadline management system without reminders is a liability. If a Frist is missed because nobody was notified, the software is actively harmful. This is the most dangerous gap in the current MVP. **Design:** **Notification types:** | Trigger | Recipients | Channel | Timing | |---------|------------|---------|--------| | Deadline warning date reached | Case assigned users | Email + in-app | Morning of warning_date | | Deadline due tomorrow | Case assigned users | Email + in-app | Morning before due_date | | Deadline overdue | Case assigned users + partners | Email + in-app | Morning after due_date | | Appointment in 1 hour | Appointment attendees | In-app push | 1 hour before | | New case event | Case assigned users | In-app | Immediate | | Conflict check needed | Partners | Email + in-app | On case creation | | beA message received | Assigned lawyer | Email + in-app | Immediate | | Team member invited | Invitee | Email | Immediate | **New tables:** ```sql -- Notification preferences per user CREATE TABLE kanzlai.notification_preferences ( user_id UUID NOT NULL, tenant_id UUID NOT NULL, channel TEXT NOT NULL, -- 'email', 'in_app', 'push' event_type TEXT NOT NULL, -- 'deadline_warning', 'deadline_due', 'deadline_overdue', ... enabled BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (user_id, tenant_id, channel, event_type) ); -- In-app notification inbox CREATE TABLE kanzlai.notifications ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, user_id UUID NOT NULL, -- recipient title TEXT NOT NULL, body TEXT, link TEXT, -- deep link to relevant page event_type TEXT NOT NULL, entity_type TEXT, entity_id UUID, read_at TIMESTAMPTZ, -- NULL = unread created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Case user assignments (who works on which case) CREATE TABLE kanzlai.case_assignments ( case_id UUID NOT NULL REFERENCES kanzlai.cases(id) ON DELETE CASCADE, user_id UUID NOT NULL, role TEXT NOT NULL DEFAULT 'assigned', -- 'lead', 'assigned', 'observer' created_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (case_id, user_id) ); ``` **Backend:** - **Notification worker:** Background goroutine (like CalDAV sync) that runs every minute: 1. Query deadlines where `warning_date = today` or `due_date = tomorrow` or `due_date < today AND status != 'completed'` 2. Look up case assignments to find recipients 3. Create in-app notifications + send emails via `m mail send` 4. Track sent notifications to avoid duplicates (dedup by entity_id + event_type + date) - **API:** `GET /api/notifications` (paginated, unread first), `PATCH /api/notifications/{id}/read`, `PATCH /api/notifications/read-all` - **Email service:** Uses `m mail send` for reliable delivery with Sent folder copy **Frontend:** - Bell icon in header with unread count badge - Notification dropdown/panel showing recent notifications - Notification preferences page in settings - Case detail: "Zugewiesene Personen" section for managing case assignments --- ### 5. Time Tracking (Zeiterfassung) **Why:** Every Kanzleimanagement system has this. Lawyers bill by the hour. Without time tracking, they need a separate system, breaking the workflow. **Design:** **New table: `kanzlai.time_entries`** ```sql CREATE TABLE kanzlai.time_entries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES kanzlai.tenants(id), case_id UUID NOT NULL REFERENCES kanzlai.cases(id), user_id UUID NOT NULL, date DATE NOT NULL, duration INTEGER NOT NULL, -- minutes description TEXT NOT NULL, activity TEXT, -- 'research', 'drafting', 'hearing', 'call', 'review', 'travel' billable BOOLEAN NOT NULL DEFAULT true, billed BOOLEAN NOT NULL DEFAULT false, -- linked to invoice invoice_id UUID, -- set when billed hourly_rate NUMERIC(10,2), -- rate at time of entry (snapshot) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- User hourly rates (can change over time) CREATE TABLE kanzlai.hourly_rates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, user_id UUID NOT NULL, rate NUMERIC(10,2) NOT NULL, -- EUR per hour valid_from DATE NOT NULL, valid_to DATE, -- NULL = current created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **API:** - `GET /api/time-entries?case_id=X&user_id=Y&from=DATE&to=DATE` - `POST /api/time-entries` — create entry - `PUT /api/time-entries/{id}` — update (only if not billed) - `DELETE /api/time-entries/{id}` — delete (only if not billed) - `GET /api/time-entries/summary?group_by=case|user|month` — aggregated view **Frontend:** - Timer widget in header — click to start/stop, auto-fills duration - Case detail: "Zeiterfassung" tab showing time entries for that case - Global time entry page at `/zeit` with weekly view - Quick entry: case selector + duration + description (one-line form) - Activity type dropdown for categorization - Monthly summary view grouped by case **Running timer:** - Store active timer in localStorage (case_id, start_time) - Show elapsed time in header - On stop: pre-fill a time entry creation form --- ### 6. RVG Fee Calculator (Gebuehrenrechner) **Why:** Table stakes for any German law firm software. The RVG Gebührenrechner is what turns time tracking into invoices. **Design:** **New tables:** ```sql -- RVG fee table (Anlage 2 zu § 13 RVG) — versioned for updates CREATE TABLE kanzlai.rvg_fee_table ( id SERIAL PRIMARY KEY, version TEXT NOT NULL, -- '2025-06-01' (KostBRAeG 2025) value_up_to NUMERIC(12,2) NOT NULL, -- Gegenstandswert bis base_fee NUMERIC(10,2) NOT NULL, -- Gebühr valid_from DATE NOT NULL, valid_to DATE -- NULL = current ); -- Fee type catalog (VV-Nummern) CREATE TABLE kanzlai.rvg_fee_types ( id SERIAL PRIMARY KEY, vv_number TEXT NOT NULL, -- 'VV 3100', 'VV 3104', etc. name TEXT NOT NULL, -- 'Verfahrensgebühr 1. Instanz' rate NUMERIC(4,2) NOT NULL, -- Gebührensatz (e.g., 1.3) rate_min NUMERIC(4,2), -- For Rahmengebühren (range fees) rate_max NUMERIC(4,2), context TEXT, -- 'civil_first_instance', 'out_of_court', etc. category TEXT NOT NULL -- 'procedural', 'hearing', 'settlement', 'business' ); -- Invoices CREATE TABLE kanzlai.invoices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, case_id UUID NOT NULL REFERENCES kanzlai.cases(id), invoice_number TEXT NOT NULL, -- Sequential: RE-2026-001 recipient_party_id UUID REFERENCES kanzlai.parties(id), invoice_date DATE NOT NULL, due_date DATE, gegenstandswert NUMERIC(12,2), -- Dispute value fee_items JSONB NOT NULL, -- Array of {vv_number, description, rate, base_fee, amount} expenses JSONB, -- Array of {description, amount} subtotal NUMERIC(10,2) NOT NULL, vat_rate NUMERIC(4,2) NOT NULL DEFAULT 19.00, vat_amount NUMERIC(10,2) NOT NULL, total NUMERIC(10,2) NOT NULL, status TEXT NOT NULL DEFAULT 'draft', -- 'draft', 'sent', 'paid', 'cancelled' paid_at TIMESTAMPTZ, notes TEXT, created_by UUID NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **RVG calculation logic (Go service):** ``` Input: Gegenstandswert, []VV-Nummer Output: fee breakdown with individual items + total 1. Look up base_fee for Gegenstandswert in rvg_fee_table - Linear interpolation for values between steps - Above 500,000: +192 EUR per 50,000 EUR increment 2. For each VV-Nummer: a. Look up rate from rvg_fee_types b. Calculate: base_fee × rate = fee amount 3. Apply Anrechnungsvorschriften: - VV 2300 (Geschäftsgebühr) credited against VV 3100 (Verfahrensgebühr) up to 0.75× 4. Add Auslagen: - Postpauschale: 20% of total fees, max 20 EUR (VV 7002) - Dokumentenpauschale: optional per-page calculation - Custom expenses (travel, etc.) 5. Calculate 19% USt on everything 6. Return structured breakdown ``` **API:** - `POST /api/rvg/calculate` — calculate fees from Gegenstandswert + VV-Nummern - `GET /api/invoices?case_id=X&status=Y` — list invoices - `POST /api/invoices` — create invoice (from RVG calculation or manual) - `PUT /api/invoices/{id}` — update draft invoice - `POST /api/invoices/{id}/send` — mark as sent (+ email to client if portal enabled) - `POST /api/invoices/{id}/pay` — mark as paid **Frontend:** - Fee calculator page at `/abrechnung/rechner` — input Gegenstandswert, select VV numbers, see breakdown - Invoice list at `/abrechnung` with status filters - Invoice creation wizard: select case → choose billing method (RVG or hourly) → review → save - Invoice PDF generation (server-side, using Go HTML→PDF or LaTeX template) - Case detail: "Abrechnung" tab showing invoices + unbilled time entries --- ### 7. DATEV Export (DATEV-Schnittstelle) **Why:** Every German law firm has a Steuerberater who needs DATEV-format data. Without this export, the firm needs to manually re-enter financial data — a dealbreaker. **Design:** **EXTF format export:** Generate Buchungsstapel CSV files from invoices. **Tenant settings additions:** ```json { "datev": { "beraternummer": "12345", "mandantennummer": "67890", "kontenrahmen": "SKR04", "wirtschaftsjahr_beginn": "01.01", "erloes_konto": "4400", "forderungen_konto": "1200" } } ``` **API:** - `POST /api/export/datev` — generate EXTF file for a date range - Input: `{ from: "2026-01-01", to: "2026-03-31" }` - Output: CSV file download - Each invoice maps to one Buchungssatz: - Umsatz = invoice total - Soll/Haben = 'S' - Konto = Forderungskonto (1200) - Gegenkonto = Erlöskonto (4400) - Belegdatum = invoice_date - Belegfeld 1 = invoice_number - Buchungstext = case_number + " " + party name **Frontend:** - Export button in `/abrechnung` page - Date range picker + download button - Settings page: DATEV configuration section --- ## P1: Should-Have Features ### 8. Document Templates (Schriftsatz-Vorlagen) **Why:** Lawyers write the same document types repeatedly. Templates with auto-fill from case data save hours per case. **Design:** **New table: `kanzlai.document_templates`** ```sql CREATE TABLE kanzlai.document_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, name TEXT NOT NULL, -- 'Klageerwiderung UPC', 'Mahnschreiben' category TEXT NOT NULL, -- 'schriftsatz', 'brief', 'intern', 'vertrag' content TEXT NOT NULL, -- Markdown/HTML with {{variable}} placeholders variables JSONB NOT NULL DEFAULT '[]', -- [{name: "mandant", label: "Mandant", source: "party.plaintiff"}] language TEXT NOT NULL DEFAULT 'de', is_active BOOLEAN NOT NULL DEFAULT true, created_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **Template variables (auto-filled from case data):** | Variable | Source | Example | |----------|--------|---------| | `{{mandant}}` | Party with role 'plaintiff' or 'defendant' (depending on side) | "TechCorp GmbH" | | `{{gegner}}` | Opposing party | "PatentTroll AG" | | `{{az}}` | Case number | "UPC_CFI_123/2026" | | `{{gericht}}` | Court | "UPC München Local Division" | | `{{gericht_az}}` | Court reference | "ACT_789456/2026" | | `{{anwalt}}` | Current user's name | "RA Dr. Max Mustermann" | | `{{datum}}` | Today's date | "28. März 2026" | | `{{kanzlei}}` | Tenant name | "Mustermann & Partner" | | `{{naechste_frist}}` | Next deadline title + date | "Statement of Defence — 15.04.2026" | **API:** - `GET /api/templates` — list templates - `POST /api/templates` — create template - `PUT /api/templates/{id}` — update template - `POST /api/templates/{id}/render?case_id=X` — render template with case data, return filled document - `POST /api/templates/{id}/render-pdf?case_id=X` — render and convert to PDF **Frontend:** - Template management page at `/vorlagen` - Template editor with live preview and variable insertion toolbar - "Schriftsatz erstellen" button on case detail page → select template → review filled version → download as PDF or save as document --- ### 9. beA Integration (Elektronisches Anwaltspostfach) **Why:** Since January 2022, German lawyers must use beA for all court filings. It's the primary communication channel with courts. Without beA, the firm still needs RA-MICRO just for filing. **Design:** **Integration path:** Use the **bea.expert REST API** — a third-party wrapper that provides ~40 REST endpoints, avoiding the BRAK Java KSW toolkit dependency. **New tables:** ```sql -- beA account configuration (per-user, per-tenant) CREATE TABLE kanzlai.bea_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, user_id UUID NOT NULL, safe_id TEXT NOT NULL, -- SAFE-ID of the lawyer's mailbox display_name TEXT NOT NULL, -- "RA Dr. Max Mustermann" config JSONB NOT NULL DEFAULT '{}', -- API endpoint, auth config (encrypted) is_active BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- beA messages (cached locally for search and case linking) CREATE TABLE kanzlai.bea_messages ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, bea_account_id UUID NOT NULL REFERENCES kanzlai.bea_accounts(id), bea_message_id TEXT NOT NULL, -- ID from beA system direction TEXT NOT NULL, -- 'inbound', 'outbound' sender_safe_id TEXT NOT NULL, recipient_safe_id TEXT NOT NULL, subject TEXT NOT NULL, body TEXT, attachments JSONB, -- [{name, size, mime_type, storage_path}] case_id UUID REFERENCES kanzlai.cases(id), -- linked case status TEXT NOT NULL DEFAULT 'new', -- 'new', 'read', 'processed', 'filed' received_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **Workflow:** 1. **Configuration:** User enters beA credentials in settings, system validates via bea.expert API 2. **Inbox sync:** Background job polls PostboxOverview every N minutes, caches new messages 3. **Message view:** User sees beA inbox within KanzlAI, can read messages and download attachments 4. **Case linking:** User can link a beA message to a case (drag-and-drop or dropdown). Attachments auto-import as case documents. 5. **Sending:** Compose a message (or use a template), attach documents from case file, send via bea.expert API. Only PDF/TIFF attachments per ERVV. 6. **eEB (elektronische Empfangsbekenntnis):** Handle structured acknowledgments of receipt (XJustiz format) **API:** - `GET /api/bea/inbox` — list cached beA messages - `GET /api/bea/messages/{id}` — get message with attachments - `POST /api/bea/messages/{id}/link` — link message to case - `POST /api/bea/send` — send message via beA - `POST /api/bea/sync` — trigger manual sync **Frontend:** - beA inbox page at `/bea` — email-style list with case assignment - Compose view with template selection and PDF-only attachment validation - Case detail: "beA" tab showing linked messages - Settings: beA account configuration **Licensing:** bea.expert requires a commercial license. Budget for this. --- ### 10. Full-Text Search (Volltextsuche) **Why:** Law firms accumulate thousands of documents and notes. Without search, finding information means clicking through cases one by one. **Design:** **PostgreSQL tsvector approach** (no external search engine needed): ```sql -- Search index materialized from multiple tables CREATE MATERIALIZED VIEW kanzlai.search_index AS SELECT c.tenant_id, 'case' AS entity_type, c.id AS entity_id, c.case_number || ' ' || c.title || ' ' || COALESCE(c.ai_summary, '') AS content, to_tsvector('german', c.case_number || ' ' || c.title || ' ' || COALESCE(c.ai_summary, '')) AS search_vector FROM kanzlai.cases c UNION ALL SELECT p.tenant_id, 'party', p.id, p.name || ' ' || COALESCE(p.representative, ''), to_tsvector('german', p.name || ' ' || COALESCE(p.representative, '')) FROM kanzlai.parties p UNION ALL SELECT d.tenant_id, 'deadline', d.id, d.title || ' ' || COALESCE(d.description, '') || ' ' || COALESCE(d.notes, ''), to_tsvector('german', d.title || ' ' || COALESCE(d.description, '') || ' ' || COALESCE(d.notes, '')) FROM kanzlai.deadlines d UNION ALL SELECT n.tenant_id, 'note', n.id, n.content, to_tsvector('german', n.content) FROM kanzlai.notes n; CREATE INDEX idx_search_vector ON kanzlai.search_index USING gin(search_vector); CREATE INDEX idx_search_tenant ON kanzlai.search_index(tenant_id); ``` Refresh the materialized view periodically or on relevant mutations. **API:** - `GET /api/search?q=TERM&type=case,party,deadline` — cross-entity search with type filtering - Returns: entity type, entity ID, title/name, highlighted snippet, relevance score **Frontend:** - Global search bar in header (Ctrl+K shortcut) - Results grouped by entity type - Click result to navigate to detail page - Search suggestions from recent searches --- ### 11. Reporting & Analytics (Berichte) **Why:** Partners need to see: Are we meeting deadlines? How is workload distributed? Which cases are profitable? Without reporting, the software is a filing cabinet, not a management tool. **Design:** **Report types:** | Report | Description | Audience | |--------|-------------|----------| | Fristeneinhaltung | Deadline compliance rate — % completed on time vs overdue | Partners | | Arbeitsbelastung | Hours by user, by case, by period — who's overloaded? | Partners | | Fallstatistik | Cases by status, type, court — pipeline view | Partners | | Umsatzbericht | Revenue by case, client, period — from invoices | Partners | | Aktivitätsbericht | Actions per user per period — productivity view | Partners | | Fälligkeitsvorschau | Upcoming deadlines across all cases — planning view | All | **API:** - `GET /api/reports/deadline-compliance?from=DATE&to=DATE` — deadline stats - `GET /api/reports/workload?from=DATE&to=DATE&group_by=user|case` — time entry aggregation - `GET /api/reports/case-stats?from=DATE&to=DATE` — case pipeline metrics - `GET /api/reports/revenue?from=DATE&to=DATE&group_by=case|month` — invoice aggregation **Frontend:** - Reports page at `/berichte` — dashboard-style with charts - Date range filter + grouping options - Charts: bar charts for workload, line charts for trends, pie charts for distribution - Export to CSV/PDF for offline sharing - Chart library: lightweight — Recharts or Chart.js (via react-chartjs-2) --- ### 12. Wiedervorlagen (Follow-Up System) **Why:** A fundamental pattern in German law firm workflow — "remind me about this case/document on date X." Different from deadlines: Wiedervorlagen are internal reminders, not procedural deadlines. **Design:** **New table: `kanzlai.follow_ups`** ```sql CREATE TABLE kanzlai.follow_ups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, case_id UUID REFERENCES kanzlai.cases(id), user_id UUID NOT NULL, -- who should be reminded title TEXT NOT NULL, description TEXT, due_date DATE NOT NULL, priority TEXT NOT NULL DEFAULT 'normal', -- 'low', 'normal', 'high', 'urgent' status TEXT NOT NULL DEFAULT 'pending', -- 'pending', 'done', 'snoozed' snoozed_to DATE, -- if snoozed, new date created_by UUID NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), completed_at TIMESTAMPTZ ); ``` **Integration with notifications:** The notification worker checks follow_ups alongside deadlines. **Frontend:** - Quick-create button on any entity detail page: "Wiedervorlage" - Follow-up list at `/wiedervorlagen` with date filtering - Morning email digest: today's follow-ups alongside today's deadlines --- ### 13. Email Integration (E-Mail-Anbindung) **Why:** Most client and opponent communication happens via email. Without email integration, the firm operates in two separate worlds — the email client and KanzlAI. **Design:** **Approach:** IMAP-based email import (not a full email client — that's scope creep). **New tables:** ```sql CREATE TABLE kanzlai.email_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, user_id UUID NOT NULL, email TEXT NOT NULL, imap_host TEXT NOT NULL, imap_port INTEGER NOT NULL DEFAULT 993, smtp_host TEXT, smtp_port INTEGER DEFAULT 587, username TEXT NOT NULL, password TEXT NOT NULL, -- encrypted at rest is_active BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE kanzlai.emails ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, email_account_id UUID NOT NULL REFERENCES kanzlai.email_accounts(id), message_id TEXT NOT NULL, -- RFC 2822 Message-ID direction TEXT NOT NULL, -- 'inbound', 'outbound' from_address TEXT NOT NULL, to_addresses TEXT[] NOT NULL, cc_addresses TEXT[], subject TEXT NOT NULL, body_text TEXT, body_html TEXT, attachments JSONB, case_id UUID REFERENCES kanzlai.cases(id), received_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **Workflow:** 1. Configure IMAP account in settings 2. Background sync fetches new emails periodically 3. User views emails in KanzlAI and links them to cases 4. Auto-suggestion: match sender/recipient against party contacts to suggest case assignment 5. Email attachments can be saved as case documents **Frontend:** - Email page at `/email` — inbox-style list - Case detail: "E-Mail" tab showing linked emails - "Zur Akte" button on each email to link to a case - Settings: email account configuration --- ## P2: Differentiator Features (UPC-Specific Intelligence) These features leverage m's existing infrastructure (youpcms, mLex, youpc.org data) to create an unbeatable competitive advantage for UPC patent litigation. ### 14. Patent Family Tracking **Why:** UPC cases revolve around patents. A case management system for patent litigation that doesn't track patents is like a hospital system that doesn't track patients. **Design:** **New tables:** ```sql CREATE TABLE kanzlai.patents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, patent_number TEXT NOT NULL, -- 'EP1234567' title TEXT, applicant TEXT, filing_date DATE, grant_date DATE, expiry_date DATE, status TEXT NOT NULL DEFAULT 'active', -- 'active', 'expired', 'withdrawn', 'revoked' patent_type TEXT, -- 'EP', 'UP', 'DE', 'US', 'WO' opt_out_status TEXT, -- 'opted_out', 'not_opted_out', 'opt_out_withdrawn' opt_out_date DATE, claims_count INTEGER, abstract TEXT, metadata JSONB, -- Classifications, designations, priority data created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Patent family relationships CREATE TABLE kanzlai.patent_family ( parent_patent_id UUID NOT NULL REFERENCES kanzlai.patents(id), child_patent_id UUID NOT NULL REFERENCES kanzlai.patents(id), relationship TEXT NOT NULL, -- 'national_validation', 'divisional', 'continuation', 'priority' PRIMARY KEY (parent_patent_id, child_patent_id) ); -- Link patents to cases CREATE TABLE kanzlai.case_patents ( case_id UUID NOT NULL REFERENCES kanzlai.cases(id) ON DELETE CASCADE, patent_id UUID NOT NULL REFERENCES kanzlai.patents(id), role TEXT NOT NULL, -- 'asserted', 'challenged', 'prior_art' PRIMARY KEY (case_id, patent_id) ); ``` **Integration with youpc.org/EPO:** - Auto-lookup patent data from EPO Open Patent Services (OPS) API by patent number - Import patent family tree from EPO - Track opt-out status from UPC opt-out register **Frontend:** - Case detail: "Patente" tab showing linked patents with family tree visualization - Patent detail page showing full patent info + all cases where it appears - Auto-fill case data when a patent number is entered --- ### 15. Claim Chart Management **Why:** Claim charts (Merkmalsgliederung) are the core analytical tool in patent litigation — mapping claim elements to accused products or prior art. No existing Kanzleimanagement system handles this. **Design:** **New tables:** ```sql CREATE TABLE kanzlai.claim_charts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, case_id UUID NOT NULL REFERENCES kanzlai.cases(id), patent_id UUID REFERENCES kanzlai.patents(id), title TEXT NOT NULL, -- 'Claim 1 Infringement Analysis' chart_type TEXT NOT NULL, -- 'infringement', 'invalidity', 'comparison' status TEXT NOT NULL DEFAULT 'draft', created_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE kanzlai.claim_chart_entries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), chart_id UUID NOT NULL REFERENCES kanzlai.claim_charts(id) ON DELETE CASCADE, claim_element TEXT NOT NULL, -- 'a mounting bracket configured to...' element_number TEXT, -- '1a', '1b', '1c' evidence TEXT, -- 'Accused product uses X-shaped bracket (see Exhibit 3, p.12)' assessment TEXT, -- 'literally_met', 'equivalent', 'not_met', 'unclear' documents JSONB, -- [{document_id, page, highlight}] sort_order INTEGER NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` **Frontend:** - Case detail: "Claim Charts" tab - Two-column view: claim element (left) | evidence (right) - Color-coded assessment: green (met), yellow (equivalent/unclear), red (not met) - Drag-drop reordering of elements - Link evidence to uploaded documents with page references - Export to Word/PDF for court submissions --- ### 16. UPC Case Intelligence (mLex Integration) **Why:** m has 1,600+ structured UPC decisions with holdings, legal principles, citation networks, and division analytics. No competitor has this data. This turns KanzlAI from "case file management" into "case strategy intelligence." **Design:** **Integration approach:** Connect to the existing youpc.org/mLex Supabase database (same flexsiebels instance) via cross-schema queries or a dedicated API endpoint. **Features:** **A) Similar Case Finder** - Input: case type, court, patent classification, key issues - Output: relevant UPC decisions from the mLex database, ranked by similarity - Uses pgvector embeddings on holdings + legal principles for semantic search - "Wie hat die Münchner Lokalkammer bisher über Softwarepatente entschieden?" **B) Division Analytics** - Per-division statistics: success rates, average timeline, judge panel compositions - "München grants PI in 40% of cases, median time to hearing: 8 months" - Updated automatically as new decisions are scraped **C) Legal Principle Lookup** - Search legal principles extracted from UPC case law - "Show me all decisions on claim construction of functional features" - Returns structured holdings with citations **D) Precedent Suggestions** - When drafting a Schriftsatz, suggest relevant precedents based on case type and issues - AI-powered: Claude analyzes the case context and retrieves relevant mLex decisions **API:** - `GET /api/upc/similar-cases?case_id=X` — find similar cases - `GET /api/upc/division-stats?division=MUNICH` — division analytics - `GET /api/upc/principles?query=TERM` — search legal principles - `POST /api/upc/suggest-precedents` — AI-powered precedent suggestion **Frontend:** - Case detail: "UPC Intelligence" tab (only for UPC-type cases) - Global UPC research page at `/upc-recherche` - Division comparison tool (already partially exists in youpc.org) --- ### 17. AI Document Drafting **Why:** Combine case data + templates + legal intelligence to generate first drafts. This is the "wow factor" that gets users to switch from RA-MICRO. **Design:** **Workflow:** 1. User selects a document type (e.g., "Statement of Defence") and a case 2. System loads: case data, parties, patent info, relevant deadlines, linked documents, relevant precedents from mLex 3. Claude generates a structured first draft using the template + case context 4. User reviews and edits in a rich text editor 5. Export to PDF for filing **API:** - `POST /api/ai/draft` — generate document draft - Input: `{ case_id, template_id, instructions, include_precedents: true }` - Output: structured document in Markdown/HTML - Rate-limited: 3 requests/minute (more expensive than extraction) **Frontend:** - "KI-Entwurf" button on the template rendering page - Split view: generated draft (left) | case context (right) - Edit capabilities before saving as document **Privacy consideration:** Case data sent to Claude API. Tenants must opt-in, with clear data processing agreement. Consider self-hosted Claude via AWS Bedrock for sensitive firms. --- ### 18. AI Case Strategy Analysis **Why:** Beyond document management — help lawyers think about their cases. "What are the strengths and weaknesses of our position?" **Design:** **AI analysis types:** | Analysis | Input | Output | |----------|-------|--------| | Strengths/Weaknesses | Case data + claim charts | Bullet-point analysis with confidence | | Timeline Prediction | Case type + division | Estimated timeline based on historical data | | Cost Estimate | Case type + Gegenstandswert | Estimated legal costs (own + opponent) | | Strategy Options | Full case data | Recommended approaches with pros/cons | **API:** - `POST /api/ai/analyze-strategy` — comprehensive case analysis - Input: `{ case_id, analysis_type }` - Output: structured analysis with sections **Frontend:** - Case detail: "KI-Analyse" tab - Analysis results cached and versioned (re-run as case evolves) - Each analysis shows the date it was generated and what data it was based on --- ## P3: Nice-to-Have Features ### 19. Client Portal (Mandantenportal) External-facing view where clients can see the status of their cases. **Design:** - Separate authentication (email + password, no Supabase Auth dependency) - Read-only access to assigned cases: status, upcoming deadlines, recent events - Secure document exchange: client can upload documents, lawyer can share documents - Invoice viewing and payment status - Accessible via subdomain: `portal.kanzlai.msbls.de` **Data model:** Use the `extern` role from the permissions system. Client portal users are linked to specific cases via `case_assignments`. --- ### 20. Mobile Optimization / PWA **Design:** - Progressive Web App with offline capability for viewing case data - Service worker for push notifications (deadline reminders) - Optimized touch targets and mobile layouts (already partially done with responsive Tailwind) - Add `manifest.json` with installable app metadata - Minimal — not a native app, but installable from browser --- ### 21. Multi-Language Support (Mehrsprachigkeit) **Design:** - `next-intl` for frontend internationalization - German primary, English for UPC work - Language selector in settings - Template system already supports per-template language - Backend API responses use language-neutral keys; frontend maps to locale --- ### 22. EDA Integration (Elektronisches Mahnverfahren) **Design:** - Generate EDA-format files for electronic dunning proceedings - Submit to the relevant Mahngericht - Track Mahnbescheid and Vollstreckungsbescheid status - Lower priority — UPC firms rarely do Mahnverfahren --- ### 23. Advanced Integrations | Integration | Priority | Effort | Notes | |-------------|----------|--------|-------| | Microsoft 365 Calendar | P3 | Medium | Alternative to CalDAV for firms using Outlook | | Google Workspace | P3 | Medium | Alternative auth + calendar | | Schufa/Creditreform | P3 | High | Credit checks on parties — requires contracts | | EPO OPS API | P2 | Medium | Auto-fetch patent data by number | | DPMA DPMAregister | P3 | Medium | German patent/trademark status | | Slack/Teams webhooks | P3 | Low | Notification delivery alternative | --- ## Data Model Summary: New Tables | Table | Priority | Purpose | |-------|----------|---------| | `audit_log` | P0 | Append-only change history | | `conflict_checks` | P0 | Conflict of interest check results | | `permissions` | P0 | Role-action permission matrix | | `notifications` | P0 | In-app notification inbox | | `notification_preferences` | P0 | Per-user notification settings | | `case_assignments` | P0 | Who works on which case | | `time_entries` | P0 | Billable time tracking | | `hourly_rates` | P0 | Per-user billing rates | | `rvg_fee_table` | P0 | RVG Gebührentabelle (reference) | | `rvg_fee_types` | P0 | VV-Nummern catalog (reference) | | `invoices` | P0 | Fee invoices | | `follow_ups` | P1 | Wiedervorlagen | | `document_templates` | P1 | Schriftsatz templates | | `bea_accounts` | P1 | beA mailbox config | | `bea_messages` | P1 | Cached beA messages | | `email_accounts` | P1 | IMAP email config | | `emails` | P1 | Cached emails linked to cases | | `patents` | P2 | Patent tracking | | `patent_family` | P2 | Patent family relationships | | `case_patents` | P2 | Case-patent linking | | `claim_charts` | P2 | Patent claim analysis | | `claim_chart_entries` | P2 | Claim chart rows | | `party_relationships` | P1 | Corporate structures for conflict checks | | `search_index` | P1 | Full-text search materialized view | **Total new tables:** 24 (on top of existing 12) --- ## Implementation Phases ### Phase 1: Foundation (P0 core — audit, permissions, notifications) **Goal:** Make the existing MVP production-safe. | Task | Effort | Dependencies | |------|--------|--------------| | Audit trail table + middleware | 3-4 days | None | | Role-based permissions (extend existing roles) | 2-3 days | None | | Case assignments table + UI | 1-2 days | None | | Notification system (in-app + email) | 3-4 days | Case assignments | | Notification preferences UI | 1 day | Notifications | **Deliverable:** Every change is logged. Users have proper roles. Deadlines trigger reminders. ### Phase 2: Money (P0 — time tracking, RVG, invoicing, DATEV) **Goal:** The billing pipeline — from time entry to DATEV export. | Task | Effort | Dependencies | |------|--------|--------------| | Time entries table + CRUD + API | 2-3 days | None | | Timer UI (header widget + case tab) | 2 days | Time entries API | | Hourly rates configuration | 1 day | None | | RVG fee table + calculator service | 2-3 days | None | | RVG calculator UI | 1-2 days | Calculator service | | Invoice model + CRUD + API | 2-3 days | RVG calculator | | Invoice creation wizard UI | 2-3 days | Invoice API | | Invoice PDF generation | 1-2 days | Invoice model | | DATEV EXTF export | 1-2 days | Invoices | **Deliverable:** Complete billing pipeline. Lawyers can track time, calculate fees, generate invoices, export to DATEV. ### Phase 3: Compliance (P0 — conflict checks) **Goal:** Statutory compliance for conflict of interest. | Task | Effort | Dependencies | |------|--------|--------------| | pg_trgm extension + party search index | 1 day | None | | Conflict check service (exact + fuzzy) | 2-3 days | None | | Conflict check on case creation (auto-trigger) | 1 day | Conflict service | | Conflict check UI (results + clearance) | 2 days | Conflict API | | Cologne phonetic matching | 1-2 days | Conflict service | **Deliverable:** Automatic conflict checking on every new case/party. Auditable clearance workflow. ### Phase 4: Communication (P1 — beA, email, templates) **Goal:** KanzlAI becomes the central communication hub. | Task | Effort | Dependencies | |------|--------|--------------| | Document template engine | 3-4 days | None | | Template editor UI | 2-3 days | Template engine | | Full-text search (materialized view + API) | 2-3 days | None | | Search UI (global search bar) | 1-2 days | Search API | | Follow-up (Wiedervorlagen) system | 2 days | Notifications | | beA integration (bea.expert API) | 5-7 days | License agreement | | Email integration (IMAP sync) | 4-5 days | None | **Deliverable:** Templates, search, beA, email — all communication flows through KanzlAI. ### Phase 5: UPC Intelligence (P2 — the differentiator) **Goal:** No competitor can match this. | Task | Effort | Dependencies | |------|--------|--------------| | Patent model + family tracking | 2-3 days | None | | EPO OPS API integration (auto-fetch patent data) | 2-3 days | Patent model | | Claim chart management | 3-4 days | Patent model | | mLex cross-schema queries | 2-3 days | Existing mLex data | | Similar case finder | 2-3 days | mLex integration | | Division analytics dashboard | 2-3 days | mLex integration | | AI document drafting | 3-4 days | Templates + mLex | | AI strategy analysis | 2-3 days | mLex + case data | **Deliverable:** UPC-specific intelligence layer. Patent tracking, claim charts, case law search, AI strategy. ### Phase 6: Polish (P3) **Goal:** Professional finish. | Task | Effort | Dependencies | |------|--------|--------------| | Client portal | 5-7 days | Invoices, case assignments | | PWA + push notifications | 2-3 days | Notification system | | Multi-language (DE/EN) | 3-4 days | All UI pages | | Reporting dashboard | 3-4 days | Time entries, invoices | | EDA Mahnverfahren | 3-4 days | Invoices | --- ## New Frontend Routes (Complete) ``` Existing: /dashboard /cases, /cases/new, /cases/[id]/* /fristen, /fristen/neu, /fristen/rechner, /fristen/[id] /termine, /termine/neu, /termine/[id] /ai/extract /einstellungen, /einstellungen/team New (P0): /protokoll Audit log viewer (admin) /zeit Time tracking overview (weekly view) /abrechnung Invoice list /abrechnung/rechner RVG fee calculator /abrechnung/[id] Invoice detail /kollision Manual conflict check /benachrichtigungen Notification center New (P1): /vorlagen Document template management /vorlagen/[id] Template editor /bea beA inbox /bea/compose beA compose message /email Email inbox /wiedervorlagen Follow-up list /suche Full search results page New (P2): /upc-recherche UPC case law research /upc-recherche/divisionen Division analytics /patente Patent list /patente/[id] Patent detail + family tree New (P3): /berichte Reporting dashboard portal.* Client portal (separate app/subdomain) ``` --- ## Architecture Decisions ### 1. Stay on Go + Next.js The current stack is solid. No framework migration needed. Go handles the backend complexity well (concurrent CalDAV sync, notification workers, beA polling). Next.js App Router is mature enough for the frontend. ### 2. Stay on Supabase All new tables go in the `kanzlai` schema. The flexsiebels instance already has the mLex data in another schema — cross-schema queries enable the UPC intelligence layer without data duplication. ### 3. Background Workers as Goroutines The CalDAV sync pattern (background goroutine with interval) extends to: notification dispatch, beA polling, email sync, search index refresh. Keep them in the same Go binary — no need for a separate worker process yet. ### 4. PDF Generation Use Go's `html/template` → HTML → `wkhtmltopdf` (or `chromedp` headless) for invoice and document PDF generation. Keep it server-side. ### 5. beA via bea.expert The bea.expert REST API is the only sane integration path. BRAK's Java KSW toolkit is not viable for a modern web app. ### 6. No External Search Engine PostgreSQL full-text search with `tsvector` + `pg_trgm` is sufficient for the data volumes a single law firm generates. No Elasticsearch/Meilisearch needed — reduces operational complexity. --- ## Competitive Positioning | Feature | RA-MICRO | Advoware | Kleos | **KanzlAI** | |---------|----------|----------|-------|-------------| | General Kanzleimanagement | Full | Full | Full | **Full (after P0-P1)** | | beA Integration | Yes | Yes | Yes | **Yes (P1)** | | RVG Calculator | Yes | Yes | Yes | **Yes (P0)** | | DATEV Export | Yes | Yes | Yes | **Yes (P0)** | | Cloud-Native | Partial | Partial | Yes | **Yes** | | UPC Deadline Rules | No | No | No | **Yes (already shipped)** | | UPC Case Law Database | No | No | No | **Yes (P2)** | | AI Deadline Extraction | No | No | No | **Yes (already shipped)** | | AI Document Drafting | Partial | No | No | **Yes (P2)** | | Patent Family Tracking | No | No | No | **Yes (P2)** | | Claim Chart Management | No | No | No | **Yes (P2)** | | Division Analytics | No | No | No | **Yes (P2)** | | Multi-Tenant SaaS | No | No | Yes | **Yes (already shipped)** | **Tagline:** "Die einzige Kanzleisoftware, die UPC-Patentprozesse versteht." --- ## Risk Register | Risk | Impact | Mitigation | |------|--------|------------| | beA API changes / bea.expert discontinuation | High | Abstract beA behind an interface; monitor BRAK announcements | | RVG table updates (new Kostenrechtsänderungsgesetz) | Medium | Versioned fee table with effective dates; easy to update | | DSGVO compliance for AI features (data sent to Claude) | High | Offer self-hosted Claude via Bedrock; explicit tenant opt-in | | Scope creep on P2 features | Medium | Ship P0+P1 first; P2 only after core is solid | | Single-developer bottleneck | High | Clean architecture, good docs, modular services | | UPC procedural rules change | Low | Rules in database, not hardcoded; already have update pattern | --- ## Success Metrics | Metric | Target | How to Measure | |--------|--------|----------------| | Deadline compliance rate | > 99% | No overdue deadlines that weren't caught by reminders | | Time from case creation to first deadline | < 5 min | AI extraction + deadline calculator | | Invoice generation time | < 2 min | RVG calculator + template | | Conflict check time | < 3 sec | Automated on case creation | | User adoption | 1 firm within 3 months of P0 | Direct outreach to patent firms | | Feature parity with competitors | P0+P1 complete | Checklist comparison | --- ## Appendix: Prior Design Documents - `DESIGN-dashboard-redesign.md` — t-kz-060: Dashboard interactivity + detail pages (implemented) - This document (`ROADMAP.md`) — t-kz-070: Full system vision --- *This roadmap is a living document. Features will be re-prioritized as user feedback comes in. The UPC intelligence layer (P2) is the strategic differentiator — but P0 must ship first to establish credibility as a serious Kanzleimanagement system.*