Auto-derived project codes from the tree (e.g. EXMPL.OPNT.567.INF.CFI), custom override wins #50

Open
opened 2026-05-20 11:47:59 +00:00 by mAi · 2 comments
Collaborator

Trigger

m 2026-05-20 13:47:

I would like to have project codes generated by the tree (where possible). So if the client is EXMPL and the Litigation is vs OPNT and the Patent ist EP1234567 / EP 567 and the court is UPC and it is an infringement proceeding in first instance it could be EXMPL.OPNT.567.INF.CFI — this should be the default and auto generated and used if no custom one is used.

Shape

Dot-separated segments, one per ancestor in the tree, each derived from that ancestor's most-relevant identifying field:

project_type segment source example
client client short code (reference if set, otherwise a slug of title) EXMPL
litigation opponent / counterparty short code (from title or a dedicated opponent field) OPNT
patent last 3 digits of patent_number (or full number when shorter) 567
case proceeding type + court level INF.CFI for UPC-CFI infringement

Assembled top-down from the deepest current project: <client>.<litigation>.<patent>.<proceeding>.<court>. Missing ancestors are skipped silently — EXMPL.567.INF.CFI is valid for a case under a Patent directly under a Client.

Custom override

If paliad.projects.reference is set on the project itself, that wins — auto-derivation only fills in the gap. The displayed code in headers / breadcrumbs / pickers reflects either the custom value or the auto-derived one with no extra UI indicator.

Implementation considerations

  • Derive lazily on render (Go service helper BuildProjectCode(project_id)) — no schema change, no migration. Each call walks the ancestor chain via the existing paliad.projects.path ltree.
  • Cache: optional materialised view paliad.projects_derived_codes(project_id, derived_code) if perf becomes a concern. Skip in v1; profile later.
  • Sanitisation: uppercase, strip diacritics, collapse non-alphanumerics to - then trim. EP-number extraction has its own rule (regex on the canonical EP format).
  • Show vs. store: derived code is displayed only — paliad.projects.reference keeps storing the manual override. Single source of truth: ancestor metadata.
  • Surfaces to update:
    • Project header on /projects/{id}
    • Breadcrumb trail
    • Project picker (typeahead / dropdown labels)
    • Submission-template variable bag ({{project.code}} should be derivable)
    • Excel export __meta sheet
    • Gitea-like "copy reference" affordance in the header

Open design questions for the head's batch

  1. Litigation opponent source — does litigation projects carry a dedicated opponent field today, or does the segment derive from a regex on title (e.g. "vs OPNT" → OPNT)? Probably needs a small schema addition: paliad.projects.opponent_code text on litigation projects.
  2. Patent segment — last 3 digits is the design example. Confirm: 3 digits always, or last-N where N depends on number length? For UPC publication numbers (longer than 7 digits), maybe last 4?
  3. Case segment — proceeding type abbreviation is currently proceeding_type_id reference into the proceeding-type table; map e.g. upc.inf.cfi.*INF.CFI. Verify the mapping table needs.
  4. Custom override semantics — wholesale override (custom replaces ALL segments) or per-segment override (user can set just one level)? Recommended: wholesale, custom is the entire string.
  5. Where does the user set the custom override — already on paliad.projects.reference, or a new dedicated project_code_override field?
  6. Collision handling — two cases with identical derived codes (rare but possible)? Append a -N disambiguator or treat as advisory?

Out of scope

  • Reverse mapping (look up a project by code) — that already works via reference.
  • History of project codes (audit who changed the manual override and when) — not requested.
  • Bulk regeneration of existing project references — manual codes stay; auto-derive only fills empty slots.

Role recommendation

inventor → coder — small but with 5+ design calls + a tiny schema addition (opponent_code on litigations). Reasonable batch with other tree / project-form feedback items.

