# Data Model: Filter UX Standardization

## Overview

This feature introduces no new persistent storage. It defines a conceptual model for how in-scope Filament resource lists are classified, standardized, and protected against drift.

## Entities

### FilterTier

- Purpose: Classifies a resource list by rollout priority and required filter behavior.
- Source: The feature spec’s Tier 1, Tier 2, and Tier 3 model.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tier_key` | enum(`tier_1`,`tier_2`,`tier_3`) | yes | Standard priority bucket for the list |
| `criticality` | enum(`critical`,`important`,`standard`) | yes | Human-readable priority level |
| `requires_persistence` | boolean | yes | Whether search, sort, and filter state must persist |
| `requires_core_filters` | boolean | yes | Whether domain-appropriate filters are mandatory |
| `requires_date_range_when_time_based` | boolean | yes | Whether time-series lists in the tier must expose date range |
| `notes` | string nullable | no | Explanatory notes for exceptions or optional scope |

#### Validation Rules

- Tier 1 and Tier 2 must set `requires_persistence` to true.
- Tier 3 must remain optional unless elevated by a later spec.

### ResourceFilterProfile

- Purpose: Represents the agreed filter contract for one resource list.
- Source: Existing Filament resource tables such as `FindingResource`, `PolicyVersionResource`, `AlertDeliveryResource`, and peers.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `resource_class` | string | yes | Backing Filament resource class |
| `route_scope` | enum(`tenant`,`workspace`,`canonical_view`) | yes | Scope model used by the resource list |
| `data_ownership` | enum(`tenant_owned`,`workspace_owned`,`mixed`) | yes | Ownership context of listed records |
| `tier` | reference `FilterTier` | yes | Required behavior level |
| `has_filters` | boolean | yes | Whether the list exposes at least one filter |
| `has_persistence_trio` | boolean | yes | Whether filters, search, and sort persist in session |
| `supports_soft_delete` | boolean | yes | Whether the resource is soft deletable |
| `uses_standard_archived_filter` | boolean | yes | Whether the standard archive filter is present |
| `uses_central_status_source` | boolean | yes | Whether prioritized status/outcome filters derive from a central source |
| `has_date_range_filter` | boolean | yes | Whether the list exposes a date-range filter |
| `date_range_column` | string nullable | no | Primary time column used for the filter |
| `default_filter_behavior` | string nullable | no | Optional smart default such as open-only or active-only |
| `query_risk` | enum(`low`,`medium`,`high`) | yes | Risk level for added filter/query complexity |
| `exception_reason` | string nullable | no | Required when the standard is intentionally not fully applied |

#### Validation Rules

- If `tier` is Tier 1 or Tier 2 and `has_filters` is true, `has_persistence_trio` must be true.
- If `supports_soft_delete` is true, `uses_standard_archived_filter` must be true unless `exception_reason` is populated.
- If the list is time-based and in Tier 1 or Tier 2, `has_date_range_filter` must be true unless `exception_reason` is populated.

### FilterDimension

- Purpose: Describes one business-relevant filter dimension on a list.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `dimension_key` | string | yes | Stable filter identifier such as `status`, `outcome`, `platform`, or `date_range` |
| `filter_type` | enum(`select`,`trashed`,`ternary`,`custom`,`date_range`) | yes | Native Filament filter type |
| `label` | string | yes | User-facing label |
| `source_type` | enum(`enum`,`catalog`,`model_constant`,`query_distinct`,`custom_query`) | yes | Origin of the filter options or behavior |
| `is_priority_dimension` | boolean | yes | Whether this is a core required filter for the list |
| `has_indicator_support` | boolean | yes | Whether active filter indicators appear in the summary UI |
| `query_cost` | enum(`low`,`medium`,`high`) | yes | Estimated cost of applying the filter |

#### Validation Rules

- `date_range` filters must set `has_indicator_support` to true.
- `status` and `outcome` dimensions on prioritized resources should use `enum` or `catalog` source types where possible.

### CentralOptionSource

- Purpose: Represents the shared vocabulary source used by a filter dimension.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `source_key` | string | yes | Identifier such as `BaselineProfileStatus`, `BadgeDomain::FindingStatus`, or `TagBadgeDomain::Platform` |
| `source_kind` | enum(`enum`,`badge_catalog`,`tag_badge_catalog`,`config_registry`,`static_helper`) | yes | Kind of central option source |
| `provides_labels` | boolean | yes | Whether the source exposes user-facing labels |
| `provides_ordering` | boolean | yes | Whether the source defines preferred option order |
| `requires_adapter` | boolean | yes | Whether a thin helper is needed to convert the source into filter options |

#### Notes

- `BaselineProfileStatus` is already an enum-backed source.
- `FindingStatus` and `AlertDeliveryStatus` currently have centralized badge semantics but may need a thin adapter to become filter option sources cleanly.
- Policy type and platform labels may continue to come from existing config or tag-badge catalogs.

### FilterGuardRule

- Purpose: Defines one regression rule enforced in tests.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `rule_key` | string | yes | Stable guard identifier |
| `rule_type` | enum(`persistence`,`archive_visibility`,`central_status_source`,`functional_behavior`,`scope_safety`) | yes | What the rule protects |
| `coverage_level` | enum(`static_guard`,`livewire_behavior`,`feature_scope`) | yes | Test style used to enforce the rule |
| `applies_to` | list<string> | yes | Resource classes or test targets covered |
| `failure_mode` | string | yes | What kind of regression this rule should catch |

## Relationships

- One `FilterTier` applies to many `ResourceFilterProfile` records.
- One `ResourceFilterProfile` contains many `FilterDimension` definitions.
- One `FilterDimension` may depend on one `CentralOptionSource`.
- One `FilterGuardRule` may protect many `ResourceFilterProfile` records.

## State Transitions

- Audit: Record the current `ResourceFilterProfile` for each in-scope list.
- Standardization: Add missing persistence, archive visibility, date-range filters, and essential dimensions.
- Alignment: Swap prioritized local status arrays for central option sources or thin adapters.
- Guarding: Extend `FilterGuardRule` coverage so the standardized state cannot drift silently.

## Notes

- No migrations, new tables, or new Eloquent models are required.
- This conceptual model exists to support planning, implementation sequencing, and regression protection.