Save the Queen City: a volunteer board that no longer depends on one inbox
Everything a volunteer preservation group runs on: public site, members hub and a daily routine that files documents and briefs the board.
"I'm blown away with what Tom has done with it."
Vice President, Plainfield preservation nonprofit (I serve on its board)

What changed
The situation
The group runs on volunteers, with no budget for staff or software. Its work depends on showing up at the right city hearing with the right history in hand.
What I built
A public site
Member sign-ups, an email list the group owns, and always-current links to city agendas.
A private members hub
Real board and member logins, not a shared password.
A daily routine at 5 a.m
It files inbox attachments into a tagged archive, syncs meeting invites, and pulls new city meeting documents.
An AI board briefing
The members home page opens with a summary of what's new and what needs action, with a link to every source it used, beside the calendar.
A searchable archive
Ask questions across years of minutes and case files.
A practice copy
The whole site, duplicated, where the board reviews changes before they go live.
A nightly check
Both sites are checked, and an alert goes out only when something is wrong.
What it costs
Beyond the domain, effectively nothing. Everything runs inside AWS and Google free tiers, on accounts that belong to the nonprofit, so the group isn't locked into any volunteer's personal subscription.
How it fits together
The group's Google Workspace holds mail, files and calendar and runs the daily routine. AWS serves the site, guards the members hub and checks itself nightly.
Colors follow AWS service categories; grey is outside the account; dashed lines are background paths. Swipe the diagram sideways.
Step by step
- The public reaches the site through CloudFront. An edge function cleans up addresses on every request.
- Members sign in through a login function backed by Cognito. The edge function turns anyone without a valid session away from the members area.
- Every day at 5 a.m., an Apps Script routine reads the shared board inbox.
- Attachments are filed into the Drive archive by topic and date, tagged, and marked if sensitive. Thread context is saved beside them.
- The routine watches the city’s agenda portal and pulls new meeting documents as they are posted.
- Gemini writes the board briefing under strict rules: business items only, and a link for every source.
- The routine publishes the briefing and recent documents through a secret-signed update function.
- The update function edits the right sections of the site and refreshes the cache, on both the live site and the sandbox.
- Every night, a read-only validator checks both sites against the site plan and sends an alert through SNS only if something is off.
Technical details
For your IT person: components, trade-offs and security. Open any section.
Components
| Layer | Service | What it does here |
|---|---|---|
| Edge | CloudFront + CloudFront Function | TLS, caching, and clean-URL rewrites. The function also checks for a session cookie before serving anything under the members area. |
| Site | S3 (private) | Static public pages and the members hub, readable only by CloudFront. |
| Sign-in | Lambda (login) + Cognito | The login function is a second CloudFront origin for sign-in paths. It checks credentials against Cognito and sets the session cookie on the parent domain, so the apex, www and production addresses all work. |
| Publishing | Lambda (update) | Accepts signed requests from the daily routine, updates named sections of pages, stores hosted files, and refreshes CloudFront. |
| Checking | Lambda (validator, Python) + SNS | Every night it reads both buckets and checks them against a schema of pages, entities, categories and redirects. It flags any hand-written brief older than three weeks. It never writes. |
| Daily routine | Google Apps Script | Runs once a day around 5 a.m. Its steps are filing, library organizing, sensitivity tagging, thread export, calendar sync, agenda watch, the briefing and the publish. |
| AI | Gemini API, NotebookLM | Gemini writes the briefing. The routine picks the current model automatically and keeps a cached fallback, so a model retirement doesn’t break the morning run. NotebookLM answers questions over the archive. |
| Workspace | Gmail, Drive, Calendar | A shared board inbox, the document archive and the group calendar, all owned by the nonprofit. |
| Environments | Terraform (shared module) | The same module builds production and a complete sandbox, each with its own bucket, CDN, sign-in pool and functions. |
Design decisions and trade-offs
Security and privacy
- The members area is enforced at the edge and at sign-in, not by hiding links.
- Sensitive case files are tagged so they stay out of anything public.
- Secrets live in script properties and function settings, never in page code.
- The nonprofit owns both the AWS and the Google accounts.
Run a nonprofit or a small office?
The same pattern works for any group whose knowledge lives in a shared inbox. Book a free 30-minute fit call and I’ll tell you what it would take.