## Trigger m 2026-05-20 13:47: > I would like to have project codes generated by the tree (where possible). So if the client is EXMPL and the Litigation is vs OPNT and the Patent ist EP1234567 / EP 567 and the court is UPC and it is an infringement proceeding in first instance it could be EXMPL.OPNT.567.INF.CFI — this should be the default and auto generated and used if no custom one is used. ## Shape Dot-separated segments, one per ancestor in the tree, each derived from that ancestor's most-relevant identifying field: | project_type | segment source | example | |---|---|---| | client | client short code (`reference` if set, otherwise a slug of `title`) | `EXMPL` | | litigation | opponent / counterparty short code (from title or a dedicated opponent field) | `OPNT` | | patent | last 3 digits of `patent_number` (or full number when shorter) | `567` | | case | proceeding type + court level | `INF.CFI` for UPC-CFI infringement | Assembled top-down from the deepest current project: `<client>.<litigation>.<patent>.<proceeding>.<court>`. Missing ancestors are skipped silently — `EXMPL.567.INF.CFI` is valid for a case under a Patent directly under a Client. ## Custom override If `paliad.projects.reference` is set on the project itself, that wins — auto-derivation only fills in the gap. The displayed code in headers / breadcrumbs / pickers reflects either the custom value or the auto-derived one with no extra UI indicator. ## Implementation considerations - Derive lazily on render (Go service helper `BuildProjectCode(project_id)`) — no schema change, no migration. Each call walks the ancestor chain via the existing `paliad.projects.path` ltree. - Cache: optional materialised view `paliad.projects_derived_codes(project_id, derived_code)` if perf becomes a concern. Skip in v1; profile later. - Sanitisation: uppercase, strip diacritics, collapse non-alphanumerics to `-` then trim. EP-number extraction has its own rule (regex on the canonical EP format). - Show vs. store: derived code is **displayed** only — `paliad.projects.reference` keeps storing the manual override. Single source of truth: ancestor metadata. - Surfaces to update: - Project header on `/projects/{id}` - Breadcrumb trail - Project picker (typeahead / dropdown labels) - Submission-template variable bag (`{{project.code}}` should be derivable) - Excel export `__meta` sheet - Gitea-like "copy reference" affordance in the header ## Open design questions for the head's batch 1. Litigation opponent source — does litigation projects carry a dedicated `opponent` field today, or does the segment derive from a regex on `title` (e.g. "vs OPNT" → `OPNT`)? Probably needs a small schema addition: `paliad.projects.opponent_code text` on litigation projects. 2. Patent segment — last 3 digits is the design example. Confirm: 3 digits always, or last-N where N depends on number length? For UPC publication numbers (longer than 7 digits), maybe last 4? 3. Case segment — proceeding type abbreviation is currently `proceeding_type_id` reference into the proceeding-type table; map e.g. `upc.inf.cfi.*` → `INF.CFI`. Verify the mapping table needs. 4. Custom override semantics — wholesale override (custom replaces ALL segments) or per-segment override (user can set just one level)? Recommended: wholesale, custom is the entire string. 5. Where does the user set the custom override — already on `paliad.projects.reference`, or a new dedicated `project_code_override` field? 6. Collision handling — two cases with identical derived codes (rare but possible)? Append a `-N` disambiguator or treat as advisory? ## Out of scope - Reverse mapping (look up a project by code) — that already works via `reference`. - History of project codes (audit who changed the manual override and when) — not requested. - Bulk regeneration of existing project references — manual codes stay; auto-derive only fills empty slots. ## Role recommendation **inventor → coder** — small but with 5+ design calls + a tiny schema addition (opponent_code on litigations). Reasonable batch with other tree / project-form feedback items.
mAi self-assigned this 2026-05-20 11:47:59 +00:00
Author
Collaborator

Implemented in PR #67 (#67) — paired with #47.

Design decisions (all picks confirmed by head):

  • New paliad.projects.opponent_code text on litigations (slug [A-Z0-9-]{1,16}); regex on title rejected as brittle
  • Patent segment: last 3 digits of the digit-stream (full digits when <3); kind-code suffix (A1, B2, T3, …) stripped before extraction
  • Case segment: proceeding_types.code jurisdiction prefix dropped → INF.CFI, REV.CFI, APL.MERITS, INF.LG, INF.OLG, …
  • Custom override (paliad.projects.reference) wins outright (wholesale, not per-segment)
  • BuildProjectCode populates code on every projected Project JSON (one bulk CTE round-trip per list page; no v1 cache)
  • Collisions are advisory in v1 (no -N disambiguator; users set custom reference if it matters)

Reference tree from the issue body (Example Client → Siemens v Huawei → EP3456789 → upc.inf.cfi) derives to EXAMPLE.OPNT.789.INF.CFI once opponent_code is filled.

Final SHA: d326acb. Migration: mig 113 (rebumped from 111→112→113 to dodge euler/gauss slot collisions).

Wired into project header, picker, submission-template variable bag ({{project.code}}), Excel __meta row is a follow-up once the surface change pattern lands. Deploy via auto-webhook on merge.

Implemented in PR #67 (https://mgit.msbls.de/m/paliad/pulls/67) — paired with #47. Design decisions (all picks confirmed by head): - New `paliad.projects.opponent_code text` on litigations (slug `[A-Z0-9-]{1,16}`); regex on title rejected as brittle - Patent segment: last 3 digits of the digit-stream (full digits when <3); kind-code suffix (A1, B2, T3, …) stripped before extraction - Case segment: `proceeding_types.code` jurisdiction prefix dropped → `INF.CFI`, `REV.CFI`, `APL.MERITS`, `INF.LG`, `INF.OLG`, … - Custom override (`paliad.projects.reference`) wins outright (wholesale, not per-segment) - `BuildProjectCode` populates `code` on every projected Project JSON (one bulk CTE round-trip per list page; no v1 cache) - Collisions are advisory in v1 (no `-N` disambiguator; users set custom `reference` if it matters) Reference tree from the issue body (`Example Client → Siemens v Huawei → EP3456789 → upc.inf.cfi`) derives to `EXAMPLE.OPNT.789.INF.CFI` once opponent_code is filled. Final SHA: d326acb. Migration: mig 113 (rebumped from 111→112→113 to dodge euler/gauss slot collisions). Wired into project header, picker, submission-template variable bag (`{{project.code}}`), Excel `__meta` row is a follow-up once the surface change pattern lands. Deploy via auto-webhook on merge.
Author
Collaborator

Shipped via kepler on mai/kepler/inventorcoder-project — merged into main; commit https://mgit.msbls.de/m/paliad/commit/1c021ed. Live after next Dokploy deploy.

Shipped via kepler on `mai/kepler/inventorcoder-project` — merged into main; commit https://mgit.msbls.de/m/paliad/commit/1c021ed. Live after next Dokploy deploy.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#50
No description provided.