Files
paliad/.claude/CLAUDE.md
mAi 8f6cee5a83 chore(t-paliad-194): delete paliad-side paliadin skill bundle (SoT moved to m/mAi)
Per m's 2026-05-13 decision (m/mAi#207 §13 Q4): the paliadin SKILL.md
and references/sql-recipes.md are now owned by aichat. The aichat repo
already has the equivalents committed at skills/aichat/paliadin/ on
mai/darwin/issue-207-aichat (verified before this commit). Aichat's
own deploy doc handles installation on mRiver.

Deleted:
  scripts/skills/paliadin/SKILL.md
  scripts/skills/paliadin/references/sql-recipes.md
  scripts/install-paliadin-skill

Legacy LocalPaliadinService / RemotePaliadinService still depend on
~/.claude/skills/paliadin/ being present on whichever host they run
against. Until those paths retire (Phase C / Q15), operators install
the skill manually from m/mAi/skills/aichat/paliadin/.

CLAUDE.md updated:
  - PALIADIN_SESSION_PREFIX row points readers at m/mAi for the skill
    SoT and notes the legacy paths still expect a manual install.
  - New env-var rows for PALIADIN_BACKEND / AICHAT_URL / AICHAT_TOKEN /
    AICHAT_PERSONA so the operator runbook for the Phase B flip is
    self-contained.
2026-05-15 03:03:49 +02:00

12 KiB

paliad

Paliad — the patent paladin. All-in-one patent practice platform for HLC (formerly Hogan Lovells) colleagues. Knowledge platform + Aktenverwaltung in one sidebar, one URL, one login.

Brand: Paliad (firm-agnostic — survives firm renames) Primary domain: paliad.de Legacy domains: patholo.de, patholo.msbls.de (active during transition) Memory group_id: paliad mai project_id: paliad

Purpose

  • Project management — hierarchical projects (Client → Litigation → Patent → Case), deadlines, appointments, parties, notes, audit trail. Team-based visibility with inheritance down the project tree. Personal CalDAV sync.
  • Interactive knowledge tools — Prozesskostenrechner, Fristenrechner, Gebührentabellen, Checklisten, Gerichtsverzeichnis, Patentglossar, Link Hub, Downloads.
  • Dashboard — logged-in landing with deadline traffic lights, upcoming appointments, recent activity, all scoped to visible projects.
  • Share guides, templates, and documents with the patent team.
  • Document best practices and style guides (HL Patents Style).
  • Long-term: document upload, collaboration annotations, Outlook/Exchange sync.

Audience

  • HLC patent lawyers and PAs (Munich, Düsseldorf, Amsterdam, London, Paris, Milan, Hamburg)
  • Primary languages: German + English (DE/EN toggle on every page)
  • Must be accessible, clean, professional

