Files
paliad/internal/db/migrations/040_seed_concepts_and_backfill.up.sql
m 78966ec098 feat(t-paliad-131): Phase A — concept layer + AnchorOverrides + click-to-edit dates
PR-1 of the Unified Fristenrechner. Purely additive: new search-grouping
layer + per-rule date override capability. No coverage changes yet
(those land in PR-2 = Phase B1 UPC counterclaim cross-flows).

Migrations:
- 037: paliad.deadline_concepts (id, slug, name_de/en, aliases text[],
  party, category, sort_order). Trigram + GIN indexes for the search bar.
- 038: deadline_rules.concept_id (uuid FK), legal_source (text);
  event_deadlines.legal_source; trigger_events.concept_id (text slug,
  soft-link — youpc imports keep their bigint PK).
- 039: deadline_rules.condition_flag text → text[] (USING ARRAY[old]).
  Semantic: rule renders iff every element is in CalcOptions.Flags.
  Single-element arrays preserve the legacy with_ccr swap exactly.
- 040: seed 30 concept rows + backfill all 74 fristenrechner deadline_rules
  with concept_id; backfill legal_source from existing rule_code
  (e.g. 'RoP.023' → 'UPC.RoP.23.1', '§ 276 ZPO' → 'DE.ZPO.276.1',
  'Art. 108 EPÜ' → 'EU.EPÜ.108', 'R. 79(1) EPÜ' → 'EU.EPC-R.79.1').

Calculator (services/fristenrechner.go):
- ConditionFlag is now pq.StringArray (matches text[] schema). New
  allFlagsSet() helper gates rule rendering; rules with multi-element
  flags require ALL of them set (prep for Phase B1 with_amend ∧ with_cci).
- CalcOptions.AnchorOverrides map[string]string (rule_code → YYYY-MM-DD).
  The tree-walk consults overrideDates[parent.code] before reading the
  computed-date map; lets a downstream rule re-anchor on a user-set date.
- IsCourtSet rows that get an override stop being placeholder and emit
  the user's date as a real anchor (so downstream cost_app etc. compute
  off it). New IsOverridden flag in UIDeadline so the UI can highlight
  user-edited rows.
- LegalSource surfaced on UIDeadline for future search-card display.

UI (frontend/src/client/fristenrechner.ts + global.css + i18n):
- Each timeline / column rule date is click-to-edit. Click → inline
  date input → blur or Enter → POST with anchorOverrides → re-render.
  Empty value clears the override. Escape cancels. Root-event rows
  (the trigger anchor) stay non-editable — that's the trigger-date input.
- Override map cleared on proceeding switch / reset; persists across
  trigger-date / flag toggle changes within the same proceeding.
- New CSS: subtle hover underline on .frist-date-edit; lime border on
  .timeline-date--overridden + .frist-date-edit-input.
- New i18n key deadlines.date.edit.hint (DE + EN).

Handler (handlers/fristenrechner.go):
- POST body gains optional anchorOverrides map<string,string>; passed
  through to CalcOptions.

Tests:
- TestAllFlagsSet covers single-flag legacy semantic, two-flag AND
  semantic, empty-required unconditional, extra-flags-no-effect.
- Existing TestIsCourtDeterminedRule unchanged.

Phase A ships standalone — Phase B1 (UPC counterclaim cross-flows) and
Phase C/D (search backend + concept-card UI) follow.
2026-05-05 00:05:12 +02:00

450 lines
29 KiB
SQL

