wip(projects): t-paliad-222 — backend + frontend changes (pre-merge checkpoint)

Backend: mig 110/111 (will be renumbered after merging main),
validators + helpers widened, BuildProjectCode helper + projection
populator wired into List/GetByID/ListAncestors/GetTree/CCR. All
internal Go tests pass.

Frontend: ProjectFormFields conditional render — opponent_code on
litigation, our_side renamed to Client Role on case with grouped
optgroups. i18n keys for both DE and EN. fristenrechner perspective
mapping widened. project-form.ts payload reader/writer + showFieldsForType
toggle for new litigation block.

Migration slots about to be bumped (mig 110 was claimed by euler's
project_type_other on main).
This commit is contained in:
mAi
2026-05-20 14:45:33 +02:00
parent cc23e9e537
commit 5dea0a703b
16 changed files with 1192 additions and 70 deletions

View File

@@ -159,10 +159,35 @@ type Project struct {
// OurSide is which side the firm represents on this project. Used
// by the Fristenrechner Determinator to predefine the perspective
// chip from the project context (t-paliad-164). NULL = unknown /
// not set; Determinator falls back to free-pick. Allowed values:
// claimant, defendant, court, both.
// not set; Determinator falls back to free-pick.
//
// Allowed sub-roles (mig 110, t-paliad-222):
// Active : claimant, applicant, appellant
// Reactive : defendant, respondent
// Other : third_party, other
//
// The DB column name stays as `our_side`; the UI label has moved
// to "Client Role" / "Mandantenrolle" on case projects and is
// hidden on every other project type.
OurSide *string `db:"our_side" json:"our_side,omitempty"`
// OpponentCode is the short slug for the opposing party on a
// litigation project (uppercase letters / digits / dashes, max 16
// chars). Used as the middle segment when services.BuildProjectCode
// assembles an auto-derived project code from the ancestor tree —
// e.g. EXMPL.OPNT.567.INF.CFI (t-paliad-222 / m/paliad#50). NULL
// → segment skipped silently. Only meaningful on type='litigation'
// rows; CHECK constraint (mig 111) enforces the pairing.
OpponentCode *string `db:"opponent_code" json:"opponent_code,omitempty"`
// Code is the auto-derived (or override) project code, computed at
// projection time by services.BuildProjectCode. Not a DB column —
// no `db:` tag — populated by service-layer projection helpers
// after the row is loaded. Empty on rows for which the helper has
// not run (e.g. raw fixtures in tests, internal projection paths
// that don't call the helper).
Code string `db:"-" json:"code,omitempty"`
// CounterclaimOf is the parent project this row is a counterclaim
// (CCR) against (t-paliad-174 SmartTimeline Slice 3). NULL on
// regular projects; non-NULL rows are CCR sub-projects rendered as