From 67cd66e054d0bc7f7484e9d81ed776980f554833 Mon Sep 17 00:00:00 2001
From: m
Date: Sat, 18 Apr 2026 09:14:43 +0200
Subject: [PATCH] =?UTF-8?q?fix:=20audit=20quick=20wins=20=E2=80=94=20impor?=
=?UTF-8?q?tant=20+=20polish=20batch=20(t-paliad-017)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Items from docs/improvement-audit.md §2 + §3:
I-1 Hide Dokumente tab entirely from Akten detail (Phase H deferred);
drop placeholder TSX panel, VALID_TABS entry, and orphaned
akten.detail.soon.* i18n keys.
I-2 Add data-i18n keys for all 7 office labels on the landing page.
EN mode now correctly renders "Milan" (was "Mailand").
I-3 Unify UPC URLs in Gerichtsverzeichnis to the canonical hyphenated
form (unified-patent-court.org) matching links.go — 43 occurrences.
I-6 Add SEP/FRAND glossary category with 13 entries (FRAND, SEP,
Standard-essentielles Patent, Patentpool, Anti-Suit, Anti-Anti-Suit,
Injunction Gap, Orange-Book-Standard, Huawei/ZTE, RAND, ETSI IPR,
Patent-Hold-up, Patent-Hold-out) + filter pill + suggest-modal option.
I-7 Refresh README: list migration 014 (checklist_instances), mark
Phase I (Notizen) and Phase J (docs) shipped.
P-1 Remove HL Intern stub links (URL "#") and the now-empty "hl" category.
P-2 Dashboard heading: "Meine Mandate" → "Meine Akten" (matches CLAUDE.md
naming convention). Onboarding hint updated likewise.
P-4 Drop "Hogan Lovells Patent Practice" from the footer — Paliad is the
firm-agnostic brand.
P-5 Empty-state text on Fristen- and Termine-Kalender when the viewed
month has no items.
Verified: bun run build clean, go build / vet / test ./... clean.
---
README.md | 7 +-
frontend/src/akten-detail.tsx | 11 ----
frontend/src/client/akten-detail.ts | 4 +-
frontend/src/client/fristen-kalender.ts | 9 +++
frontend/src/client/i18n.ts | 38 ++++++-----
frontend/src/client/termine-kalender.ts | 9 +++
frontend/src/components/Footer.tsx | 2 +-
frontend/src/dashboard.tsx | 4 +-
frontend/src/fristen-kalender.tsx | 4 ++
frontend/src/glossar.tsx | 2 +
frontend/src/index.tsx | 14 ++--
frontend/src/termine-kalender.tsx | 4 ++
internal/handlers/gerichte.go | 86 ++++++++++++-------------
internal/handlers/glossar.go | 15 +++++
internal/handlers/links.go | 17 -----
15 files changed, 124 insertions(+), 102 deletions(-)
diff --git a/README.md b/README.md
index 8a104af..1ab8eb6 100644
--- a/README.md
+++ b/README.md
@@ -40,13 +40,14 @@ Current migrations (as of April 2026):
011_feedback_tables link_suggestions, checklisten_feedback, gerichte_feedback
012_fristenrechner_rules DB-backed rule set for /tools/fristenrechner
013_user_caldav_config per-user CalDAV (encrypted) + sync log
+014_checklist_instances persisted checklist instances linkable to Akten
```
Add a new migration:
```
-internal/db/migrations/014_.up.sql
-internal/db/migrations/014_.down.sql
+internal/db/migrations/015_.up.sql
+internal/db/migrations/015_.down.sql
```
The down file is required and must reverse the up cleanly (verified by adding a one-off down test before merge).
@@ -104,6 +105,6 @@ Push to `main` → Gitea webhook → Dokploy auto-deploy on mlake.
## Project status (April 2026)
-Phases A–G of the KanzlAI integration are shipped (schema, services, Akten, Fristen, Termine + CalDAV, Dashboard). Phase H (AI Frist extraction) is **deferred** pending a reversal of the "no Anthropic API" decision. Phase I (Notizen service + UI) pending — the polymorphic schema exists (`paliad.notizen`) but the service and UI aren't built yet.
+Phases A–G, I and J of the KanzlAI integration are shipped: schema, services, Akten, Fristen, Termine + CalDAV, Dashboard, Notizen service + UI (commit `5a9f8e5`, 2026-04-17), and instanceable Checklisten (migration 014). Phase H (AI Frist extraction) is **deferred** pending a reversal of the "no Anthropic API" decision; the Dokumente tab on Akten detail is hidden until that lands. KanzlAI infra retirement (Dokploy shutdown, `kanzlai` schema drop, Gitea archive) is still pending.
See `docs/feature-roadmap.md` for the full backlog and `docs/design-kanzlai-integration.md` for the integration design.
diff --git a/frontend/src/akten-detail.tsx b/frontend/src/akten-detail.tsx
index ace693a..8740253 100644
--- a/frontend/src/akten-detail.tsx
+++ b/frontend/src/akten-detail.tsx
@@ -57,7 +57,6 @@ export function renderAktenDetail(): string {
Parteien
Fristen
Termine
- Dokumente
Notizen
Checklisten
@@ -212,16 +211,6 @@ export function renderAktenDetail(): string {
- {/* Dokumente — Phase H placeholder */}
-
-
-
Bald verfügbar
-
- Dokumenten-Upload folgt in Phase H.
-
-
-
-
{/* Notizen — Phase I */}
diff --git a/frontend/src/client/akten-detail.ts b/frontend/src/client/akten-detail.ts
index 277fed9..fd2eb0c 100644
--- a/frontend/src/client/akten-detail.ts
+++ b/frontend/src/client/akten-detail.ts
@@ -57,9 +57,9 @@ interface Me {
office: string;
}
-type TabId = "verlauf" | "parteien" | "fristen" | "termine" | "dokumente" | "notizen" | "checklisten";
+type TabId = "verlauf" | "parteien" | "fristen" | "termine" | "notizen" | "checklisten";
-const VALID_TABS: TabId[] = ["verlauf", "parteien", "fristen", "termine", "dokumente", "notizen", "checklisten"];
+const VALID_TABS: TabId[] = ["verlauf", "parteien", "fristen", "termine", "notizen", "checklisten"];
interface ChecklistInstanceSummary {
id: string;
diff --git a/frontend/src/client/fristen-kalender.ts b/frontend/src/client/fristen-kalender.ts
index a91ef1f..753ae28 100644
--- a/frontend/src/client/fristen-kalender.ts
+++ b/frontend/src/client/fristen-kalender.ts
@@ -96,6 +96,15 @@ function render() {
grid.querySelectorAll(".frist-cal-cell-has").forEach((cell) => {
cell.addEventListener("click", () => openPopup(cell.dataset.iso!));
});
+
+ const monthStart = isoDate(viewYear, viewMonth, 1);
+ const monthEnd = isoDate(viewYear, viewMonth, daysInMonth);
+ const hasInMonth = allFristen.some((f) => {
+ const iso = f.due_date.slice(0, 10);
+ return iso >= monthStart && iso <= monthEnd;
+ });
+ const empty = document.getElementById("frist-cal-empty")!;
+ empty.style.display = hasInMonth ? "none" : "";
}
function openPopup(iso: string) {
diff --git a/frontend/src/client/i18n.ts b/frontend/src/client/i18n.ts
index e48a11a..3fe536d 100644
--- a/frontend/src/client/i18n.ts
+++ b/frontend/src/client/i18n.ts
@@ -33,7 +33,7 @@ const translations: Record> = {
"nav.soon.tooltip": "Bald verf\u00fcgbar",
// Footer
- "footer.text": "\u00a9 2026 Paliad \u2014 Nur f\u00fcr internen Gebrauch. Hogan Lovells Patent Practice.",
+ "footer.text": "\u00a9 2026 Paliad \u2014 Nur f\u00fcr internen Gebrauch.",
// Landing page
"index.title": "Paliad \u2014 Patentwissen f\u00fcr Hogan Lovells",
@@ -56,7 +56,13 @@ const translations: Record> = {
"index.style.title": "HL Patents Style",
"index.style.desc": "Word-Vorlage im HL Patents Style. Formatierung, Schriftarten und Makros f\u00fcr standardisierte Schrifts\u00e4tze.",
"index.offices": "Standorte",
- "index.munich": "M\u00fcnchen",
+ "index.office.munich": "M\u00fcnchen",
+ "index.office.duesseldorf": "D\u00fcsseldorf",
+ "index.office.hamburg": "Hamburg",
+ "index.office.amsterdam": "Amsterdam",
+ "index.office.london": "London",
+ "index.office.paris": "Paris",
+ "index.office.milan": "Mailand",
// Login
"login.title": "Anmelden \u2014 Paliad",
@@ -453,7 +459,6 @@ const translations: Record> = {
"akten.detail.tab.parteien": "Parteien",
"akten.detail.tab.fristen": "Fristen",
"akten.detail.tab.termine": "Termine",
- "akten.detail.tab.dokumente": "Dokumente",
"akten.detail.tab.notizen": "Notizen",
"akten.detail.tab.checklisten": "Checklisten",
"akten.detail.checklisten.empty": "F\u00fcr diese Akte sind noch keine Checklisten-Instanzen erfasst.",
@@ -462,10 +467,6 @@ const translations: Record> = {
"akten.detail.checklisten.col.progress": "Fortschritt",
"akten.detail.checklisten.col.created": "Angelegt",
"akten.detail.checklisten.hint": "Instanzen werden auf der Vorlagen-Seite unter \"Checklisten\" angelegt.",
- "akten.detail.soon": "Bald verf\u00fcgbar",
- "akten.detail.soon.fristen": "Fristenverwaltung kommt in Phase E \u2014 diese Akte wird dann Fristen anzeigen.",
- "akten.detail.soon.termine": "Termine & CalDAV-Sync folgen in Phase F.",
- "akten.detail.soon.dokumente": "Dokumenten-Upload folgt in Phase H.",
"akten.detail.verlauf.empty": "Noch keine Ereignisse aufgezeichnet.",
"akten.detail.parteien.add": "Partei hinzuf\u00fcgen",
"akten.detail.parteien.empty": "Noch keine Parteien eingetragen.",
@@ -573,6 +574,7 @@ const translations: Record> = {
"fristen.kalender.subtitle": "Monats\u00fcbersicht aller Fristen Ihrer Akten.",
"fristen.kalender.list": "Listenansicht",
"fristen.kalender.today": "Heute",
+ "fristen.kalender.empty": "Keine Fristen im ausgew\u00e4hlten Zeitraum.",
"cal.day.mon": "Mo",
"cal.day.tue": "Di",
"cal.day.wed": "Mi",
@@ -625,13 +627,13 @@ const translations: Record> = {
"dashboard.title": "Dashboard \u2014 Paliad",
"dashboard.greeting.prefix": "Guten Tag",
"dashboard.unavailable": "Dashboard ben\u00f6tigt die Datenbank \u2014 bitte Administrator kontaktieren.",
- "dashboard.onboarding": "Bitte schlie\u00dfen Sie das Onboarding ab, damit Ihnen Fristen und Mandate angezeigt werden k\u00f6nnen.",
+ "dashboard.onboarding": "Bitte schlie\u00dfen Sie das Onboarding ab, damit Ihnen Fristen und Akten angezeigt werden k\u00f6nnen.",
"dashboard.summary.heading": "Fristen auf einen Blick",
"dashboard.summary.overdue": "\u00dcberf\u00e4llig",
"dashboard.summary.this_week": "Diese Woche",
"dashboard.summary.upcoming": "Kommend",
"dashboard.summary.completed": "Abgeschlossen (7\u202fT.)",
- "dashboard.matters.heading": "Meine Mandate",
+ "dashboard.matters.heading": "Meine Akten",
"dashboard.matters.active": "Aktiv",
"dashboard.matters.archived": "Archiviert",
"dashboard.matters.total": "Gesamt",
@@ -724,6 +726,7 @@ const translations: Record> = {
"termine.kalender.heading": "Terminkalender",
"termine.kalender.subtitle": "Monats\u00fcbersicht aller Termine.",
"termine.kalender.list": "Listenansicht",
+ "termine.kalender.empty": "Keine Termine im ausgew\u00e4hlten Zeitraum.",
"akten.detail.tab.termine": "Termine",
"akten.detail.termine.add": "Termin hinzuf\u00fcgen",
"akten.detail.termine.empty": "F\u00fcr diese Akte sind noch keine Termine erfasst.",
@@ -806,7 +809,7 @@ const translations: Record> = {
"nav.soon.tooltip": "Coming soon",
// Footer
- "footer.text": "\u00a9 2026 Paliad \u2014 Internal use only. Hogan Lovells Patent Practice.",
+ "footer.text": "\u00a9 2026 Paliad \u2014 Internal use only.",
// Landing page
"index.title": "Paliad \u2014 Patent Knowledge for Hogan Lovells",
@@ -829,7 +832,13 @@ const translations: Record> = {
"index.style.title": "HL Patents Style",
"index.style.desc": "Word template in HL Patents style. Formatting, fonts, and macros for standardised briefs.",
"index.offices": "Offices",
- "index.munich": "Munich",
+ "index.office.munich": "Munich",
+ "index.office.duesseldorf": "D\u00fcsseldorf",
+ "index.office.hamburg": "Hamburg",
+ "index.office.amsterdam": "Amsterdam",
+ "index.office.london": "London",
+ "index.office.paris": "Paris",
+ "index.office.milan": "Milan",
// Login
"login.title": "Sign In \u2014 Paliad",
@@ -1226,7 +1235,6 @@ const translations: Record> = {
"akten.detail.tab.parteien": "Parties",
"akten.detail.tab.fristen": "Deadlines",
"akten.detail.tab.termine": "Appointments",
- "akten.detail.tab.dokumente": "Documents",
"akten.detail.tab.notizen": "Notes",
"akten.detail.tab.checklisten": "Checklists",
"akten.detail.checklisten.empty": "No checklist instances linked to this Akte yet.",
@@ -1235,10 +1243,6 @@ const translations: Record> = {
"akten.detail.checklisten.col.progress": "Progress",
"akten.detail.checklisten.col.created": "Created",
"akten.detail.checklisten.hint": "Instances are created on the template page under \"Checklists\".",
- "akten.detail.soon": "Coming soon",
- "akten.detail.soon.fristen": "Deadline management ships in Phase E \u2014 this matter will then list its deadlines here.",
- "akten.detail.soon.termine": "Appointments & CalDAV sync follow in Phase F.",
- "akten.detail.soon.dokumente": "Document upload lands in Phase H.",
"akten.detail.verlauf.empty": "No events recorded yet.",
"akten.detail.parteien.add": "Add party",
"akten.detail.parteien.empty": "No parties recorded yet.",
@@ -1346,6 +1350,7 @@ const translations: Record> = {
"fristen.kalender.subtitle": "Monthly view of all deadlines on your matters.",
"fristen.kalender.list": "List view",
"fristen.kalender.today": "Today",
+ "fristen.kalender.empty": "No deadlines in the selected period.",
"cal.day.mon": "Mon",
"cal.day.tue": "Tue",
"cal.day.wed": "Wed",
@@ -1497,6 +1502,7 @@ const translations: Record> = {
"termine.kalender.heading": "Appointment calendar",
"termine.kalender.subtitle": "Monthly overview of all appointments.",
"termine.kalender.list": "List view",
+ "termine.kalender.empty": "No appointments in the selected period.",
"akten.detail.tab.termine": "Appointments",
"akten.detail.termine.add": "Add appointment",
"akten.detail.termine.empty": "No appointments yet for this matter.",
diff --git a/frontend/src/client/termine-kalender.ts b/frontend/src/client/termine-kalender.ts
index 44ad1b6..a9bddd2 100644
--- a/frontend/src/client/termine-kalender.ts
+++ b/frontend/src/client/termine-kalender.ts
@@ -103,6 +103,15 @@ function render() {
grid.querySelectorAll(".frist-cal-cell-has").forEach((cell) => {
cell.addEventListener("click", () => openPopup(cell.dataset.iso!));
});
+
+ const monthStart = isoDate(viewYear, viewMonth, 1);
+ const monthEnd = isoDate(viewYear, viewMonth, daysInMonth);
+ const hasInMonth = allTermine.some((tt) => {
+ const iso = tt.start_at.slice(0, 10);
+ return iso >= monthStart && iso <= monthEnd;
+ });
+ const empty = document.getElementById("termin-cal-empty")!;
+ empty.style.display = hasInMonth ? "none" : "";
}
function openPopup(iso: string) {
diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx
index b1c8c96..ef2567e 100644
--- a/frontend/src/components/Footer.tsx
+++ b/frontend/src/components/Footer.tsx
@@ -4,7 +4,7 @@ export function Footer(): string {
return (
diff --git a/frontend/src/dashboard.tsx b/frontend/src/dashboard.tsx
index 43fda45..c49aebe 100644
--- a/frontend/src/dashboard.tsx
+++ b/frontend/src/dashboard.tsx
@@ -46,7 +46,7 @@ export function renderDashboard(): string {
- Bitte schließen Sie das Onboarding ab, damit Ihnen Fristen und Mandate angezeigt werden können.
+ Bitte schließen Sie das Onboarding ab, damit Ihnen Fristen und Akten angezeigt werden können.
@@ -79,7 +79,7 @@ export function renderDashboard(): string {
diff --git a/frontend/src/termine-kalender.tsx b/frontend/src/termine-kalender.tsx
index 183d26c..8f8f15f 100644
--- a/frontend/src/termine-kalender.tsx
+++ b/frontend/src/termine-kalender.tsx
@@ -69,6 +69,10 @@ export function renderTermineKalender(): string {
+
+ Keine Termine im ausgewählten Zeitraum.
+
+