Click any card below to jump to that section.
Every admin tool, in one place.
Daily signup trend, source attribution, and conversion funnel. Use this during recruitment campaigns to see what's working in real time.
See what's happening in the ministry and track your own work. Use the dropdown to switch between daily, weekly, monthly, and yearly views.
| Volunteer | Inmate | State | Via | Requested | Status | Actions | |
|---|---|---|---|---|---|---|---|
| Loading... | |||||||
🟢 Green = active within 30 days · 🟡 Yellow = 31–60 days · 🔴 Red = 60+ days. Click any row to see full timeline and send a nudge email.
| Name | Health | Country | Verified | Slots | Active | Pending | Last Login | Last Activity | Registered | Remove | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Loading... | |||||||||||
| Name | ID # | SID # | State | Via | Status | Slots | Letter | Actions |
|---|---|---|---|---|---|---|---|---|
| Loading... | ||||||||
Use this to add a volunteer who signed up offline (in person, by phone, etc). The volunteer will be marked as email-verified immediately — no verification email is sent. If you leave the password blank, a temporary one is generated and the volunteer can reset via "Forgot Password" on the login page.
New inmates awaiting an intro letter or pending review. Once their intro arrives, approve them to add them to the public pool.
ℹ️ What does Pending Intake actually do?
When an inmate is added to the platform — by you, by a coordinator, or via bulk import — they start with intake_status = 'pending_intro'. While they're in this state:
- They do NOT show up on the public Volunteer Dashboard, so volunteers can't request them yet.
- They do show up here, on this Pending Intake panel, where you can see who needs their intro letter.
- You can print or send the templated intro request (the one that asks the inmate to write back with a few sentences about themselves).
Once a real intro letter arrives (typed in by you or pulled in by OCR), the system flips them to intake_status = 'active' and they appear on the public dashboard for matching. After that, they're in the regular Inmates list.
Stale flag: if it's been 3+ template requests or 120+ days without an intro, they're marked stale here so you can decide whether to keep waiting or remove them.
Loading...
Inmates currently waiting without an intro letter. They're hidden from the public letters page until a letter is scanned. Click Scan Now to jump straight into the Letter Scanner pre-filled with that inmate, or Edit to paste a letter manually.
| Name | ID # | State | Via | Status | Days Waiting | Actions |
|---|---|---|---|---|---|---|
| Loading... | ||||||
When a volunteer forwards an inmate's E-platform reply to letters@penpalministry.org, it lands here. The system tries to auto-match it to one of the volunteer's active assignments. Approve to add the letter to that assignment's correspondence timeline (direction: received). Reject if it's spam, a false positive, or unintended.
ℹ️ How does Mailbox work?
Inbound emails: When someone sends an email to anything-@penpalministry.org (info@, contact@, hello@, etc.), it lands here as a new thread. You can reply directly — your reply will be sent from noreply@penpalministry.org.
Intermediated mail: When you receive a USPS letter from an inmate and forward the contents to their volunteer (or vice versa), use the + Log intermediated mail button to record what you relayed. The system threads everything by volunteer↔inmate pair so you can review the full back-and-forth in one place.
Threading: Replies stay grouped with the original thread (matched by message-id headers, with a 60-day subject + sender fallback). Threads auto-archive when you click 🗄️ Archive.
Volunteer-reported issues only. Filter by severity, status, or date. Resolved issues are excluded from the Monday digest email.
Two queues here: Removals are coordinator-flagged volunteers you'd remove from the ministry. Inmate Adds are volunteer requests to be paired with an at-capacity inmate (the volunteer's slot stays free until you approve). Approving an add-request silently auto-bumps the inmate's max-slots to fit. Reject requires a note — the volunteer sees it in their email.
Volunteer-submitted stories. Approved testimonials appear publicly at /testimonials.html. Pending ones are awaiting your review. Use + Add Testimonial to enter testimonials you received offline (email, letter, conversation) or to add inmate-side stories.
Add New Coordinator
Per-coordinator activity stats. Use the time range to scope back further. Click a coordinator card to see their full action timeline.
Insights into match performance, correspondence health, and conversion. Cached for 10 minutes — click Refresh to bust the cache.
Send a custom email to a group of volunteers. Bounced and paused accounts are automatically skipped. Use {first_name} in the body to personalize.
{first_name} is filled per-recipient when sending.Configure ministry-wide settings. Changes appear immediately on the volunteer dashboard.
Volunteer community link
Optional Discord, Slack, Facebook Group, or other community URL. Shows as a card on the volunteer dashboard so active volunteers can connect with each other.
Onboarding video URL
Optional 60-second welcome video URL (YouTube unlisted, Loom, Vimeo, etc). When set, new volunteers receive an email from Richard with the video 24–72 hours after signup. Leave blank to disable the email.
📬 AR/TX Clearinghouse Addresses
Texas and Arkansas now centralize all inmate mail through PO Box clearinghouses. This button rewrites the Physical Mailing Address of every Texas and Arkansas inmate in the database to the current clearinghouse format (with the inmate's name + ID# interpolated in).
- Arkansas: "First Last / AR-DOC ID#: nnnnn / PO Box 25918 / Tampa, FL 33622"
- Texas: "First Last / TDCJ Digital Mail Processing Center / ID#: nnnnn / PO Box 660400 / Dallas, TX 75266-0400"
⚠️ Heads up: This OVERWRITES every existing AR + TX address. The previous address is saved into a backup column on the record (physical_address_pre_clearinghouse) so it can be inspected later, but the visible address field will change. Future inmates added in TX or AR will get the autofill automatically via the Add Inmate / Edit Inmate forms.
🤖 Claude API health check
Tests whether ANTHROPIC_API_KEY is set on Railway and the Claude API is responding. Used by translation, OCR letter scanner, and several other features. If this fails, those features will all fail.
Add YouTube or Vimeo videos to the public Training Library at /training.html. Volunteers see them on the public training page.
Add a video
Customize the subject line and body of system emails. Use placeholders like {first_name} to personalize. Templates without overrides use the built-in defaults. Click "Populate all templates" to load Richard-approved canonical copy for all 12 templates at once (won't overwrite anything you've already customized).
{first_name} means, the editor below shows the full list when you select a template.
Sends a warm reminder email to volunteers with active matches, encouraging them to send a holiday card to their pen pal. Includes their pen pal names and handling tips. The cron runs automatically every November 15. Use the buttons below for off-schedule sends.
Manual trigger
Sends to all verified, non-paused, non-bounced volunteers who have at least one active match.
Auto-generated end-of-year stats. Use your browser's Print dialog to save as PDF for sharing or filing.
Add an extra layer of security to the super admin login. After enabling, every admin login will require a 6-digit code from an authenticator app (Google Authenticator, Authy, 1Password, etc.).
- Railway (your hosting provider) runs automatic daily Postgres snapshots. You can roll back to any of the past few days from the Railway dashboard if something goes catastrophically wrong.
- Backblaze B2 (cloud storage) holds every scanned letter PDF and image file long-term. Files are never deleted unless an admin explicitly removes them.
- Manual backup (below) lets you download a full JSON snapshot of every database table to your own computer whenever you want. Save it to Google Drive, a USB stick, anywhere you trust.
Note: the JSON file does NOT include the actual PDF/image files (those are huge — they live on Backblaze B2 already). The file does include the URLs pointing to those files, so a full restore would pull both pieces together.
No action needed — backups happen on schedule whether you remember or not. The email arrives Sunday morning; click the link to save to Google Drive or wherever. Use the button below to test it right now.
Prospective volunteers you added manually but who haven't completed sign-up yet. They get no automated emails (welcome, verification, broadcasts, holiday cards) and can't be matched until activated. They auto-activate when they log in, set a password, verify their email, or you create their first manual match — or click Activate below to do it manually.
Every email sent to a volunteer from the "📨 Relay Message" flow (when "📧 Also email volunteer" was ticked). Most recent first. Click a row to see the full body that was sent. Archive handled ones to clear them from this view (they're never deleted).
Reusable form letters with variable substitution. From any inmate's profile click 📄 Generate Letter to fill a template with that inmate's name, address, etc.
{{first_name}}
{{last_name}}
{{inmate_number}}
{{physical_address}}
{{prison}}
{{state}}
{{communication_system}}
{{date_today}}
{{coordinator_name}}
{{first_name}}, {{last_name}}, {{email}}, {{country}}.Shared documents for the ministry: the Volunteer Guide, training materials, platform-specific instructions, and policies. Any admin can view and download. Only super-admin can upload, edit, or archive.
Scans automatically pulled from your HP Smart → Google Drive folder. Assign each to an inmate + letter type, then it imports into the regular Letter History flow.
Optional: archive scanned intro letter PDFs to Backblaze B2 (cloud storage) so the original files are preserved long-term. Without B2, only the OCR text is saved.
End a correspondence to return the inmate to the waiting list and free up the volunteer's slot. Click 📜 to view the letter log for any correspondence. Stalled = no letter logged in 45+ days. First letter overdue = reserved 14+ days without first letter sent.
| Volunteer | Inmate | State | Via | Status | Letters | Last Activity | Actions |
|---|---|---|---|---|---|---|---|
| Loading... | |||||||
| Volunteer | Inmate | State | Ended By | Reason | Date Ended |
|---|---|---|---|---|---|
| Loading... | |||||
- 💾 Scan Handwritten Letter — a real letter from an inmate (cursive / pencil / paper)
- 📧 Scan & Email Volunteer — same scan, but emailed to the matched volunteer
- 📄 PDF → Images / Text — articles, recipes, news, anything PRINTED you want to share
Scan a handwritten letter and save it directly to an inmate's profile. Upload a single image, multiple images (one per page), or a PDF — or use your phone's camera to capture pages live.
Upload a photo of a handwritten letter (single image, multiple pages, or PDF). Scanner reads the handwriting and emails it to the matched volunteer.
Upload a PDF (article, recipe, news story, research paper) and either extract the text for pasting into a letter, or convert the pages to JPG images for downloading.
Paste the JSON from bulk-import.json into the box below and click Import.
email_verified=false with a placeholder password hash. If a volunteer ever wants to use the platform, hit "Resend Verification" on their row and they'll get the standard sign-up flow. The whole batch is tagged with an import_batch_id so it can be rolled back in one click as long as none of them have been touched yet.
first_name,last_name,email,country,usps_alias,signup_date,notes
first_name, last_name, and email are required. Others are optional. signup_date can be any date format JS recognizes (e.g. 2/11/2025, Feb 11 2025). notes commas must be escaped — wrap the whole notes value in double quotes if it contains commas.NAME, EMAIL, LOCATION, START_DATE, # PALS spreadsheet. Auto-detects the ALIAS - ONLY divider, splits ALIAS_<alias> - <real name> into usps_alias + first/last name. Email dedup is built in — re-importing the same file is safe.
Export: Download all logged correspondence as a CSV — for backup, analysis, or sharing with coordinators.
inmate, volunteer, direction, body. Recommended: date. Optional (improves matching): inmate_number, volunteer_email, alias.Direction values (any of these work):
sent / received, or inmate→volunteer / volunteer→inmate, or from inmate / from volunteer.Identification: tries volunteer email and inmate number first (exact match), falls back to fuzzy name match. Ambiguous names are reported per-row.
inmate_assignments row with status=matched and the inmate is promoted from Waiting → Matched. Volunteers and inmates must already be in the database — this endpoint only creates the pairings. Tagged with an import_batch_id for one-click rollback (refused if any pair has activity, e.g. logged letters or journal entries).
inmate_first_name, inmate_last_name, state, optional aid_number/prison, plus pp_emails (array) and/or pp_names (array).
{ "batch_label": "may-2026-registry", "matches": [ { "inmate_first_name": "DONNIE", "inmate_last_name": "ABERNATHY", "state": "Alabama", "aid_number": "Z818", "pp_emails": ["holly@example.com"], "pp_names": ["Holly Watson"] } ] }
All inmates sharing the same inmate number are grouped together. The 🔒 green row in each group is the keeper — the rest are duplicates. To change the keeper: click Set as keeper on a different row. To delete one row only: click the 🗑 Delete button on that row. To delete many at once: tick the boxes and use the bulk action button at the top. Records with active correspondences cannot be deleted unless you turn on "Force delete".
Status of every scheduled task running on the server. Green = ran on schedule. Yellow = overdue. Red = failing or hasn't run in a long time. New tasks may show "never ran" until their first execution.