Files
paliad/internal/db/migrations/072_projects_our_side.up.sql
m 188d8ec9ba feat(projects): add projects.our_side column + service plumbing (t-paliad-164 slice 1)
m's 2026-05-08 21:42 dogfood feedback on the Determinator perspective
chip: when an Akte is selected, the chip should be locked to the firm's
known side instead of asking the user to re-pick. paliad didn't track
that anywhere — paliad.parties.role records each party's role but no
flag for "this is the side we represent".

Migration 072 adds paliad.projects.our_side text with a CHECK
constraint (claimant | defendant | court | both | NULL). NULL stays the
default so existing rows are neutral and the Determinator falls back to
free-pick. Idempotent (ADD COLUMN IF NOT EXISTS + DO-block guarded
constraint) so a re-run against a partially-applied state is safe —
paliad has been bitten by collision twice this week.

Project model + ProjectService:
- OurSide *string field on models.Project
- CreateProjectInput / UpdateProjectInput accept our_side
- INSERT and partial UPDATE thread the value through; validateOurSide
  rejects unknown enum values with ErrInvalidInput before the DB
  constraint would; nullableOurSide turns "" into NULL so the form's
  "unset" sentinel can clear the column
- Update logs an our_side_changed audit event with "<from> → <to>"
  description (matching status_changed / project_type_changed
  shape); both ends use the literal "none" sentinel for NULL so the
  frontend renderer can map it to projects.field.our_side.none

i18n: event.title.our_side_changed (DE/EN), dashboard.action.short
verb form, projects.field.our_side.{label,hint,unset,claimant,
defendant,court,both,none} for the upcoming Slice 2 select.

Frontend translateEventDescription gets an our_side_changed branch
that runs translateArrowSlugs over the projects.field.our_side.*
prefix so the Verlauf tab renders localized labels.

Slice 2 wires the form, Slice 3 wires the Determinator.
2026-05-08 21:52:50 +02:00

43 lines
1.8 KiB
SQL

-- t-paliad-164 / m's 2026-05-08 21:42 dogfood feedback: when the user
-- selects an Akte in the Determinator (Slice 3c perspective chip),
-- the chip should already be locked to the firm's known side instead
-- of asking the user to re-pick something the project already knows.
--
-- Add a project-level our_side text column. NULL = unknown / not set
-- (default), so existing projects stay neutral and the Determinator
-- falls back to free-pick. The chip values mirror event_categories.
-- party so the Determinator can predefine the chip without mapping.
--
-- 'court' is allowed for completeness (paliad runs internal projects
-- where the firm represents the court / a tribunal-side stakeholder
-- — rare but real); the Determinator currently only acts on
-- claimant / defendant.
--
-- Idempotent so re-runs against a partially-applied state stay safe
-- (live tracker is at v71; paliad has been bitten by collisions
-- twice this week, see m/paliad#15 commits and dirac's mig 070).
ALTER TABLE paliad.projects
ADD COLUMN IF NOT EXISTS our_side text;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'projects_our_side_check'
AND conrelid = 'paliad.projects'::regclass
) THEN
ALTER TABLE paliad.projects
ADD CONSTRAINT projects_our_side_check
CHECK (our_side IS NULL
OR our_side IN ('claimant', 'defendant', 'court', 'both'));
END IF;
END $$;
COMMENT ON COLUMN paliad.projects.our_side IS
'Which side the firm represents on this project. Used by the '
'Fristenrechner Determinator (Slice 3c) to predefine the '
'perspective chip from the project context. Allowed: claimant, '
'defendant, court, both. NULL = unknown / not set; Determinator '
'falls back to free-pick.';