7b66c4d035e51e209dcb883e77c01900301f06a6
15 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d41fc49809 |
feat(t-paliad-139): Phase 1 — /projects/{id} aggregation bug fix
m's bug: /projects/{client_id} renders "Keine Fristen" / "Keine Termine" /
"Noch keine Ereignisse" even when descendant Cases carry deadlines, appts,
and audit events. Live verification on Siemens AG client
(61e3fb9e-29fb-44aa-867e-a89469e2cacb): 9 descendant projects, 19
deadlines, 37 project_events, 4 appointments — none on the Client row,
all invisible until now.
Root cause: 3 legacy per-project read paths used WHERE project_id = $1
(exact match), bypassing the projectDescendantPredicate primitive that
internal/services/visibility.go:68 already provides and that the t-124
union endpoints (DeadlineService.ListVisibleForUser etc.) already use.
Backend
-------
- DeadlineService.ListForProject(..., directOnly bool): subtree by
default via WHERE project_id IN (SELECT pp.id FROM paliad.projects pp
WHERE $1 = ANY(string_to_array(pp.path, '.')::uuid[])); collapses to
WHERE project_id = $1 when directOnly=true.
- AppointmentService.ListForProject: same shape.
- ProjectService.ListEvents(..., directOnly bool): same shape, plus
LEFT JOIN paliad.projects to surface project_title for the Verlauf
attribution chip on /projects/{id}. Inner subquery aliased pp to
avoid shadowing the outer join's p.
- models.ProjectEvent: new optional ProjectTitle string for the Verlauf
enrichment. Other readers leave it nil and the JSON serialiser omits
it (json:"project_title,omitempty").
- handlers/{deadlines,appointments,projects}.go: handler reads
?direct_only=true|false and passes through to the service. New
handlers.parseDirectOnly helper centralises the parse.
- project_filter_descendants_test.go: extended to also pin
DeadlineService.ListForProject + AppointmentService.ListForProject
+ ProjectService.ListEvents (live-DB test, skipped without
TEST_DATABASE_URL).
Frontend
--------
- projects-detail.ts: switched the deadline + appointment fetches from
/api/projects/{id}/deadlines + /appointments (legacy narrow) to
/api/events?type=deadline|appointment&project_id={id} (the union
endpoints, already aggregating + enriching with project_title). The
Verlauf still uses /api/projects/{id}/events but with the new
direct_only flag wiring.
- New subtreeMode state machine + URL param ?subtree=false. Default =
subtree (true). persistSubtreeMode replaceState keeps back-button
friendly.
- 3 new .subtree-toggle buttons in /projects/{id} History, Deadlines,
Appointments sections. Shared state across the three; clicking any
toggle reloads all three sections at once.
- attributionChip(rowProjectID, rowProjectTitle): inline chip "auf:
Case 14-vs-Müller" rendered when row.project_id !== currentProjectID.
Suppressed for direct rows.
- Deadline / Appointment / ProjectEvent interfaces gained an optional
project_title for the chip data path.
- 3 new i18n keys: aggregation.toggle.subtree (Inkl. Unterprojekte /
Incl. sub-projects), aggregation.toggle.direct_only (Nur direkt /
Direct only), aggregation.attribution.on (auf / on). DE+EN.
- global.css: .subtree-toggle, .subtree-toggle--active,
.aggregation-chip — small additive styling.
No schema. No migration. Phases 2 + 3 stack on top per design §7.
|
||
|
|
4d7c74994a |
feat(t-paliad-125): sort project pickers by tree path with depth indent
The /events Project filter dropdown was sorted by `updated_at DESC`, so a recently-touched Case appeared above its parent Client and cousins interleaved unrelated branches — m's report (2026-05-04): "Siemens cases come directly after 'mandant vs Gegner' and are not under 'Siemens-AG'". Backend: switch ProjectService.List to ORDER BY p.path so every descendant immediately follows its ancestor — the same ordering BuildTree produces. Both callers (handleListProjects, searchProjects) gain a stable, hierarchical default that matches user expectation. Frontend: add project-indent.ts shared helper and apply NBSP indent prefix in every <select> picker fed by /api/projects: events filter, /deadlines/new, /appointments/new, checklist new-instance modal, Fristenrechner save modal. NBSP avoids browser whitespace collapse inside <option> labels. Multi-parent repetition is out of scope (data model has singular parent_id today). Tests: project_list_order_test pins the path-order contract against a seeded mixed-recency tree. |
||
|
|
df321acb63 |
feat(t-paliad-097): clickable checklist references + Vorhandene Instanzen tab
Two related checklist UX gaps:
1. Checklist events in a project's Verlauf tab were unclickable — and
nothing in the project_events row carried the originating instance ID.
Add an `insertProjectEventWithMeta` helper, write
{"checklist_instance_id": <uuid>} as project_events.metadata for
checklist_created / _renamed / _linked / _unlinked / _reset (skipped
for _deleted — instance is gone). Surface metadata on
/api/projects/{id}/events and on dashboard recent_activity. The
Verlauf renderer wraps the title in <a href="/checklists/instances/{id}">
when metadata.checklist_instance_id is present, and the dashboard's
activity feed deep-links the project ref to the instance directly for
checklist_* events. Existing rows (metadata `{}`) stay non-clickable —
no migration backfill needed.
2. /checklists previously demanded a template pick before any existing
instance was reachable. Add a tab nav (Vorlagen / Vorhandene Instanzen)
using the existing entity-tab pattern. New endpoint
GET /api/checklist-instances and ChecklistInstanceService.ListAllVisible
return every visible instance across templates + projects, joined with
project ref/title and sorted by created_at DESC. Rows show template,
instance name (linked), project link (or "Persönlich"), progress bar,
and created date. URL state (?tab=instances) keeps the active tab
shareable. EN + DE i18n covered for tab labels and column headers.
Also adds event.title.checklist_* localizations for the Verlauf header
that translateEvent looks up.
|
||
|
|
460736ad1e |
refactor(t-paliad-092): rename Go module path patholo → paliad
F-6 from t-paliad-074 architecture audit. The Gitea repo was renamed m/patholo → mAi/paliad → m/paliad, but go.mod still declared `mgit.msbls.de/m/patholo` and every internal import echoed the pre-rebrand name. Sweep: - go.mod: module path → mgit.msbls.de/m/paliad - All *.go files: imports rewritten via sed - README.md, docs/design-kanzlai-integration.md: mAi/paliad → m/paliad - Frontend issue-reference comments (mAi/paliad#N → m/paliad#N) in i18n.ts, theme.ts, sidebar.ts, app.ts, Sidebar.tsx, PWAHead.tsx, global.css Verified: go build/vet/test ./... clean, bun run build clean, no remaining mgit.msbls.de/m/patholo or mAi/paliad references outside docs that intentionally describe the rename history. |
||
|
|
909167b036 |
refactor(t-paliad-091): NoteService consolidation — push CanSee to parent services
F-3 from t-paliad-074 architecture audit. NoteService used to call ProjectService.GetByID and AppointmentService.GetByID just for the visibility bit (~6 cross-service full-row reads in note_service.go). Each was a full SELECT on the parent row when only a boolean was needed. Add CanSee(ctx, userID, id) (bool, error) on the two parent services: single EXISTS round-trip, no projection. Personal Appointments stay visible only to their creator; project-anchored Appointments inherit the project's visibility predicate (global_admin shortcut + team-walk). NoteService gains two private helpers — requireProjectVisible and requireAppointmentVisible — that wrap CanSee + ErrNotVisible. All visibility-only sites in note_service.go (ListForProject / ListForDeadline / ListForAppointment / ListForProjectEvent / CreateForProject / CreateForDeadline / requireVisible) now go through the helpers. CreateForAppointment keeps appointment.GetByID — it legitimately needs the appointment's project_id for the audit-event row. DeadlineService.CanSee was not added: note_service never reaches into the deadline service for visibility (it does its own SELECT project_id FROM paliad.deadlines and gates via the project predicate). Test: cansee_test.go covers the gate level for both new methods — admin sees everything (global_admin shortcut), team member sees their team's, non-member sees nothing, missing IDs are invisible to all, personal appointments are private to creator. |
||
|
|
ce3227c1c0 |
refactor(t-paliad-080): service-layer naming sweep — Notiz/Termin/Frist/Projekt/Partei → Note/Appointment/Deadline/Project/Party
Mechanical rename across 8 service files plus their handler call sites and two related helpers. The English types existed already; what changed are the input-struct names, helper functions, list/create method suffixes, and parameter names so they no longer mix English types with German parameter names. Renames cover: - CreateNotizInput/UpdateNotizInput → CreateNoteInput/UpdateNoteInput, notizColumns/notizSelect → noteColumns/noteSelect, ListForProjekt/Frist/ Termin → ListForProject/Deadline/Appointment, CreateForProjekt/Frist/ Termin → CreateForProject/Deadline/Appointment, fristProjectID → deadlineProjectID - CreateTerminInput/UpdateTerminInput → CreateAppointmentInput/ UpdateAppointmentInput, terminColumns → appointmentColumns, ListForProjekt → ListForProject; parameter renames terminID → appointmentID, projektID → projectID - CreateFristInput/UpdateFristInput → CreateDeadlineInput/ UpdateDeadlineInput, fristColumns → deadlineColumns, ListForProjekt → ListForProject, isValidFristStatus → isValidDeadlineStatus; parameter renames fristID → deadlineID, projektID → projectID - CreateProjektInput/UpdateProjektInput → CreateProjectInput/ UpdateProjectInput, projektColumns → projectColumns, validateProjektStatus → validateProjectStatus, ProjektRole comment → ProjectRole - CreateParteiInput → CreatePartyInput, parteiColumns → partyColumns, ListForProjekt → ListForProject; parameter renames parteiID → partyID - OnTerminCreated/Updated/Deleted → OnAppointmentCreated/Updated/Deleted on the AppointmentCalDAVPusher interface and its CalDAVService impl - formatTermin → formatAppointment in caldav_ical - ListForProjekt → ListForProject, listWithProjekt → listWithProject, checklistInstanceWithProjektSelect → checklistInstanceWithProjectSelect, ClearProjekt → ClearProject (JSON tag clear_projekt unchanged — wire format) - insertProjectEvent helper parameter projektID → projectID, error message "insert projekt_event" → "insert project_event" - TeamService AddMember/RemoveMember/ListDirectMembers/ListEffectiveMembers parameter projektID → projectID; matching handler renames - Frontend doc-comments referencing CreateProjektInput/UpdateProjektInput updated to CreateProjectInput/UpdateProjectInput JSON wire tags (clear_projekt, etc.) and German user-facing strings (glossary entries, search.go labels, email templates, changelog, Terminsgebuehr, Fristenrechner product name) are intentionally untouched. API contract unchanged. go build/vet/test ./... clean. Frontend bun build clean. |
||
|
|
f583c650a2 |
fix(t-paliad-067): PR-1 i18n leak sweep + activity narrative (F-04, F-07, F-10, F-12, F-21, F-29, F-35, F-46)
Per docs/audit-polish-2-2026-04-29.md PR-1. Single concern: text rendered
to a German narrative that was still English or raw-keyed.
- F-04 deadlines-new.ts now references the existing fristen.field.akte.*
keys (the SSR template already used them) instead of the non-existent
fristen.field.project.* keys, so the picker no longer renders the raw
i18n key.
- F-07 + F-21 dashboard activity log + project Verlauf:
• i18n.ts gains the missing dashboard.action.short.project_type_changed
plus a parallel event.title.* key set (full noun-phrase form for
Verlauf, complementing the dashboard's verb form) and
event.description.* templates with {title}/{count}/{parent}
placeholders.
• New translateEvent(eventType, title, description) helper localizes a
stored project_events row for display; parses both new value-only
descriptions and legacy English+DE-mix shapes ("Deadline „Foo"
geändert", "Type case → litigation", "Note zu deadline hinzugefügt").
Wired into dashboard.ts and projects-detail.ts renderers.
• Go services now write descriptions as value-only payloads (the title,
the count, the parent slug, or "old → new") so future rows are
locale-clean. Affected services: deadline_service.go (5 sites),
appointment_service.go (3 sites), note_service.go (1 site),
project_service.go (2 sites: status_changed, project_type_changed).
• Translation covers historical project_events rows too — the
legacy-format parsers in translateEventDescription strip the English
"Type"/"Status" prefix and pull the quoted title out of "Deadline
„Foo" geändert" so DE/EN renders correctly without DB migration.
• Renamed dashboard.action.short.project_* DE labels from "...Akte" to
"...Projekt" to match the project-rename direction.
- F-10 deadlines list REGEL column now resolves rule_name/rule_name_en
via a JOIN-side alias on deadline_service.ListWithProjects (added
RuleName/RuleNameEN to DeadlineWithProject). New ruleDisplay() helper
prefers the localized rule name and falls back to em-dash; never
renders the raw rule_code slug ("inf.rejoin").
- F-12 fristen.col.akte and termine.col.akte DE values flip "Akte" →
"Projekt"; matching SSR placeholder text on deadlines.tsx and
appointments.tsx column headers (EN already said "Matter").
- F-29 the checklists empty-state hint on /projects/{id}/checklists is
split into prefix/link/suffix spans so the <a href="/checklists"> stays
intact after applyTranslations() runs (the previous single-string i18n
value collapsed the anchor on first paint).
- F-35 projekte.subtitle DE flips "Fälle" → "Verfahren" (matches the
actual type taxonomy: Mandant/Streitsache/Patent/Verfahren/Projekt).
Same fix on projekte.empty.hint. EN keeps "cases" since EN labels the
case type as "case".
- F-46 dashboard.greeting.prefix EN flips "Good day" → "Hello".
Verified
- go build ./... + go vet ./... + go test ./... all green.
- bun run build clean.
- Dashboard activity widget + project Verlauf renderer verified by
reading the translated paths; live smoke pending deploy.
|
||
|
|
abd99980fc |
fix(t-paliad-058): honor global_admin in visibilityPredicate
Mirror paliad.can_see_project's global-admin shortcut at the application
layer. The in-Go predicate previously relied on callers passing
user.GlobalRole as a separate :role / $roleArg parameter — the positional
variant compared against the literal 'admin' instead of 'global_admin',
so any global_admin without team membership got 404 from
/api/projects/{id} (and the other positional callsites: ListAncestors,
BuildTree, GetTree, deadline counts).
Fold the gate into a Go helper that resolves global_admin via EXISTS on
paliad.users, keyed only by userID. Callers no longer pass role, which
removes the foot-gun entirely. Drops the unused
visibilityPredicatePlaceholder dead helper.
Adds a regression test (visibility_test.go) covering global_admin +
standard user against GetByID and BuildTree without project_teams rows.
|
||
|
|
d5d1cffd3a |
feat(t-paliad-056): allow type change in project edit modal with data-loss warning
Enables the type dropdown in /projects/{id} edit modal. Switching to a
new type clears the old type's specific columns server-side and emits a
project_type_changed audit event. The frontend surfaces an inline
warning naming the fields that will be NULL'd before the user saves.
Field map (kept in sync with services.typeSpecificColumns):
client → industry, country, client_number
patent → patent_number, filing_date, grant_date
case → court, case_number, proceeding_type_id
litigation/project → none
Server: PATCH /api/projects/{id} now accepts `type`. ProjectService.Update
collects the obsolete columns up-front and force-NULLs them at the end of
the SET list; per-field appendSet calls for those columns are skipped so
Postgres' "no duplicate column in UPDATE" rule isn't tripped (and the
clear wins regardless of what the client sent). Audit event description
records old → new type slug.
Frontend: openEditModal no longer disables projekt-type. A new
renderTypeChangeWarning() computes the lost-fields list from the loaded
project record and shows it above Save when the selection diverges from
the current type. Empty when nothing would be cleared.
No DB hierarchy CHECK constraint exists on parent/child types, so type
changes don't risk schema violations on existing children. Tree
inheritance rules are not enforced on edit (matching create behaviour).
|
||
|
|
b34500ad31 |
feat(t-paliad-051): split paliad.users.role into job_title + global_role
Conflation: paliad.users.role was simultaneously job title (display only)
and global permission ('role=admin' checks across Go/SQL/JS). m wanted
to set his real job title ('Counsel Knowledge Lawyer') without losing
admin access — the t-paliad-050 admin-team UI even rejected role='admin'
on edit, so any UI-driven update silently demoted m.
Per m's three-axis principle ("firm roles are not project roles are not
tool roles"), this lands TWO orthogonal columns:
* paliad.users.job_title — free text, NULL allowed, display only.
NEVER gates anything in code or SQL.
* paliad.users.global_role — CHECK ('standard'|'global_admin'),
default 'standard'. The only thing that gates ops.
Migration 023:
* Drops NOT NULL + 'associate' default off the legacy role column
* Promotes role='admin' rows to global_role='global_admin'; clears
their role text; sets m's job_title='Counsel Knowledge Lawyer'
* Renames role -> job_title with CHECK (job_title IS NULL OR <> '')
* Replaces can_see_project body with global_role='global_admin'
* CASCADE-rebuilds every RLS policy under canonical English names —
with the historic u.role IN ('partner','admin') gates simplified
to u.global_role='global_admin' only (job_title NEVER gates)
Code surface:
* internal/models/models.go: User.Role -> User.JobTitle (*string) +
User.GlobalRole (string)
* internal/services/user_service.go: bootstrap (first row promoted to
global_admin via pg_advisory_xact_lock(7346298141), unchanged constant);
UpdateProfile drops role, accepts job_title only; AdminUpdateUser adds
global_role with last-admin demotion guard (ErrLastGlobalAdmin);
IsAdmin reads global_role
* Other services (dashboard/agenda/appointment/project/deadline/
department/party/note/checklist_instance): pass user.GlobalRole into
visibility predicates; partner-or-admin gates simplified to
global_admin only
* Handlers: drop now-impossible ErrAdminBootstrapOnly cases;
admin_users handles ErrLastGlobalAdmin -> 409
* department_service: SQL u.role -> u.job_title, DepartmentMember.Role
-> JobTitle (*string)
Frontend:
* /api/me + Me interfaces ship {job_title, global_role}
* Onboarding form: 'Berufsbezeichnung / Job title' (job_title)
* Settings + admin-team forms: same renames + i18n updates
* Admin-team: new 'Berechtigung / Permission' column with
'Standard'|'Global Admin' badge + dropdown editor; last-admin
demotion guard at the UI layer
* Sidebar admin-section reveal: me.global_role==='global_admin'
* deadlines/deadlines-detail/projects-detail/notes: partner-as-permission
gates dropped, only global_admin grants those operations
Tests:
* user_service_test: bootstrap promotes first user to global_admin,
subsequent default to standard; AdminUpdateUser refuses to demote
the last global_admin; IsAdmin reads global_role
Migration applied to ydb 2026-04-27. Live state verified:
* m: job_title='Counsel Knowledge Lawyer', global_role='global_admin'
* tester: job_title=NULL, global_role='global_admin'
* 29 stub colleagues: job_title='associate', global_role='standard'
|
||
|
|
70c3f08668 |
fix(projects-detail, services): empty-list endpoints returned JSON null → tab content blank
m reported /projects/{id} loaded the chrome and tabs but every panel was
empty even with deadlines/appointments/team rows that should render.
Console error: "Cannot read properties of null (reading 'length')" at
projects-detail.js — the Project Detail page expects every list endpoint
to return [] but at least two were returning literal JSON null.
Reproduced via the in-page fetch console:
/api/projects/{id}/parties → 200, body: "null"
/api/projects/{id}/children → 200, body: "null"
/api/projects/{id}/deadlines → 200, body: "[…]" (had data, fine)
/api/projects/{id}/team → 200, body: "[…]" (had data, fine)
Root cause: every list service in internal/services declared its result
as `var rows []models.X` and returned that to the handler, which
encoding/json marshals as `null` when the SELECT returns zero rows
(nil slice, not empty slice). Most endpoints happen to have data so
the bug stayed dormant until t-paliad-038 hit /projects/{id} where
parties + children are commonly empty.
Fix at the source — every list service that JSON-marshals to a client
now initialises `rows := []models.X{}` so the encoder produces `[]`:
party_service ListForProjekt
project_service List, ListAncestors, BuildTree, GetTree
(ListChildren goes through List)
deadline_service List + ListForProjekt
appointment_service List + ListForProjekt
note_service ListForProjekt
checklist_instance_service ListForProjekt
team_service List
department_service List + ListMembers + ListWithMembers
caldav_service was deliberately left alone — its lists are admin-only
debug surfaces, not user-facing tab fillers, and changing them would
mix scopes.
Belt-and-braces on the client too — projects-detail.ts now coerces every
`await resp.json()` for an array endpoint with `?? []` so a future
service regression can't crash the page.
Verified: go build/vet/test clean, bun run build clean.
|
||
|
|
3111c7440a |
fix(polish): i18n leaks, untranslated labels, /api/departments 500, 404 chrome (t-paliad-037)
Four bugs from tests/smoke-auth-2026-04-25.md.
Bug 4 — Dashboard activity log leaked raw i18n keys. Root cause was a mix
of three issues:
- Go services wrote German event_types (frist_created, termin_*,
projekt_*, notiz_created, checkliste_*) — no matching i18n key.
- i18n.ts only had keys for legacy `akte_*` types, none for what was
actually being written.
- The dashboard renderer always rendered `e.title` (a static label like
"Project angelegt") as a trailing detail, duplicating the action verb.
Old `akte_created` rows had English titles ("Akte created") that
bled into German output.
Switched all event_type writes to English (deadline_*, appointment_*,
project_*, note_created, checklist_*, deadlines_imported). Moved dynamic
text out of `title` into `description` for status_changed and
deadlines_imported so the static label/description split is consistent.
Added i18n keys for both new English types AND legacy German types so
historical project_events rows render cleanly. Dashboard now prefers
description over title; falls back to title only for events with no
i18n match (defensive for any unknown legacy kinds).
Bug 5 — /deadlines and /appointments matter-filter dropdowns showed raw
keys `fristen.filter.project.all` / `termine.filter.project.all`. The
client TS referenced English-prefix keys that didn't exist; the existing
keys use `fristen.filter.akte.*` / `termine.filter.akte.*`. Updated the
client refs to match the existing keys (kept i18n key namespace stable
to avoid touching every other reference).
Bug 6 — /api/departments?include=members returned 500. Reproduced via
curl: ListWithMembers (and ListMembers) used `LEFT JOIN paliad.users` on
a member.user_id that FKs auth.users — pre-onboarding members produced
NULL u.email/display_name/office/role, which sqlx can't scan into the
non-pointer string fields. Switched both to INNER JOIN; unonboarded
members are skipped (correct UX — without a profile there's nothing to
render anyway).
Bug 9 — Bare `404 page not found` on unknown auth-gated paths
(/whatsnew, /search, /settings/notifications, etc). Added a chromed 404
page (frontend/src/notfound.tsx) with sidebar + friendly card + "back
to dashboard" CTA, plus a catch-all handler on the protected mux that
serves it with HTTP 404 (and JSON 404 for /api/* misses). Anonymous
visitors keep being redirected to /login by the auth middleware before
the catch-all runs, so no separate marketing-shell variant needed.
Verification:
- go build ./... + go vet ./... + go test ./... clean
- bun run build clean (notfound.html + notfound.js produced)
- Visual checks pending after deploy
|
||
|
|
1f9c4d0296 |
fix(services): use CAST(...AS uuid[]) in visibilityPredicate (sqlx ::uuid[] bug)
Bug 1 in tests/smoke-auth-2026-04-25.md (/api/projects, /api/deadlines, /api/appointments returning HTTP 500) had a second root cause beyond the RLS function bodies fixed in 021: sqlx v1.4.0's named-parameter parser strips one colon from `::uuid[]` while compiling `:user_id` / `:role` placeholders, producing invalid SQL `:uuid[]` that Postgres rejects with `syntax error at or near ":"`. The bug was masked by the earlier `relation "paliad.projekte" does not exist` error. Replacing `::uuid[]` with the equivalent SQL-standard `CAST(... AS uuid[])` sidesteps the parser issue without changing semantics. Verified with a small repro: `sqlx.Named` no longer corrupts the cast. Only `visibilityPredicate` (the named-bind variant) is affected — the positional and `?`-placeholder variants don't go through `sqlx.Named`. |
||
|
|
aafbfbbf12 |
feat(projects): interactive tree view of project hierarchy (t-paliad-028)
- Backend: GET /api/projects/tree returns the full visible project tree as nested JSON with embedded children, open/overdue deadline counts per node — visibility-scoped via the existing predicate, single round-trip. - Frontend: new project-tree.ts module renders a collapsible, indented tree with type icons (client/litigation/patent/case/project), status badges, deadline-count chips and chevron toggles. Top two levels expand by default; deeper nodes start collapsed. Expansion state persists in sessionStorage so toggling list/tree keeps user choices. - Wired to /projects via the existing Ansicht select (Liste/Baum/Wurzeln); dedicated tree container coexists with the flat-list table. - New i18n keys (de/en) + tree styles in global.css (lime accent on hover). |
||
|
|
3faec6c526 |
refactor(rename): German→English for backend (tables, types, services, handler files)
t-paliad-025 — Phase 1: backend rename.
Migrations 018+019 rewritten from scratch with English table/column
names throughout. Since v2 schema (018/019) has never been applied to
youpc prod DB, this is a clean replacement — not an ALTER RENAME chain.
Pre-existing German tables (parteien, fristen, termine, dokumente,
akten_events, notizen) are renamed inline in 018 via ALTER TABLE … RENAME
TO alongside the akte_id → project_id column rewrite.
Renames applied:
projekte → projects
projekt_teams → project_teams
projekt_events → project_events (via akten_events → project_events)
fristen → deadlines
termine → appointments
parteien → parties
notizen → notes
dezernate → departments
dezernat_mitglieder → department_members
dokumente → documents
can_see_projekt → can_see_project
notiz_is_visible → note_is_visible
akte_id / frist_id / termin_id / akten_event_id → project_id /
deadline_id / appointment_id / project_event_id
termin_type → appointment_type
Go types + services renamed:
Projekt / ProjektService / ProjektEvent / ProjektTeamMember
Frist / FristService / FristWithProjekt
Termin / TerminService / TerminWithProjekt / TerminType
Notiz / NotizService / ChecklistInstanceWithProjekt
Dezernat / DezernatService / DezernatMitglied
Partei / Parteien / ParteienService
Files renamed (git mv):
internal/services/{projekt,frist,termin,notiz,dezernat,parteien}_service.go
→ {project,deadline,appointment,note,department,party}_service.go
internal/handlers/{projekte,fristen,fristen_pages,termine,termine_pages,
notizen,dezernate,akten_pages,gerichte,glossar,checklisten}.go
→ {projects,deadlines,deadlines_pages,appointments,appointments_pages,
notes,departments,projects_pages,courts,glossary,checklists}.go
internal/checklisten/ → internal/checklists/
internal/db/migrations/018_projekte_v2.* → 018_projects_v2.*
internal/db/migrations/019_seed_dezernate_from_user_text.*
→ 019_seed_departments_from_user_text.*
User-facing i18n strings (DE/EN labels) stay untouched. Product names
Fristenrechner / Kostenrechner / Gebührentabellen stay German.
Build + vet + tests clean.
|