Plan: Reporting & Data Quality Dashboard

On this page

Status

Step Description Status

1

Plan file and nav entry

Done (2026-03-21) — MR !50

2

Reporting route module + view models

Done (2026-03-21) — MR !50

3

Quality dashboard page

Done (2026-03-21) — MR !50

4

Quality issues list page

Done (2026-03-21) — MR !50

5

AFCARS submission workflow page

Done (2026-03-21) — MR !50

6

NCANDS submission workflow page

Done (2026-03-21) — MR !50

7

Nav link + RBAC (supervisor+)

Done (2026-03-21) — MR !50

8

E2E tests

Done (2026-03-21) — MR !50

9

Documentation, commit, push, MR

Done (2026-03-21) — MR !50

Issues: TBD
Branch: feature/reporting-dashboard

Context

The craig-reporting API (port 8006) is fully built with 14 endpoints covering data quality issues, AFCARS submissions, and NCANDS submissions. The web UI has zero reporting pages — no routes, no templates, no view models. This plan wires the existing API into the web UI.

Scope

In scope:

  • Quality dashboard page (metrics, severity breakdown, readiness percentages)

  • Quality issues list page (paginated, filterable, resolve action)

  • AFCARS submission list + detail + workflow actions (generate, review, approve, transmit)

  • NCANDS submission list + detail + workflow actions

  • Navigation link (supervisor+ visibility)

  • E2E tests for page rendering

Out of scope:

  • New API endpoints (all exist on craig-reporting)

  • Trend charts or graphs (future enhancement — tables and badges only)

Design

Route Module

File: services/craig-web/src/routes/reporting.rs — new module

View models:

#[allow(dead_code)]
#[derive(Deserialize, Default, Clone)]
pub struct QualityDashboardView {
    pub total_unresolved_issues: i64,
    pub severity_breakdown: Vec<SeverityCount>,
    pub afcars_readiness: Option<f64>,
    pub ncands_readiness: Option<f64>,
    pub field_completeness: Option<f64>,
}

#[allow(dead_code)]
#[derive(Deserialize, Default, Clone)]
pub struct SeverityCount {
    pub severity: String,
    pub count: i64,
}

#[allow(dead_code)]
#[derive(Deserialize, Default, Clone)]
pub struct QualityIssueView {
    pub id: Uuid,
    pub source_service: String,
    pub source_record_id: Option<Uuid>,
    pub issue_type: String,
    pub field_name: Option<String>,
    pub description: String,
    pub severity: String,
    pub resolved: bool,
    pub resolved_by: Option<String>,
    pub resolved_by_name: Option<String>,
    pub resolved_at: Option<String>,
    pub detected_at: String,
}

#[allow(dead_code)]
#[derive(Deserialize, Default, Clone)]
pub struct AfcarsSubmissionView {
    pub id: Uuid,
    pub reporting_period: String,
    pub record_count: i32,
    pub validation_errors: i32,
    pub status: String,
    pub reviewed_by: Option<String>,
    pub reviewed_by_name: Option<String>,
    pub approved_by: Option<String>,
    pub approved_by_name: Option<String>,
    pub created_at: String,
}

Handlers

  • GET /reporting/ — quality dashboard (fetch /v1/reporting/quality/dashboard from API)

  • GET /reporting/issues — issues list (paginated, fetch /v1/reporting/quality/issues)

  • POST /reporting/issues/{id}/resolve — resolve issue (POST to API, redirect)

  • GET /reporting/afcars — AFCARS list (fetch /v1/reporting/afcars)

  • GET /reporting/afcars/{id} — AFCARS detail

  • POST /reporting/afcars/generate — generate submission

  • POST /reporting/afcars/{id}/review — review

  • POST /reporting/afcars/{id}/approve — approve

  • POST /reporting/afcars/{id}/transmit — transmit

  • GET /reporting/ncands — NCANDS list

  • Similar NCANDS workflow handlers

Templates

  • templates/reporting/dashboard.html — stat tiles for readiness, severity breakdown table, unresolved count

  • templates/reporting/issues.html — data table with severity badges, source service, description, resolve button

  • templates/reporting/afcars.html — submission list with status badges + workflow actions

  • templates/reporting/afcars_detail.html — detail with review/approve/transmit buttons

  • templates/reporting/ncands.html — similar

Navigation

Add "Reporting" link to authenticated nav bar between "Financial" and "Rules" (or after Financial for caseworker, after Rules for admin). Visible to supervisor+ only.

File: services/craig-web/templates/base.html — add nav link with role check

Route Registration

File: services/craig-web/src/main.rs — add reporting routes:

.route("/reporting/", get(routes::reporting::dashboard))
.route("/reporting/issues", get(routes::reporting::issues_list))
.route("/reporting/issues/{id}/resolve", post(routes::reporting::resolve_issue))
.route("/reporting/afcars", get(routes::reporting::afcars_list))
.route("/reporting/afcars/generate", post(routes::reporting::generate_afcars))
.route("/reporting/afcars/{id}", get(routes::reporting::afcars_detail))
// ... similar for ncands

Verification

  1. cargo xtask dev reload + navigate to /reporting/

  2. Dashboard shows quality metrics from API

  3. Issues list renders with pagination and severity badges

  4. AFCARS workflow actions work (generate → review → approve → transmit)

  5. E2E tests verify page rendering

  6. All 121+ existing E2E tests pass

Files Touched

File Change

services/craig-web/src/routes/reporting.rs

New: ~15 handlers + view models

services/craig-web/src/routes/mod.rs

Register reporting module

services/craig-web/src/main.rs

Add ~15 routes

services/craig-web/templates/reporting/*.html

5 new templates

services/craig-web/templates/base.html

Add Reporting nav link

services/craig-web/src/config.rs

Add reporting_url if not present

tests/e2e/specs/reporting.spec.ts

New E2E tests

Documentation Updates

  • .claude/docs/services.md — note web UI reporting pages

  • CHANGELOG.adoc

  • docs/modules/ROOT/pages/roadmap.adoc — tick reporting dashboard item

  • docs/modules/ROOT/pages/guide/supervisor.adoc — reporting workflow

Edit this page · latest