Tech Stack

  • Frontend: Bun + TSX (custom JSX renderer, no React), per-page client TS bundles, HTML-first forms
  • Backend: Go API, net/http, sqlx for DB access
  • Migrations: golang-migrate/migrate/v4 with SQL files embedded via embed.FS; applied at server startup before the HTTP listener binds. Migration tracker is paliad.paliad_schema_migrations (avoids collision with other apps on the shared public.schema_migrations).
  • Database: youpc Supabase Postgres (port 11833), paliad schema. Team-based RLS via paliad.can_see_project(project_id) — visibility determined by team membership (direct + inherited up the project tree). See docs/design-data-model-v2.md.
  • Auth: Supabase (youpc instance) — password-based, email-domain gate via ALLOWED_EMAIL_DOMAINS (default hoganlovells.com,hlc.com,hlc.de). The whitelist references real DNS domains and rotates independently from FIRM_NAME (display name).
  • Hosting: Dokploy compose on mlake (72.62.52.189), compose ID Zx147ycurfYagKRl_Zzyo
  • Domains on Dokploy: paliad.de (primary, Let's Encrypt), patholo.de (legacy), patholo.msbls.de (internal)
  • Deploy: push to main → Gitea webhook → Dokploy auto-deploy

Environment variables

Variable Required Purpose
PORT no (default 8080) HTTP listen port
SUPABASE_URL yes Supabase project URL (auth)
SUPABASE_ANON_KEY yes Supabase anon key (auth)
DATABASE_URL for Aktenverwaltung Direct Postgres conn for migrations + Akten/Fristen/Termine services. Knowledge-platform features (Kostenrechner, Glossar, Links, Gebührentabellen, Checklisten, Gerichte, Downloads) work without it — those endpoints return data from static JSON and never touch the pool. Aktenverwaltung endpoints return 503 if unset.
CALDAV_ENCRYPTION_KEY for CalDAV sync 32-byte AES-256 key, base64-encoded. Encrypts CalDAV passwords at rest (AES-GCM). Server fails fast on malformed key; CalDAV is silently disabled if unset (Termine still work locally; /api/caldav-config returns 501).
GITEA_TOKEN optional Gitea API token for the private file proxy (Downloads)
PALIAD_BASE_URL optional Public origin used in email links. Defaults to https://paliad.de; override for staging/preview.
SMTP_HOST / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD / SMTP_FROM / SMTP_FROM_NAME / SMTP_USE_TLS for email SMTP credentials for Paliad's transactional mail (reminders, invitations). Port 465 uses implicit TLS. MailService silently no-ops when any required var is missing — the server still boots for knowledge-platform-only deployments.
ANTHROPIC_API_KEY not used in PoC Reserved for the eventual production-v1 Paliadin (the Anthropic Messages API path, see docs/design-paliadin-2026-05-07.md §2). The Phase 0 PoC (t-paliad-146) does NOT use this — it shells out to a local claude CLI via tmux instead, which uses m's existing Claude Code subscription. Set this env var only after the PoC validates and we cut over to the API-backed path. The earlier "Phase H Frist-Extraktion" reservation is dead — that feature is deferred separately (memory b6a11b55…).
PALIADIN_SESSION_PREFIX optional (default paliad-paliadin) Prefix for the per-user tmux session names the legacy Paliadin service uses (t-paliad-155). Each Paliad user gets their own session named <prefix>-<userid8> (first 8 hex chars of the user's UUID); conversation history accumulates per visit, ResetSession kills the session entirely. Skill source-of-truth moved to m/mAi under skills/aichat/paliadin/ (m's 2026-05-13 decision, t-paliad-194). The aichat backend owns installation on mRiver via its own deploy doc (m/mAi/docs/reference/aichat-deploy.md). Legacy LocalPaliadinService (PoC) and RemotePaliadinService (shim) still rely on ~/.claude/skills/paliadin/SKILL.md being present on the target host — install it manually from the aichat repo until those paths are retired.
PALIADIN_REMOTE_CWD shim env (default /home/m/dev/paliad) Working directory paliadin-shim uses when spawning the long-lived claude pane on mRiver. Must be the paliad repo root so claude picks up .mcp.json (project-scoped Supabase MCP); without it, the SKILL.md SQL recipes have no DB tool. Set on mRiver only — paliad's Go side never reads this.
PALIADIN_RESPONSE_DIR optional (default /tmp/paliadin) Directory where Claude writes its per-turn response files. The Go service polls this directory for {turn_id}.txt files. (Legacy LocalPaliadinService path only — aichat owns its own response dir at /tmp/aichat/paliadin/.)
PALIADIN_BACKEND optional (default legacy) Selects which Paliadin backend boots (t-paliad-194 / m/paliad#38 Phase B). legacy keeps the existing tree (PALIADIN_REMOTE_HOST → SSH shim, else local tmux, else disabled). aichat opts into the centralized m/mAi#207 backend on mRiver — RemotePaliadinService/LocalPaliadinService are bypassed and AichatPaliadinService issues HTTP calls instead. Parallel paths during the migration window; flip back is one env-var change.
AICHAT_URL required when PALIADIN_BACKEND=aichat Aichat service root (typically http://100.99.98.203:8765 over Tailscale; see m/mAi/docs/reference/aichat-deploy.md). No trailing slash needed.
AICHAT_TOKEN required when PALIADIN_BACKEND=aichat Raw bearer token registered for paliad's app_id in aichat's tokens.yaml. Distributed via Dokploy secret per Q11 (age-encrypted at rest).
AICHAT_PERSONA optional (default paliadin) Persona id to target. Override only when running a non-default deploy (e.g. staging persona).

Note on Paliadin gating (t-paliad-146): there is no PALIADIN_ENABLED env var. Access is gated in code via services.PaliadinOwnerEmail (currently matthias.siebels@hoganlovells.com). Every other authenticated user gets a 404 on /paliadin and /admin/paliadin. This means the routes register on every paliad deploy (including paliad.de prod), but only m can reach them — and even then, prod only works if the host has tmux + a claude CLI in PATH (which the Dokploy container does not). PoC remains a laptop-only feature; the gate is in the code, not the deploy. | FIRM_NAME | optional (default HLC) | Display name of the firm Paliad is being branded for in this deployment. Read once at process start by internal/branding.Name (Go) and inlined into client bundles by frontend/build.ts (TypeScript). Powers every user-facing surface — landing hero, page titles, login hint, Downloads page, footer, invitation/reminder email bodies. The ALLOWED_EMAIL_DOMAINS whitelist is a separate concern (real DNS domains, not display name) and rotates independently. |

Note on DATABASE_URL: "Work without DB" ≠ "ungated". All knowledge-platform routes (Kostenrechner, Glossar, Links, Gebührentabellen, Checklisten, Gerichte, Downloads) are still behind the auth gate (302 to /login for anon visitors); only /, /login, /logout, and /assets/* are public. The gateOnboarded middleware additionally blocks unonboarded users from app pages but does NOT gate the knowledge-platform pages.

Infrastructure

  • Gitea: m/paliad on mgit.msbls.de (renamed from mAi/paliad 2026-04-30; previously mAi/patholo — auto-redirects)
  • DNS: paliad.de → 72.62.52.189 (via Hostinger)
  • Branding: lime green accent (#c6f41c), sidebar layout, DE/EN i18n. Firm-agnostic: every user-facing firm reference is rendered from internal/branding.Name (Go) / frontend/src/branding.ts (TypeScript). Default "HLC", overridable via FIRM_NAME. See t-paliad-065.

Project status & history

Phase status, shipped milestones, open follow-ups, and the patHoLo→Paliad rebrand history live in docs/project-status.md. Read that before assuming a feature is or isn't built.

Worker Preferences

  • Use Opus for design/architecture decisions
  • Use Sonnet for implementation
  • Prefer gitster role for issues

Language convention

System language is English. All code, table names, Go types, service names, URL paths, API endpoints, file names — English. Examples: projects not projekte, deadlines not fristen, appointments not termine, ProjectService not ProjektService, /projects not /projekte.

Frontend default language is German. User-facing i18n strings are bilingual (DE primary, EN secondary). UI labels, error messages, page titles — all translated via i18n.ts. The product speaks German to its users but the codebase speaks English to developers.

Product tool names stay German as brand names: Fristenrechner, Kostenrechner, Gebührentabellen (these are proper nouns in the product context, kept in URLs as /tools/fristenrechner etc.).

Frontend conventions

.entity-table row-click contract. The default .entity-table tbody tr rule sets cursor: pointer + a hover highlight on every row. If you add an .entity-table to a page, the row affordance must match reality:

  • Rows that navigate — wire a row-level click handler that does window.location.href = "..." and skips clicks on inner <a> / <button> (so nested links and action buttons still work). Pattern lives in frontend/src/client/checklists.ts, client/projects-detail.ts, client/deadlines.ts.
  • Rows that don't navigate (read-only summary tables, admin tables where all actions are inline buttons) — add entity-table--readonly to the <table> className. That modifier neutralises the cursor and hover.

A row that looks clickable but isn't is a UX lie and confuses users (cf. t-paliad-098/099). The CSS rule and modifier are anchored in frontend/src/styles/global.css near .entity-table tbody tr.

Whole-card / whole-row click → use a JS row handler, not a ::before overlay. Don't make a card fully clickable by spanning a ::before { inset: 0 } (or any pointer-event overlay) over it — the overlay swallows pointer events on the text and breaks selection / copy (cf. t-paliad-102 → t-paliad-103). Instead, attach a row-level click handler that calls window.location.href = ... and skips clicks on inner <a> / <button> (the same pattern as the .entity-table rule above). Examples on .entity-event (Verlauf) and .dashboard-activity-item in frontend/src/client/projects-detail.ts + client/dashboard.ts. Text stays selectable, click still navigates, keyboard / Cmd-click semantics intact.