A review by a verified attorney or clerk is worth ~10x a random internet review. Bench-review's whole credibility model hinges on the audience being able to tell which reviewers are insiders.
Scope
- New columns on
users:credential_type: enum— "bar_admission" / "clerk_position" / "court_staff" / "judicial_appointment"credential_state: string— two-letter state code or "FEDERAL"credential_proof_path: string— pointer to uploaded bar card / clerk ID / etc. in private storagecredential_verified_at: datetime nullablecredential_verified_by_user_id: integer nullable(admin reviewer)
- New view:
/settings/credentials— user uploads proof (bar card photo, court ID, etc.); status shows "Pending review" / "Verified" / "Rejected". - Admin: new tab in
/adminfor credential verification queue. - Public render: green check badge next to reviewer name when verified, hover/tap shows "Verified attorney, CA bar" or similar.
- API:
POST /api/me/credentials(upload),GET /api/me/credentials/status,POST /api/admin/credentials/{userId}/verify//reject.
Acceptance
- Verified reviewers get a check badge on every surface where their name appears (article, public profile, feed cards).
- Unverified reviews still work — verification is additive, not gating.
- Credential proofs stored in PRIVATE storage; never exposed via public API.
- Admin queue lets reviewers approve / reject with a rejection reason.
- Reviewer can re-upload after rejection.
Privacy
The uploaded proof image is sensitive. Store in a non-public bucket, restrict access to the admin role, and don't expose any URL for it in client-facing payloads. The verified badge surfaces only the credential type + state — never the proof itself.