feat(t-paliad-088): Event Types for deadlines — schema + service + handlers (PR-1)
Migration 030 adds paliad.event_types and paliad.deadline_event_types
junction. ~43 firm-wide seeds biased toward submissions (25 UPC
submissions + 8 UPC decisions/orders/hearings + 5 EPO + 4 DPMA/DE + 1
cross-jurisdiction). UPC-seeded rows carry a loose trigger_event_id
column (no FK constraint per Q2: event_types leads, trigger_events
follows). RLS policies are defense-in-depth — primary enforcement is
in the Go service layer. Per Q6, any authenticated user can create
firm-wide types; admins moderate via the soft-delete archive lever.
EventTypeService: List (firm-wide ∪ own-private), GetByID, Create
(slug auto-derived, supports diacritics → ASCII), Update (author OR
admin-on-firm-wide), SuggestSimilar (powers the duplicate-warning in
the add modal), AttachToDeadlineTx + ValidateForUser + ListForDeadlines
for the junction.
DeadlineService gains an EventTypeService dependency and now:
- accepts event_type_ids on Create / Update / CreateBulk
- attaches them in the same transaction as the deadline insert
- hydrates EventTypeIDs on every Get / List / ListForProject
- supports the multi-select Typ filter via ListFilter.EventTypeIDs +
IncludeUntyped (UNION semantics within types, AND-intersected with
Status/Project)
AgendaService gets the same Typ filter on its deadline side;
appointments are unaffected.
API:
- GET /api/event-types?category=&jurisdiction=
- GET /api/event-types/suggest?q=
- POST /api/event-types
- PATCH /api/event-types/{id} (set archive=true to hide)
- GET /api/deadlines?event_type=<uuid>,<uuid>,none
- GET /api/agenda?event_type=<uuid>,<uuid>,none
- POST/PATCH /api/deadlines accept event_type_ids: [uuid]
go build / go vet / go test ./... clean.
Frontend (picker + custom-add modal + multi-select filter) follows in
PR-2. Admin moderation panel deferred to t-paliad-089 follow-up.
This commit is contained in:
@@ -181,6 +181,11 @@ type Deadline struct {
|
||||
CreatedBy *uuid.UUID `db:"created_by" json:"created_by,omitempty"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
|
||||
// EventTypeIDs lists the paliad.event_types attached to this deadline
|
||||
// via the paliad.deadline_event_types junction. Always present (never
|
||||
// nil) once the row has been hydrated by DeadlineService.
|
||||
EventTypeIDs []uuid.UUID `db:"-" json:"event_type_ids"`
|
||||
}
|
||||
|
||||
// DeadlineWithProject enriches a Deadline with parent-Project display fields
|
||||
@@ -403,3 +408,51 @@ type EventDeadlineRuleCode struct {
|
||||
RuleCode string `db:"rule_code" json:"rule_code"`
|
||||
SortOrder int `db:"sort_order" json:"sort_order"`
|
||||
}
|
||||
|
||||
// EventType is a user-facing categorization tag for a Deadline (Statement
|
||||
// of Defence, Reply, Decision on the merits, EPO opposition, …). Distinct
|
||||
// from TriggerEvent: TriggerEvents are calc-engine state (UPC-only,
|
||||
// verbatim youpc imports), EventTypes are the broader taxonomy users
|
||||
// pick from when creating a Deadline.
|
||||
//
|
||||
// CreatedBy NULL on system seeds; set on user-created rows. IsFirmWide
|
||||
// true for seeds and any firm-wide row a user explicitly publishes;
|
||||
// false for personal taxonomy. TriggerEventID is a loose linkage column
|
||||
// (no FK constraint) populated only for seeded UPC rows.
|
||||
type EventType struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
Slug string `db:"slug" json:"slug"`
|
||||
LabelDE string `db:"label_de" json:"label_de"`
|
||||
LabelEN string `db:"label_en" json:"label_en"`
|
||||
Category string `db:"category" json:"category"`
|
||||
Jurisdiction *string `db:"jurisdiction" json:"jurisdiction,omitempty"`
|
||||
Description string `db:"description" json:"description"`
|
||||
TriggerEventID *int64 `db:"trigger_event_id" json:"trigger_event_id,omitempty"`
|
||||
CreatedBy *uuid.UUID `db:"created_by" json:"created_by,omitempty"`
|
||||
IsFirmWide bool `db:"is_firm_wide" json:"is_firm_wide"`
|
||||
ArchivedAt *time.Time `db:"archived_at" json:"archived_at,omitempty"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
// EventTypeCategory enumerates the values allowed on event_types.category.
|
||||
// Mirrors the CHECK constraint in migration 030.
|
||||
const (
|
||||
EventTypeCategorySubmission = "submission"
|
||||
EventTypeCategoryDecision = "decision"
|
||||
EventTypeCategoryOrder = "order"
|
||||
EventTypeCategoryService = "service"
|
||||
EventTypeCategoryFee = "fee"
|
||||
EventTypeCategoryHearing = "hearing"
|
||||
EventTypeCategoryOther = "other"
|
||||
)
|
||||
|
||||
// EventTypeJurisdiction enumerates the values allowed on
|
||||
// event_types.jurisdiction (NULL is also valid).
|
||||
const (
|
||||
EventTypeJurisdictionUPC = "UPC"
|
||||
EventTypeJurisdictionEPO = "EPO"
|
||||
EventTypeJurisdictionDPMA = "DPMA"
|
||||
EventTypeJurisdictionDE = "DE"
|
||||
EventTypeJurisdictionAny = "any"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user