Commit Graph

4 Commits

Author SHA1 Message Date
mAi
cc13a5b857 chore(admin): remove /admin/rules/export page + export-migrations API (t-paliad-297)
Some checks failed
Paliad CI gate / build (push) Has been cancelled
Paliad CI gate / test-go (push) Has been cancelled
Paliad CI gate / deploy (push) Has been cancelled
Workflow shifted to hand-written numbered migrations; the audit-row SQL
export tool no longer has any consumers. Pure deletion — /admin/rules
and /admin/rules/{id}/edit stay; only the export-to-SQL flow goes.

Deleted:
- frontend/src/admin-rules-export.tsx
- frontend/src/client/admin-rules-export.ts

Removed:
- routes GET /admin/rules/export and GET /admin/api/rules/export-migrations
- handleAdminExportRuleMigrations + handleAdminRulesExportPage
- RuleEditorService.ExportMigrationsSince + ExportResult + sqlEscape helper
- build.ts entries (import, client bundle, dist HTML write)
- Sidebar "Regel-Migrations" nav item + "Migrations exportieren" button on /admin/rules
- all admin.rules.export.* + nav.admin.rules_export + admin.rules.list.export i18n keys (DE+EN)
- .admin-rules-export-* CSS rules (dead after page deletion)

Doc references in design-fristen-phase2-2026-05-15.md and
design-paliad-data-export-2026-05-19.md updated to mark the endpoint as
removed (acceptance #2 requires grep to return zero hits).
2026-05-26 11:50:14 +02:00
mAi
bc5b3557d0 feat(t-paliad-209): rename DeadlineRule.Code → SubmissionCode across Go layer
Workstream B Go sweep — matches mig 098. Every place the deadline-rules
service reads/writes the per-rule identifier now uses the new column
name and the new struct field. Distinct from rule_code (legal citation)
and from proceeding_types.code (the proceeding's 3-segment code).

Touch points:
- models.DeadlineRule.Code → SubmissionCode (db + json tags renamed
  in lockstep — JSON contract `submission_code` is the new shape).
- deadline_rule_service: ruleColumns SELECT list updated.
- rule_editor_service: CreateRuleInput.Code → SubmissionCode (json tag
  too), INSERT + CloneAsDraft SELECT updated.
- projection_service: lookupRuleByCode → lookupRuleBySubmissionCode
  (SQL WHERE clause + error message); every r.Code / parent.Code /
  rule.Code / first.Code / src.rule.Code read renamed.
- fristenrechner: r.Code / prev.Code / rule.Code reads renamed in
  Calculate (parent-anchor + override-key + computed-by-code map) and
  in CalculateRule's LocalCode emission; the proceeding-code+submission-
  code resolver query uses `submission_code = $2`.
- event_trigger_service / deadline_calculator: r.Code reads renamed.

UIDeadline.Code (the calculator's wire response) is unchanged — that
field is a separate API contract pointing at the same value; renaming
it would force every frontend deadline-renderer through a contract
break that isn't part of this workstream.

Test fixtures updated to the new SubmissionCode field name; live-DB
tests updated to the post-mig-098 prefixed values (`inf.sod` →
`upc.inf.cfi.sod` etc.). New submission_codes_shape_test asserts
every active+published row matches the 4+-segment proceeding-prefixed
shape (sibling of TestProceedingCodeShape; mirrors mig 098 §6.1).

go build ./... clean. go test ./internal/... green.
2026-05-18 15:06:04 +02:00
mAi
99a72a744f refactor(t-paliad-195): drop legacy fields from Go service surface
Phase 3 Slice 9 Go cleanup. With mig 091's column drops live, the
service layer stops reading + emitting the legacy shape:

  - models.DeadlineRule: drop IsMandatory, IsOptional, ConditionFlag,
    ConditionRuleID fields. Comment block flags Slice 9 as the
    closeout slice.
  - DeadlineRuleService.ruleColumns: SELECT no longer enumerates the
    dropped columns. The post-Slice-9 schema is the live shape.
  - FristenrechnerService.UIDeadline: drops IsMandatory + IsOptional
    fields. Frontend reads `priority` directly post-Slice-8; the
    legacy emit was kept "for one release" and that release is now.
  - evalConditionExpr signature: drops the conditionFlag fallback
    param. NULL / "null" expressions return true (unconditional);
    the legacy text[] fallback was the only reason for the second
    param. New helpers hasConditionExpr + extractFlagsFromExpr fill
    the gaps (alt-swap guard + RuleCalculation.FlagsRequired list).
  - FristenrechnerService.Calculate + calculateByTriggerEvent +
    EventTriggerService.Trigger: switched to the new (single-arg)
    evalConditionExpr; alt-swap guard now uses
    hasConditionExpr(r.ConditionExpr) instead of the dropped
    len(r.ConditionFlag) > 0 check.
  - FristenrechnerService.CalculateRule: RuleCalculationRule.IsMandatory
    derived from priority via wireFlagsFromPriority (kept for the
    result-card panel TS contract). FlagsRequired walks the jsonb
    gate tree to enumerate {"flag":"X"} leaves (replaces the
    dropped condition_flag enumeration).
  - RuleEditorService.Create + CloneAsDraft INSERT statements:
    dropped is_mandatory / is_optional / condition_flag from the
    column lists. Live shape only.

Test fixtures (projection_service_test.go, rule_editor_service_test.go,
fristenrechner_test.go) all updated to write the live shape on
seed; the evalConditionExpr table-driven test dropped its legacy
fallback cases (the fallback no longer exists) and now exercises
20 pure-jsonb scenarios across AND/OR/NOT compositions.

The deadline_rule_service_test backfill assertion lost its
(is_mandatory, is_optional) bucket cross-check (those columns are
gone); the priority-non-NULL invariant still holds via the CHECK
constraint. condition_flag cross-check now joins the pre-mig-091
snapshot table (when present) instead of the live row.
2026-05-15 17:53:31 +02:00
mAi
b21ce6dd7b feat(t-paliad-191): RuleEditorService — admin rule lifecycle
Phase 3 Slice 11a (m's Q5 option C: "I need to see these things,
admin only"). RuleEditorService owns the admin-only lifecycle for
paliad.deadline_rules:

  Create        → INSERT row with lifecycle_state='draft', published_at=NULL.
  UpdateDraft   → UPDATE WHERE id=$1 AND lifecycle_state='draft'.
                   Published or archived rows must clone-as-draft first
                   (ErrInvalidLifecycleState otherwise — 409).
  CloneAsDraft  → INSERT deep copy of source row (published OR archived)
                   as a new draft with draft_of pointing at the source.
                   Lets editors propose changes to live rules without
                   mutating the live row.
  Publish       → UPDATE lifecycle_state='published', set published_at.
                   When draft_of != NULL, also archives the cloned-from
                   peer so each rule has at most one live row.
  Archive       → UPDATE lifecycle_state='archived' (allowed from
                   published OR draft).
  Restore       → UPDATE lifecycle_state='published' (only from archived).
  Preview       → Calls FristenrechnerService.Calculate with the draft
                   as a RuleOverrides entry — pure simulation, no DB
                   write. If draft_of is set, the override substitutes
                   for the peer (matching ID); otherwise it's appended.
  ListAudit     → SELECT paliad.deadline_rule_audit rows for one rule,
                   newest-first, with offset/limit pagination. Joined
                   with paliad.users.display_name for the changed_by
                   column.
  ListRules     → Admin list view with filters (proceeding_type_id,
                   trigger_event_id, lifecycle_state, fuzzy q over
                   name / name_en / rule_code).
  ExportMigrationsSince → SQL blob generator for the migration-export
                   admin flow (Q-H-5 pure SQL format). v1 emits one
                   statement per audit row in chronological order;
                   Slice 11b polishes the output (header comment,
                   collapse consecutive UPDATEs).

Audit-reason invariant: every write method requires a non-empty
reason string. setAuditReasonTx writes it into the session-local
paliad.audit_reason setting in the same transaction as the
INSERT/UPDATE, so mig 079's trigger captures the rationale
forever. Empty reason → ErrAuditReasonRequired (400 in the handler).

Spawn cycle guard: validateSpawnNoCycle pre-checks Create + UpdateDraft
edits that touch spawn_proceeding_type_id against the global rule
graph. Reuses the design §6 cycle-guard semantics — walks the
target proceeding's spawn rules transitively; raises ErrCyclicSpawn
if any reachable proceeding is the source. Slice 7's runtime guard
catches anything this misses; the editor surface catches it at
edit time so the editor sees a clear 409 instead of a silent
projection failure.

Typed errors:
  ErrRuleNotFound          → 404 in handler
  ErrInvalidLifecycleState → 409 in handler
  ErrAuditReasonRequired   → 400 in handler
  ErrInvalidInput          → 400 (re-uses the existing services-wide error)
  ErrCyclicSpawn           → 409 (re-uses Slice 7's typed error)

RuleAuditEntry struct extends models.DeadlineRuleAudit with a
display_name for the admin UI; distinct from services.AuditEntry
(the cross-source union for the site-wide audit panel) so the two
read paths don't conflict.
2026-05-15 01:50:03 +02:00