medium priority low complexity documentation pending documentor Tier 5

Acceptance Criteria

Every public method on ReportHistoryRepository has a Dart `///` doc comment with: description, all parameters, return type, and all thrown exception types
Every public method on ReportFileStorageClient has equivalent Dart doc comments with the same coverage
ARCHITECTURE.md contains a section titled `## Bufdir Report History Data Foundation` with subsections for table schema, RLS policies, and storage bucket configuration
Table schema section lists every column with: name, type, nullable/required, description, and any CHECK constraints
RLS policy section includes a matrix table showing allowed (✓) and denied (✗) operations per role (peer_mentor, coordinator, org_admin, unauthenticated) for SELECT, INSERT, UPDATE, DELETE
RLS section includes one concrete example SQL query per role showing how the policy filters results
Storage section documents bucket name, path convention (`{orgId}/{reportId}/{filename}`), signed URL expiry configuration, and retention/deletion policy
ARCHITECTURE.md section is internally consistent with the actual implementation — no invented behavior
Doc comments compile cleanly with `dart doc` — no broken references or malformed tags
Documentation is written entirely in English

Technical Requirements

frameworks
Dart doc comments (/// triple-slash syntax)
Markdown (for ARCHITECTURE.md)
apis
ReportHistoryRepository public interface
ReportFileStorageClient public interface
Supabase RLS policy SQL (for documentation of policy logic)
data models
bufdir_report_history (all columns)
ReportHistoryRecord (domain model fields)
StorageException (domain error type)
security requirements
Documentation must explicitly note that organization_id scoping is enforced at both the RLS layer (database) and the repository layer (application) — belt-and-suspenders pattern
Warn developers that bypassing the repository and querying Supabase directly from UI code will lose application-layer scoping

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Write Dart doc comments directly above each class and public method in `report_history_repository.dart` and `report_file_storage_client.dart`. Use `@throws` convention in the description (Dart does not have a formal `@throws` tag, but document thrown exceptions in the comment body: 'Throws [RepositoryException] if the Supabase query fails.'). For the ARCHITECTURE.md section, place it in the feature directory (e.g., `lib/features/bufdir_report_history/ARCHITECTURE.md`) rather than the project root to keep it co-located with the code. Use a Markdown table for the RLS policy matrix — it renders well in both GitHub and IDEs.

Derive the documentation from the actual migration SQL and repository source — do not document intended behavior, only implemented behavior. If any discrepancy is found between implementation and intent during documentation, raise it as a separate issue rather than documenting the wrong behavior.

Testing Requirements

No automated tests required for this documentation task. Manual review checklist: (1) run `dart doc` and verify zero warnings on the documented files; (2) have a second developer read the ARCHITECTURE.md section and confirm they can correctly answer: what columns exist, who can read/write, what the storage path looks like, and what exceptions to handle — without looking at source code.

Component
Report History RLS Policy Configuration
infrastructure low
Dependencies (5)
Write unit tests for ReportHistoryRepository using Mockito-generated mocks for the Supabase client. Cover: successful paginated fetch returns correct ReportHistoryRecord list, insertReportRecord maps domain model to correct JSON payload, updateReportStatus sends correct patch, error responses from Supabase are mapped to typed domain exceptions, and organization_id scoping is always applied in queries. epic-bufdir-report-history-foundation-task-008 Write unit tests for ReportFileStorageClient covering: uploadReportFile constructs organization-scoped path correctly, upload emits progress stream events, getSignedUrl returns URL with correct expiry, downloadReportFile delegates to signed URL generation, deleteReportFile calls storage remove with correct path, and storage errors are wrapped in typed StorageException. Use flutter_test and Mockito. epic-bufdir-report-history-foundation-task-009 Create the ReportHistoryRepository class in Dart using the Supabase Flutter client. Implement methods: fetchReportHistory(organizationId, {limit, offset}) returning paginated List<ReportHistoryRecord>, fetchReportById(id), insertReportRecord(ReportHistoryRecord), updateReportStatus(id, status), and deleteReportRecord(id). Use Riverpod provider for dependency injection. Handle Supabase errors and map to domain exceptions. epic-bufdir-report-history-foundation-task-004 Create the ReportFileStorageClient class wrapping Supabase Storage operations. Implement uploadReportFile(organizationId, localFilePath, reportId) returning the remote file path, downloadReportFile(filePath) returning a signed URL valid for 60 minutes, deleteReportFile(filePath), and getSignedUrl(filePath, expiresIn). Enforce organization-scoped file paths (e.g., {orgId}/{reportId}/{filename}). Handle upload progress stream for UI feedback. epic-bufdir-report-history-foundation-task-006 Write integration tests that verify the RLS policies are correctly enforced. Tests must cover: (1) coordinator from org A cannot read org B records, (2) peer mentor cannot insert report records, (3) admin can delete records within their org, (4) unauthenticated request is rejected. Use the Supabase service role client to seed test data and the anon/user client to verify access restrictions. Run against a local Supabase instance. epic-bufdir-report-history-foundation-task-007
Epic Risks (3)
high impact medium prob security

Incorrectly authored RLS policies could silently allow cross-organization data reads, exposing sensitive report history of one organization to coordinators of another in a multi-tenant environment.

Mitigation & Contingency

Mitigation: Write integration tests that explicitly authenticate as a user from organization A and assert zero rows are returned for organization B's history records. Use Supabase's built-in RLS testing utilities and review policies with a second developer.

Contingency: If a cross-tenant leak is discovered post-deployment, immediately revoke all active sessions for affected organizations, audit query logs for unauthorized access, and patch the RLS policy in a hotfix migration before re-enabling access.

medium impact medium prob technical

The 5-year retention policy for report files may conflict with Supabase Storage's lack of native lifecycle rules, requiring a custom pg_cron job that could fail silently and either delete files prematurely or never clean up.

Mitigation & Contingency

Mitigation: Implement the retention cleanup as a documented pg_cron job with explicit logging to a separate audit_jobs table. Add a Supabase Edge Function health check that verifies the cron job ran within the last 25 hours.

Contingency: If the cron job fails, files accumulate in storage (non-critical for compliance — over-retention is safer than under-retention). Alert the ops team via monitoring and manually trigger the cleanup function once the cron issue is resolved.

medium impact low prob integration

Signed URL generation depends on the requesting user's Supabase session being valid at the time of the call. If sessions expire during a long screen interaction, URL generation will fail with an authorization error and confuse the coordinator.

Mitigation & Contingency

Mitigation: Wrap signed URL generation in the service layer with a session-refresh check before calling Supabase Storage. Generate URLs on demand (tap-to-download) rather than pre-generating them for all list items on screen load.

Contingency: If a URL generation fails due to session expiry, surface a clear error message prompting the coordinator to re-authenticate, then automatically retry URL generation after session refresh completes.