feat(iace): Klaerungen Phase 3 — DB-Tabelle + Multi-User + PDF-Export
[migration-approved]
Three pieces complete the Klaerungen lifecycle:
1. Migration 028: iace_clarifications + iace_clarification_comments +
iace_clarification_history. Deterministic clarification_key
(UNIQUE per project) so engine re-inits don't lose answers.
History table logs every status/answer transition. The previous
JSONB-in-metadata storage is kept as read-only fallback for
pre-migration projects until a one-shot upcopy script runs.
2. Multi-User-Workflow:
- assigned_to field on every clarification (free-text user kuerzel
for now; an FK to users can be added in a follow-up).
- Comment thread per clarification (POST .../comment, GET
.../detail returns the thread).
- Status-history log written by UpsertClarification when the
status or answer actually changes.
- Frontend Modal: Zugewiesen-an + Bearbeiter fields, comment
thread with inline post, collapsible history section.
3. PDF-Export via print-friendly HTML:
- GET /clarifications.html returns a standalone A4-styled
document with status badges, norm references, affected hazards
and a signature row at the bottom. The Bediener opens the link
and uses Strg-P / Cmd-P to save as PDF. No server-side PDF
dependency added.
- Frontend "PDF / Druck" button next to CSV export.
Backend:
- internal/iace/store_clarifications.go: UpsertClarification,
ListClarificationsForProject, GetClarificationByKey,
AddClarificationComment, ListClarificationComments,
ListClarificationHistory.
- internal/api/handlers/iace_handler_clarifications.go:
- AnswerClarification now writes the SQL row, falls back to legacy
JSONB read on list.
- PostClarificationComment, ListClarificationDetail,
ExportClarificationsHTML added.
Migration must be applied manually on Mac Mini and prod via
psql -f /migrations/028_iace_clarifications.sql — pattern as in
scripts/apply_*_migration.sh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
-- Migration 028: IACE Clarifications — Multi-User-Workflow
|
||||
-- ==========================================================================
|
||||
-- Up to Phase 2 the Klaerungen feature persisted answers in
|
||||
-- iace_projects.metadata.clarification_answers (JSONB). That works for a
|
||||
-- single user but cannot model assigned_to, comment threads, status
|
||||
-- history or audit trail. Phase 3 introduces a proper relational table.
|
||||
--
|
||||
-- The previous JSONB blob remains read by the engine as fallback for any
|
||||
-- project whose clarifications have not yet been migrated, so this is a
|
||||
-- non-breaking add-on. A separate one-shot upcopy script migrates the
|
||||
-- existing JSONB answers into rows.
|
||||
-- ==========================================================================
|
||||
|
||||
-- 1. Main table: one row per (project, clarification_id)
|
||||
CREATE TABLE IF NOT EXISTS iace_clarifications (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
project_id UUID NOT NULL REFERENCES iace_projects(id) ON DELETE CASCADE,
|
||||
-- Deterministic clarification ID generated by the engine
|
||||
-- (e.g. "pattern:HP1640:0", "manuf:fanuc:dual-check-safety-dcs:1").
|
||||
-- Stable across re-inits so persisted answers survive.
|
||||
clarification_key TEXT NOT NULL,
|
||||
-- The verbatim question + source as known at last engine run.
|
||||
-- Kept in this table so the audit trail does not break if the
|
||||
-- pattern library is later updated.
|
||||
question TEXT NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
category TEXT NOT NULL,
|
||||
norm_references TEXT[] DEFAULT '{}',
|
||||
-- Lifecycle state
|
||||
status TEXT NOT NULL DEFAULT 'open'
|
||||
CHECK (status IN ('open', 'in_progress', 'answered', 'not_relevant')),
|
||||
answer TEXT DEFAULT '' CHECK (answer IN ('', 'ja', 'nein', 'teilweise')),
|
||||
reasoning TEXT DEFAULT '',
|
||||
-- Multi-User workflow
|
||||
assigned_to TEXT DEFAULT '', -- user id / kuerzel — free text for now
|
||||
answered_by TEXT DEFAULT '',
|
||||
answered_at TIMESTAMPTZ,
|
||||
-- Common audit
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (project_id, clarification_key)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_project ON iace_clarifications(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_tenant ON iace_clarifications(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_status ON iace_clarifications(project_id, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_assignee ON iace_clarifications(assigned_to) WHERE assigned_to <> '';
|
||||
|
||||
-- 2. Comment thread: one row per comment, ordered by created_at
|
||||
CREATE TABLE IF NOT EXISTS iace_clarification_comments (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
clarification_id UUID NOT NULL REFERENCES iace_clarifications(id) ON DELETE CASCADE,
|
||||
author TEXT NOT NULL DEFAULT '',
|
||||
body TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_comments_clar ON iace_clarification_comments(clarification_id, created_at);
|
||||
|
||||
-- 3. Status history — every status / answer change is logged.
|
||||
CREATE TABLE IF NOT EXISTS iace_clarification_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
clarification_id UUID NOT NULL REFERENCES iace_clarifications(id) ON DELETE CASCADE,
|
||||
actor TEXT NOT NULL DEFAULT '',
|
||||
from_status TEXT,
|
||||
to_status TEXT,
|
||||
from_answer TEXT,
|
||||
to_answer TEXT,
|
||||
note TEXT DEFAULT '',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_iace_clar_history_clar ON iace_clarification_history(clarification_id, created_at);
|
||||
|
||||
-- 4. Trigger to bump updated_at on the main table
|
||||
CREATE OR REPLACE FUNCTION iace_clarifications_touch_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_iace_clarifications_updated_at ON iace_clarifications;
|
||||
CREATE TRIGGER trg_iace_clarifications_updated_at
|
||||
BEFORE UPDATE ON iace_clarifications
|
||||
FOR EACH ROW EXECUTE FUNCTION iace_clarifications_touch_updated_at();
|
||||
Reference in New Issue
Block a user