-- t-paliad-131 Phase A4: seed deadline_concepts + backfill concept_id
-- + legal_source on existing deadline_rules.
--
-- 30 concepts cover the existing 74 fristenrechner rules. Subsequent
-- coverage migrations (Phase B1 UPC counterclaim, B3 DE OLG/BGH/DPMA,
-- B5 EPA gaps, B6 cross-cutting Wiedereinsetzung) reuse these concepts
-- and add new ones as their rules land.
--
-- Slug naming rule (per design §4.4):
-- - EN slug for concepts native to UPC/EPC AND for shared concepts
-- that exist in both DE and UPC/EPC.
-- - DE slug only for concepts that exist exclusively in German law
-- (none in this initial seed; first DE-only concepts arrive in B3).
-- ============================================================================
-- 1. Seed paliad.deadline_concepts (30 rows)
-- ============================================================================
INSERT INTO paliad.deadline_concepts (slug, name_de, name_en, description, aliases, party, category, sort_order) VALUES
-- Initiating filings
('statement-of-claim', 'Klageerhebung', 'Statement of Claim', 'Die Einreichung der Klageschrift, die das Verfahren in Gang setzt.', ARRAY['Klageschrift', 'Klage', 'Statement of Claim', 'SoC', 'Klageerhebung'], 'claimant', 'submission', 10),
('application-for-revocation', 'Nichtigkeitsklage', 'Application for Revocation', 'Antrag auf Nichtigerklärung eines Patents — UPC Zentralkammer oder BPatG.', ARRAY['Statement for Revocation', 'Nichtigkeitsklage', 'Revocation Action', 'SoR'], 'claimant', 'submission', 11),
('application-for-provisional-measures', 'Antrag einstweilige Maßnahmen', 'Application for Provisional Measures', 'Antrag auf einstweilige Verfügung / einstweilige Maßnahmen vor dem UPC.', ARRAY['einstweilige Verfügung', 'einstweilige Maßnahmen', 'Application for PM', 'PI Application', 'EV-Antrag'], 'claimant', 'submission', 12),
('application-for-determination-of-damages', 'Antrag auf Schadensbemessung', 'Application for Determination of Damages', 'Antrag auf Schadensbemessungsverfahren nach abschließender Verletzungsfeststellung.', ARRAY['Schadensbemessung', 'Schadensersatz Antrag', 'damages application'], 'claimant', 'submission', 13),
('request-to-lay-open-books', 'Antrag auf Bucheinsicht', 'Request to Lay Open Books', 'Antrag auf Vorlage der Geschäftsbücher zur Berechnung des Schadensersatzes.', ARRAY['Bucheinsicht', 'lay-open books', 'discovery books'], 'claimant', 'submission', 14),
-- Pleadings cycle
('statement-of-defence', 'Klageerwiderung', 'Statement of Defence', 'Erwiderung des Beklagten auf eine Klageschrift, üblicherweise mit Verteidigungsanträgen und Sachvortrag.', ARRAY['Klageerwiderung', 'Statement of Defence', 'SoD', 'Erwiderung Klage', 'Verteidigung', 'Antwort auf Klage'], 'defendant', 'submission', 20),
('reply-to-defence', 'Replik', 'Reply to Defence', 'Erwiderung des Klägers auf die Klageerwiderung.', ARRAY['Replik', 'Reply to Defence', 'Reply to SoD'], 'claimant', 'submission', 21),
('rejoinder', 'Duplik', 'Rejoinder', 'Erwiderung des Beklagten auf die Replik.', ARRAY['Duplik', 'Rejoinder', 'Rejoinder to Reply'], 'defendant', 'submission', 22),
-- Appeal cycle
('notice-of-appeal', 'Berufungsschrift', 'Notice of Appeal', 'Einlegung der Berufung gegen ein erstinstanzliches Urteil.', ARRAY['Berufungsschrift', 'Berufungseinlegung', 'Berufungsfrist', 'Notice of Appeal', 'Beschwerdefrist', 'Beschwerdeeinlegung'], 'both', 'submission', 30),
('statement-of-grounds-of-appeal', 'Berufungsbegründung', 'Statement of Grounds of Appeal', 'Begründung der Berufung — separate Frist nach Einlegung.', ARRAY['Berufungsbegründung', 'Statement of Grounds', 'Grounds of Appeal', 'Beschwerdebegründung'], 'both', 'submission', 31),
('response-to-appeal', 'Berufungserwiderung', 'Response to Appeal', 'Erwiderung der Berufungsbeklagten auf die Berufungsbegründung.', ARRAY['Berufungserwiderung', 'Response to Appeal', 'Statement of Response', 'Erwiderung Berufung', 'Erwiderung Beschwerde'], 'both', 'submission', 32),
('cross-appeal', 'Anschlussberufung', 'Cross-Appeal', 'Anschlussberufung des Berufungsbeklagten innerhalb der Frist zur Berufungserwiderung.', ARRAY['Anschlussberufung', 'Cross-Appeal', 'Anschlussbeschwerde'], 'both', 'submission', 33),
('reply-to-cross-appeal', 'Erwiderung Anschlussberufung', 'Reply to Cross-Appeal', 'Erwiderung des Berufungsklägers auf die Anschlussberufung.', ARRAY['Erwiderung Anschlussberufung', 'Reply to Cross-Appeal'], 'both', 'submission', 34),
('appeal-with-leave', 'Berufung mit Zulassung', 'Appeal (with Leave)', 'Berufung gegen eine vom Gericht zugelassene Anordnung — 15-Tage-Frist (UPC R.220.2).', ARRAY['Berufung mit Zulassung', 'appeal with leave', 'order appeal'], 'both', 'submission', 35),
('request-for-discretionary-review', 'Antrag auf Ermessensüberprüfung', 'Request for Discretionary Review', 'Antrag auf Ermessensüberprüfung beim Berufungsgericht (UPC R.220.3).', ARRAY['Ermessensüberprüfung', 'discretionary review'], 'both', 'submission', 36),
('application-for-leave-to-appeal', 'Antrag auf Berufungszulassung', 'Application for Leave to Appeal', 'Antrag auf Zulassung der Berufung gegen eine Kostenentscheidung (UPC R.221.1).', ARRAY['Berufungszulassung', 'leave to appeal', 'Antrag Berufungszulassung'], 'both', 'submission', 37),
-- Cost-decision concept
('application-for-cost-decision', 'Antrag auf Kostenentscheidung', 'Application for Cost Decision', 'Antrag auf Festsetzung der erstattungsfähigen Kosten nach abschließender Entscheidung (UPC R.151).', ARRAY['Antrag auf Kostenentscheidung', 'cost decision', 'Kostenfestsetzungsantrag'], 'both', 'submission', 40),
-- Opposition / EPA-Erteilung
('opposition', 'Einspruchsfrist', 'Opposition', 'Einspruchsfrist gegen ein erteiltes Patent (EPA Art. 99 EPÜ, DPMA § 59 PatG).', ARRAY['Einspruch', 'Einspruchsfrist', 'opposition', 'Opposition Period', 'Opposition Notice'], 'both', 'submission', 50),
('request-for-examination', 'Prüfungsantrag', 'Request for Examination', 'Antrag auf sachliche Prüfung der EP-Anmeldung (R. 70(1) EPÜ).', ARRAY['Prüfungsantrag', 'Request for Examination', 'Examination Request'], 'claimant', 'submission', 51),
('approval-and-translation', 'Zustimmung und Übersetzung', 'Approval and Translation', 'Zustimmung zur Erteilungsfassung + Einreichung der Übersetzungen + Zahlung der Erteilungsgebühr (R. 71(3) EPÜ).', ARRAY['Zustimmung Erteilung', 'Approval', 'Translation Filing', 'R71(3) Approval'], 'claimant', 'submission', 52),
('filing', 'Anmeldung', 'Filing', 'Einreichung der Patentanmeldung — Anker für viele Erteilungsfristen.', ARRAY['Anmeldung', 'Filing', 'Patentanmeldung', 'Application Filing'], 'claimant', 'submission', 53),
-- Court-set events
('oral-hearing', 'Mündliche Verhandlung', 'Oral Hearing', 'Vom Gericht anberaumte mündliche Verhandlung — Datum wird vom Gericht bestimmt.', ARRAY['Mündliche Verhandlung', 'Oral Hearing', 'Hauptverhandlung', 'Haupttermin', 'Termin', 'Oral Proceedings'], 'court', 'hearing', 60),
('interim-conference', 'Zwischenverfahren', 'Interim Conference', 'Vom Gericht durchgeführte Zwischenkonferenz zur Verfahrensführung.', ARRAY['Zwischenverfahren', 'Interim Conference', 'Zwischenkonferenz', 'CMC'], 'court', 'hearing', 61),
('decision', 'Entscheidung', 'Decision', 'Vom Gericht erlassene Sachentscheidung — Urteil oder Beschluss.', ARRAY['Entscheidung', 'Urteil', 'Decision', 'Judgment', 'Endurteil'], 'court', 'decision', 62),
('order', 'Beschluss', 'Order', 'Vom Gericht erlassene verfahrensleitende Anordnung oder Beschluss.', ARRAY['Beschluss', 'Anordnung', 'Order', 'Verfügung', 'angegriffene Entscheidung'], 'court', 'order', 63),
('cost-decision', 'Kostenfestsetzungsbeschluss', 'Cost Decision', 'Beschluss zur Festsetzung der erstattungsfähigen Kosten (UPC R.157).', ARRAY['Kostenfestsetzungsbeschluss', 'Cost Decision', 'Decision on Costs', 'Kostenbeschluss'], 'court', 'decision', 64),
-- EP-Erteilungsverfahren-spezifische Court-Events
('search-report', 'Recherchenbericht', 'Search Report', 'Vom EPA erstellter Recherchenbericht zur EP-Anmeldung.', ARRAY['Recherchenbericht', 'Search Report', 'EP Search Report'], 'court', 'decision', 70),
('publication', 'Veröffentlichung', 'Publication', 'Veröffentlichung der Patentanmeldung (A1) oder der Erteilung (B1).', ARRAY['Veröffentlichung', 'Publication', 'A1', 'B1', 'Erteilungsveröffentlichung'], 'court', 'decision', 71),
('communication-r71-3', 'Mitteilung nach R. 71(3)', 'Communication under R. 71(3)', 'Mitteilung des EPA mit dem Erteilungstext zur Zustimmung (R. 71(3) EPÜ).', ARRAY['R 71(3)', 'Communication R71(3)', 'Mitteilung 71(3)', 'Erteilungstext'], 'court', 'decision', 72),
('grant', 'Erteilung', 'Grant', 'Veröffentlichung der Erteilung des EP-Patents (B1).', ARRAY['Erteilung', 'Grant', 'Patenterteilung', 'B1 Veröffentlichung'], 'court', 'decision', 73)
;
-- ============================================================================
-- 2. Backfill deadline_rules.concept_id (74 rows in fristenrechner trees)
-- ============================================================================
-- Helper: WITH-clause is per-statement; we use a CTE per UPDATE block to
-- map the 12 fristenrechner proc_type codes to their pt.id values.
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id, slug FROM paliad.deadline_concepts
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.soc'), ('DE_INF', 'de_inf.klage')
) AND c.slug = 'statement-of-claim';
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id, slug FROM paliad.deadline_concepts
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_REV', 'rev.app'), ('DE_NULL', 'de_null.klage')
) AND c.slug = 'application-for-revocation';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'application-for-provisional-measures')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_PI')
AND dr.code = 'pi.app';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'application-for-determination-of-damages')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_DAMAGES')
AND dr.code = 'damages.app';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'request-to-lay-open-books')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_DISCOVERY')
AND dr.code = 'disc.app';
-- statement-of-defence: spans many trees
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'statement-of-defence'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.sod'),
('UPC_REV', 'rev.defence'),
('DE_INF', 'de_inf.erwidg'),
('DE_NULL', 'de_null.erwidg'),
('UPC_DAMAGES', 'damages.defence'),
('UPC_DISCOVERY', 'disc.defence'),
('UPC_PI', 'pi.response'),
('EPA_OPP', 'epa_opp.erwidg')
);
-- reply-to-defence
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'reply-to-defence'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.reply'),
('UPC_REV', 'rev.reply'),
('DE_INF', 'de_inf.replik'),
('UPC_DAMAGES', 'damages.reply'),
('UPC_DISCOVERY', 'disc.reply')
);
-- rejoinder
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'rejoinder'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.rejoin'),
('UPC_REV', 'rev.rejoin'),
('DE_INF', 'de_inf.duplik'),
('UPC_DAMAGES', 'damages.rejoin'),
('UPC_DISCOVERY', 'disc.rejoin')
);
-- notice-of-appeal: covers DE Berufung, UPC Berufung, EPA Beschwerde
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'notice-of-appeal'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_APP', 'app.notice'),
('DE_INF', 'de_inf.berufung'),
('DE_NULL', 'de_null.berufung'),
('EPA_OPP', 'epa_opp.beschwerde'),
('EPA_APP', 'epa_app.beschwerde')
);
-- statement-of-grounds-of-appeal
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'statement-of-grounds-of-appeal'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_APP', 'app.grounds'),
('DE_INF', 'de_inf.beruf_begr'),
('DE_NULL', 'de_null.beruf_begr'),
('EPA_OPP', 'epa_opp.beschwerde_begr'),
('EPA_APP', 'epa_app.begr')
);
-- response-to-appeal
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'response-to-appeal'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_APP', 'app.response'),
('EPA_APP', 'epa_app.erwidg')
);
-- cross-appeal + reply-to-cross-appeal
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'cross-appeal'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_APP', 'app.cross_a'),
('UPC_APP_ORDERS', 'app_ord.cross')
);
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'reply-to-cross-appeal'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_APP', 'app.cross_a_reply'),
('UPC_APP_ORDERS', 'app_ord.cross_reply')
);
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'appeal-with-leave')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_APP_ORDERS')
AND dr.code = 'app_ord.with_leave';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'request-for-discretionary-review')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_APP_ORDERS')
AND dr.code = 'app_ord.discretion';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'application-for-leave-to-appeal')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_COST_APPEAL')
AND dr.code = 'cost.leave_app';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'application-for-cost-decision')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_INF')
AND dr.code = 'inf.cost_app';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'opposition')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EPA_OPP')
AND dr.code = 'epa_opp.frist';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'request-for-examination')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.exam_req';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'approval-and-translation')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.approval';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'filing')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.filing';
-- Court-set events: oral-hearing
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'oral-hearing'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.oral'),
('UPC_REV', 'rev.oral'),
('UPC_PI', 'pi.oral'),
('UPC_APP', 'app.oral'),
('DE_INF', 'de_inf.termin'),
('DE_NULL', 'de_null.termin'),
('EPA_APP', 'epa_app.oral')
);
-- interim-conference
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'interim-conference'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.interim'),
('UPC_REV', 'rev.interim')
);
-- decision (covers both Entscheidung and Urteil; epa_app.entsch + entsch2 both)
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'decision'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_INF', 'inf.decision'),
('UPC_REV', 'rev.decision'),
('UPC_APP', 'app.decision'),
('DE_INF', 'de_inf.urteil'),
('DE_NULL', 'de_null.urteil'),
('EPA_OPP', 'epa_opp.entsch'),
('EPA_APP', 'epa_app.entsch'),
('EPA_APP', 'epa_app.entsch2')
);
-- order
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'order'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('UPC_PI', 'pi.order'),
('UPC_APP_ORDERS', 'app_ord.order')
);
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'cost-decision')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'UPC_COST_APPEAL')
AND dr.code = 'cost.decision';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'search-report')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.search';
WITH proc AS (
SELECT id, code FROM paliad.proceeding_types WHERE category = 'fristenrechner'
),
con AS (
SELECT id FROM paliad.deadline_concepts WHERE slug = 'publication'
)
UPDATE paliad.deadline_rules dr
SET concept_id = c.id
FROM proc p, con c
WHERE dr.proceeding_type_id = p.id
AND ROW(p.code, dr.code) IN (
('EP_GRANT', 'ep_grant.publish'),
('EPA_OPP', 'epa_opp.grant')
);
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'communication-r71-3')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.r71_3';
UPDATE paliad.deadline_rules dr
SET concept_id = (SELECT id FROM paliad.deadline_concepts WHERE slug = 'grant')
WHERE dr.proceeding_type_id = (SELECT id FROM paliad.proceeding_types WHERE code = 'EP_GRANT')
AND dr.code = 'ep_grant.grant';
-- ============================================================================
-- 3. Backfill deadline_rules.legal_source from existing rule_code
-- ============================================================================
-- UPC RoP — current paliad rule_code is canonical 'RoP.NNN.x'. Convert
-- to structured 'UPC.RoP.NNN.x' (drop period before the rule number,
-- preserve subparagraph dots).
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.23.1' WHERE rule_code = 'RoP.023';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.29.b' WHERE rule_code = 'RoP.029.b';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.29.c' WHERE rule_code = 'RoP.029.c';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.29.a' WHERE rule_code = 'RoP.029.a';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.29.d' WHERE rule_code = 'RoP.029.d';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.137.2' WHERE rule_code = 'RoP.137.2';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.139' WHERE rule_code = 'RoP.139';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.142.2' WHERE rule_code = 'RoP.142.2';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.142.3' WHERE rule_code = 'RoP.142.3';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.151' WHERE rule_code = 'RoP.151';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.220.1' WHERE rule_code = 'RoP.220.1';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.220.2' WHERE rule_code = 'RoP.220.2';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.220.3' WHERE rule_code = 'RoP.220.3';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.221.1' WHERE rule_code = 'RoP.221.1';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.237' WHERE rule_code = 'RoP.237';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.238.1' WHERE rule_code = 'RoP.238.1';
UPDATE paliad.deadline_rules SET legal_source = 'UPC.RoP.238.2' WHERE rule_code = 'RoP.238.2';
-- DE ZPO / PatG — convert German free-text citations to structured codes.
UPDATE paliad.deadline_rules SET legal_source = 'DE.ZPO.276.1' WHERE rule_code = '§ 276 ZPO';
UPDATE paliad.deadline_rules SET legal_source = 'DE.ZPO.517' WHERE rule_code = '§ 517 ZPO';
UPDATE paliad.deadline_rules SET legal_source = 'DE.ZPO.520.2' WHERE rule_code = '§ 520 ZPO';
UPDATE paliad.deadline_rules SET legal_source = 'DE.PatG.82.1' WHERE rule_code = '§ 82 PatG';
UPDATE paliad.deadline_rules SET legal_source = 'DE.PatG.110.1' WHERE rule_code = '§ 110 PatG';
UPDATE paliad.deadline_rules SET legal_source = 'DE.PatG.111.1' WHERE rule_code = '§ 111 PatG';
-- EPA — Art. / R. → structured EU.* namespace.
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPÜ.93.1' WHERE rule_code = 'Art. 93 EPÜ';
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPÜ.99.1' WHERE rule_code = 'Art. 99 EPÜ';
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPÜ.108' WHERE rule_code = 'Art. 108 EPÜ';
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPC-R.70.1' WHERE rule_code = 'R. 70(1) EPÜ';
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPC-R.71.3' WHERE rule_code = 'R. 71(3) EPÜ';
UPDATE paliad.deadline_rules SET legal_source = 'EU.EPC-R.79.1' WHERE rule_code = 'R. 79(1) EPÜ';