[Story-1079] Filing type forum parity

Story 1079Epic None21 files · +1493/−114

PR #272 · pramaan-io/pramaan-functions · merged 2026-06-08

Why this matters

When a filing type disappears, its history disappears with it.

No archive, no soft delete, no audit — and references dangling.

Row gone. References orphan. Audit trail lost.

The fix — Archive, never shred; reference once, track forever.

How it flows

sequenceDiagram
  autonumber
  participant card as filing_type (catalog card)
  participant lib as lifecycle (librarian)
  participant bor as snapshot / template (borrower)
  card->>card: FT-002 issued, live
  card->>lib: request: archive this card
  lib->>bor: who has this card on loan?
  bor->>lib: 8 snapshots + 4 templates
  lib-->>card: flip availability  row retained
  card->>card: FT-002 permanent, never reissued

src/domains/filing_type/service.py

Methodin → outwhat it does
_in_use_references(filing_type_id, firm_id) → tuple[InUseReference, ...]lists snapshots and templates borrowing this filing type, blocking blind delete
_usage_count(db, filing_type_id, firm_id) → intcounts active borrowers so the UI shows how busy this card is
archive_filing_type(db, filing_type_id) → FilingTypeDetailViewmoves the card to the back room — flag flips, row retained
unarchive_filing_type(db, filing_type_id) → FilingTypeDetailViewbrings the card back to the live shelf if the firm needs it again

What changed, file by file

Alembic migration adds the availability lifecycle, archive/delete audit columns, and per-firm filing_type_number to business.filing_types, and rewrites the reference-kind constraint to allow filing_type as a valid kind.

new methodsignature
_replace_reference_kind_constraint(include_filing_type) → None
upgrade() → None
downgrade() → None
New fields: revision : strdown_revision : str | Sequence[str] | Nonebranch_labels : str | Sequence[str] | Nonedepends_on : str | Sequence[str] | None

Filing type service gains archive/unarchive actions plus in-use reference and usage-count checks, killing the naive hard-delete path that would orphan matter snapshots and matter-type templates.

new methodsignature
_list_item(row, usage_count) → FilingTypeListItem
_in_use_references(filing_type_id, firm_id) → tuple[InUseReference, ...]
_usage_count(db, filing_type_id, firm_id) → int
archive_filing_type(db, filing_type_id) → FilingTypeDetailView
unarchive_filing_type(db, filing_type_id) → FilingTypeDetailView

Filing type entity gains availability, filing_type_number, and audit columns (archived_at, archived_by_user_id, deleted_by_user_id, created_by_user_id) so every row carries its own provenance.

New fields: filing_type_number : intavailability : strcreated_by_user_id : UUID | Nonearchived_at : datetime | Nonearchived_by_user_id : UUID | Nonedeleted_by_user_id : UUID | None

Filing type DTOs surface availability, formatted filing_type_number, archive timestamps, usage count, and is_in_use / can_delete flags for the API and management UI.

new classsignature
FilingTypeAvailability(class)
_trim_name(value) → str | None
_trim_description(value) → str | None
New fields: availability : FilingTypeAvailabilityinclude_archived : boolfiling_type_number : intfiling_type_number_formatted : strarchived_at : datetime | Nonearchived_by_user_id : UUID | Noneusage_count : intis_in_use : boolcan_delete : boolcreated_by_user_id : UUID | None

Filing type repository helpers (current_user_id, find_live_by_name, create) carry the actor and the new filing_type_number allocation into inserts.

new methodsignature
current_user_id(db) → UUID
find_live_by_name(db, name, excluding_filing_type_id) → FilingType | None
create(db, data, filing_type_number, created_by_user_id) → FilingType

HTTP router exposes archive and unarchive endpoints and the management-only include_archived listing flag, bringing filing types to forum parity.

new methodsignature
archive_filing_type(filing_type_id, db, _) → FilingTypeDetailView
unarchive_filing_type(filing_type_id, db, _) → FilingTypeDetailView
New fields: include_archived : Annotated[

Shared formatter format_filing_type_ref renders the per-firm filing type number as the human-readable FT-001 string used across the platform.

new methodsignature
format_filing_type_ref(filing_type_number) → str

Files changed (21)

File±
alembic/versions/e2f8a1b3c4d5_0080_filing_type_forum_parity.py ★+313
docs/walkthroughs/story-1079-walkthrough.html+132
openapi/app-api.json ★+398 −41
src/app_api/router_filing_types.py+45 −8
src/domains/filing_type/AGENTS.md+42
src/domains/filing_type/dtos/__init__.py+2 −4
src/domains/filing_type/dtos/filing_type.py+68 −14
src/domains/filing_type/entity.py+70 −4
src/domains/filing_type/repository.py+49 −18
src/domains/filing_type/service.py ★+160 −12
src/domains/matter/redesign_service.py+1 −1
src/domains/matter_type/repository.py+3 −3
src/domains/reference_counter/entity.py+2 −1
src/shared/constants/firm_status.py+1
src/shared/formatters/__init__.py+2 −1
src/shared/formatters/filing_type_ref.py+14
tests/contract/test_app_filing_types_openapi.py+52
tests/integration/test_app_filing_types.py+70 −5
tests/integration/test_app_matter_redesign.py+4 −2
tests/shared/formatters/test_filing_type_ref.py+25
tests/unit/test_filing_type_parity_migration.py+40