Case Study

Pardon Hub: Django Rebuild

A full-stack case management system for Do Moore Good's Pardon Me Campaign, Philadelphia. Purpose-built in Django to replace disconnected spreadsheets, now handling intake through Board of Pardons submission with a chained AI review pipeline and a threaded case-communication log.

Django AI Prompt Chain Role-Based Access Google Drive Threaded Comms

The Problem

As the Pardon Me Campaign grew, the team was tracking applicants, volunteers, and hubs across spreadsheets, with no central system and no way to coordinate communications. There was no document management, no automated outreach, and no single place for staff to see the full picture of a case.

The Solution

A full-stack Django web application purpose-built for the Pardon Me Campaign. One codebase, one database, one place for staff and coaches to work.

Role-Based Access

Super admins, hub managers, and pardon coaches (community liaisons, peer volunteers) each see a scoped slice of the data, plus a future applicant portal. Every list query is scoped to the user's role. A coach's URL cannot expose another coach's applicants, even if guessed directly.

Chained AI Case Review

A five-step Gemini prompt chain: dedupe and timeline every uploaded document, summarize the court record, score it against the PA Board of Pardons criteria, evaluate rehabilitation factors, and flag charges eligible for expungement or Clean Slate Act relief without a pardon. Each step feeds the next. Prompts live in the database, editable by staff without a developer, and every output is reviewed before it touches a case.

Threaded Case Updates

Case notes and contact history live in one threaded log per applicant, not a separate spreadsheet tab. A coach replies directly under any entry to keep a back-and-forth linked instead of scattering it across new rows, and a soft-delete with recovery means an accidental delete never loses history.

Forward-to-Log Email Import

A coach forwards their actual email exchange with an applicant to a dedicated address. A Gmail Apps Script and webhook parse it, match both participants against the database, and auto-create the update, attachments included, no retyping. Anything it can't confidently match lands in a staff review queue instead of silently failing.

Communications Pipeline

A queue-based email system with named trigger classes (status change, hub assignment, coach pairing, plus automated follow-up and coach-inactivity reminders). Every message is logged, BCC'd to a sysadmin mailbox for audit, and per-recipient opt-out is respected at send time.

PA UJS Portal Integration

One-click copy of name and DOB for court lookups, plus a bookmarklet that auto-fills the PA Unified Judicial System search form and bulk-downloads every docket sheet on the results page. Cuts document collection from 20 minutes to under two.

System Architecture

Public Intake
Multi-step form
Django App
Core logic + auth
SQLite DB
Source of truth
Google Drive
Proxied doc storage
Vertex AI
Gemini, 5-step chain
Email Queue
Comms + reminders
Apps Script
Forwarded-email intake

Auth uses magic-link email. Users click a time-limited link to start a session. No passwords, no OAuth flow, no Google account required for coaches. A weekly job still mirrors core records to a legacy Google Sheet as a fallback, but the spreadsheet-driven workflow the original system depended on is long gone.

Application Mockups

Applicants (staff view)
Last name ▲ First name Status DOB Hub Coach Follow-up Added Updated
View Applicant A Addition New 1982-04-09 Unassigned Unassigned - 2026-05-01 2026-05-01
View Applicant B In Progress 1978-11-22 West Philly Hub Coach 1 2026-04-30 2026-03-14 2026-05-08
View Applicant C 1990-07-03 Kensington Hub Coach 2 2026-06-01 2026-02-28 2026-05-10
View Applicant D Approved 1975-02-17 North Philly Hub Coach 3 - 2025-11-05 2026-04-22
View Applicant E In Progress 1986-09-14 Germantown Hub Coach 4 2026-05-28 2026-01-19 2026-05-12
Applicant Detail

Applicant B

In Progress Submit an update Upload documents
APP-0412 · added 2026-03-14 · last updated 2026-05-08 10:31 · hub West Philly Hub
Personal info
Documents (2)
Updates (7)
AI Summary (2)

Assignments

Hub: West Philly Hub
Coach: Coach 1
Add

Conviction history

CountiesPhiladelphia
OffensesPossession w/ intent
Sentence typeProbation
ViolationsNo
Yrs since completion10+ years
Copy for UJS search Open the portal
AI Summary Tab
Generate View current prompt ↗
Summarize court documents · 2026-05-08 10:22 · gemini-2.5-flash · 2 document(s) · latest

Conviction summary: One conviction on record (Philadelphia County, 2013). Possession with intent to deliver a controlled substance (35 P.S. 780-113(a)(30)). Docket CP-51-CR-0002847-2013.

Sentence: 2 years probation, completed without violation. No incarceration.

Years since completion: Sentence completed approximately 2015. Approx. 11 years elapsed.

Notes: No additional arrests or charges found in the record set provided. One alias on record (maiden name). Employment records referenced in RAP sheet indicate current employment. Strong candidate for positive board evaluation based on time elapsed and clean record post-conviction.

Fill Conviction History from this summary

Check the fields you want to replace with the AI's values, then apply. Review each one carefully.

Replace? Current value From this summary
Philadelphia Philadelphia
Possession w/ intent PWID (35 P.S. 780-113(a)(30))
Probation Probation
(blank) 10+ years
Apply checked fields
Updates Tab (Threaded)
📞 Coach 1 2026-05-08 (they called, reached): Checked in about the personal statement draft. She's finishing it this week and asked about the letters-of-support deadline.
Reply
Date, contact method, direction, and notes fields, posting inline without leaving the page.
✉️ Coach 1 2026-05-09 (we emailed, reached): Sent over the letters-of-support deadline and a template to share with her references.
📧 Coach 1 2026-05-14 (they emailed, reached): "Attached is the finished statement, thank you for the template!"
Coach 1 uploaded personal-statement-draft.docx (as part of email importer)
📝 Hub Manager 2026-05-15: Status moved to Reviewed / Ready to Pair.
AI Output: Document Timeline

2013

March 2013
  • 2013-03-25Arrest: Theft by unlawful taking, movable property. (D1)
  • 2013-03-27Charge: Complaint filed, theft and conspiracy. (D1)
May 2013
  • 2013-05-02Probation started: 12-month ARD probation, community service condition. (D1, D3)

2019

April 2019
  • 2019-04-01Restitution satisfied: Final judgment satisfied, case closed. (D4)

Grouped by year, then month; individual events are plain list items rather than nested accordions, so a long case history reads top-to-bottom without extra clicks. Citations link back to the exact source PDF and page.

Impact

Tech Stack

Django Python SQLite Google Drive API Vertex AI / Gemini 2.5 Apache + Gunicorn systemd Google Apps Script WeasyPrint Magic Link Auth

Need a system like this?

I build practical, custom web tools that replace spreadsheet chaos with real, maintainable workflows.

Let's talk