Project Story Inspiration
Origin: I wanted a small, practical tool that lowers friction between residents and city staff — an app that turns short citizen reports into clear, actionable emails.
Why it mattered: Many civic requests fail because of poor formatting, missing details, or misrouting. A lightweight interface that drafts department-directed emails and lets users edit before sending reduces that waste.
What I Built
Stack:
Backend: Node.js + Express
Frontend: Vanilla HTML, CSS, JavaScript
Key files:
server.js — routing, email generation, send/save fallback
index.html — UI and modal
script.js — form submit, preview/send flows
styles.css — styling
API.env — runtime secrets
Core features:
Draft generation: via generateEmailContent (AI or generic template).
Preview/edit modal: UI lets users adjust subject/body before sending (/mcp/preview + /mcp/send-custom).
Safe fallback: if SMTP fails or isn’t configured, the server writes test-email-.txt so no reports are lost.
How I Built It
Routing: Implemented REST endpoints:
POST /report — classification and routing logic (heuristics + optional AI).
POST /mcp/preview — returns generated subject/body for review.
POST /mcp/send-custom — accepts exact {to, subject, body} and uses sendOrSaveEmail.
Email transport: Used Nodemailer with SMTP credentials from API.env. The send function attempts SMTP first, then falls back to saving locally.
UX flow:
User enters issue + location.
Generated preview appears.
Editable modal opens.
Edited content is sent via POST /mcp/send-custom.
Small, careful changes: Added a header image and a .header-icon rule without altering layout or behavior.
What I Learned
Operational lessons: Environment variables must be set before the Node process starts. Editing API.env is insufficient unless you restart or export the session vars. On Windows, killing a port-bound process often requires elevation.
Email lessons: Gmail SMTP rejects credentials (535 BadCredentials) without 2FA + app password. Transactional providers (SendGrid, Mailgun) are far more reliable for production.
Product lessons: Allowing user edits is essential. If you regenerate AI content, it overwrites edits unless you explicitly send the edited {subject, body} to /mcp/send-custom.
Challenges & How They Were Solved
SMTP authentication
Issue: Nodemailer failed with 535 errors until 2FA/app password was set.
Mitigation: Use robust fallback (save-to-disk), prefer session env vars, and consider SendGrid for production.
Windows port handling
Issue: EADDRINUSE and permission errors restarting Node.
Mitigation: Use Get-NetTCPConnection + Stop-Process carefully with admin privileges.
Preserving user edits
Issue: UI initially re-generated emails, overwriting user edits.
Fix: Added /mcp/send-custom endpoint and updated client to send edited {to, subject, body} directly..

Log in or sign up for Devpost to join the conversation.