TenantAtlas/specs/059-unified-badges/research.md
2026-01-23 00:40:52 +01:00

4.3 KiB

Research — Unified Badge System (Single Source of Truth) v1

Goal

Standardize status/health and severity/risk badge semantics suite-wide so operators can reliably scan the admin UI without misread signals (for example, “success” never appearing as warning).

V1 scope explicitly excludes tag/category chips (policy type/platform/environment).

Existing Code & Patterns (to reuse)

Filament badge surfaces (current)

  • Tables already use TextColumn::badge() in many places.
  • Ad-hoc status and severity mapping exists in several hotspots, for example:
    • /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Pages/Monitoring/Operations.php
    • /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Widgets/Dashboard/RecentDriftFindings.php
    • /Users/ahmeddarrazi/Documents/projects/TenantAtlas/resources/views/filament/forms/components/restore-run-checks.blade.php

Guard test pattern (current)

  • The repo already uses Pest “guard” tests that scan the codebase for forbidden patterns:
    • /Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Guards/NoLegacyBulkOperationsTest.php

Status / severity sources (current)

Status-like values already exist in models/enums and must remain the source of truth for meaning:

  • Operation runs: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Models/OperationRun.php (status) + outcome usage in UI.
  • Inventory sync runs: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Models/InventorySyncRun.php (status constants).
  • Backup schedule runs: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Models/BackupScheduleRun.php (status constants).
  • Entra group sync runs: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Models/EntraGroupSyncRun.php (status constants).
  • Restore runs: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/RestoreRunStatus.php (enum).
  • Findings: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Models/Finding.php (severity + status constants).

Key Decisions

Decision: Centralize status-like badge semantics behind domain mappers

  • Decision: Introduce a central badge semantics layer that maps a “domain” + “value” to a single badge meaning (label + color meaning + optional icon).
  • Rationale: Eliminates drift from per-page match blocks and keeps UI semantics testable and reviewable.
  • Alternatives considered:
    • Inline mappings per resource/widget: rejected (drifts quickly; hard to enforce).
    • Config-only mappings: rejected for v1 (harder to type-check; still needs a rendering abstraction).
    • DB-stored mappings: rejected (adds runtime dependency and migration/tenant complexity for no user value).

Decision: V1 scope is “status-like” only (status/health + severity/risk)

  • Decision: V1 migrates status-like badges suite-wide; tag/category chips are deferred.
  • Rationale: Status/health and severity/risk are the highest-risk trust killers when inconsistent; tags are valuable but less safety-critical and more domain-specific.

Decision: Canonical drift severity meanings

  • Decision: Drift finding severity mapping is canonical: low = neutral, medium = warning, high = danger.
  • Rationale: Severity is a risk/attention signal; “low” should not appear as “success”.

Decision: No severity taxonomy changes in v1

  • Decision: Do not add/rename severity levels (for example, do not introduce “critical” in v1).
  • Rationale: This feature standardizes rendering semantics; changing underlying severity taxonomy is a separate scope and needs domain review.

Decision: Enforcement is tests + a lightweight guard

  • Decision: Add:
    • Mapping tests per domain (including invariants like “success is never warning”).
    • A lightweight guard test that flags newly introduced ad-hoc mappings for status/health and severity/risk.
  • Rationale: Mapping tests prove correctness; the guard prevents regressions and enforces the single-source-of-truth rule.
  • Alternatives considered:
    • Strict guard banning any badge usage not from the central system: rejected (too brittle; would block deferred tag/category chip work and legitimate non-status uses).

Open Questions

None — remaining work is implementation-time discovery of all status-like badge surfaces to migrate.