Document expiry watcher
A serverless watcher that tracks every contract, certificate, insurance policy, license, lease, and software subscription your business renews; pings the right owner with full context before each one lapses; escalates if nobody acts. The owner can renew, snooze, or ack-only right from the alert. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.
-
01
A document expiry watcher on AWS for a few dollars a month
The whole system on one page — an item intake, a watcher, and a dispatch piece, plus the four moves they share for every item.
-
02
How an item gets tracked
Three lanes feed the registry — the Drive sheet itself, an inbox-forwarding lane that parses PDFs into proposed rows for one-tap approval, and an hourly calendar import for events tagged
#expires. -
03
How the watcher knows when to alert
A daily tick reads the registry, computes days-to-expiry per item, compares against per-category window chains in the rules doc, and picks one of four moves: healthy, first alert, reminder, escalate. No model on the tick.
-
04
How an alert finds the right person
Owner resolution per item, quiet hours, holiday calendars, Slack DMs with full context, email fallback, and the four guardrails between the watcher’s chosen move and the actual ping landing.
-
05
How an item gets renewed
Three actions on the Acknowledge button: renew (new expiry, fresh chain), snooze (delay without dismissing, capped at three per chain), and ack-only (silence the chain without changing the expiry). Every action is logged.
-
06
What the expiry watcher costs
Pennies a month at SMB volume. The watcher runs once a day, calls no models on the tick, and only fires Bedrock on the inbound parsing lane and the monthly summary.
-
07
Engineering reference: the expiry watcher architecture
Same system, drawn purely for engineers. Service names, resource identifiers, region, Bedrock model IDs, Lambda inventory, IAM scopes, the SES inbound rule set, EventBridge Scheduler config, and the DynamoDB schemas.
Frequently asked questions
- What is a document expiry watcher?
- A small serverless system that tracks every contract, certificate, insurance policy, license, lease, and software subscription your business renews; pings the right owner with full context before each one lapses; and escalates to a manager if nobody acts. The owner can renew, snooze, or ack-only directly from the alert.
- How much does it cost to run?
- About $1.50/month at typical small-business volume (around 100 tracked items). The fixed cost is essentially zero. The variable cost is dominated by the daily Lambda tick that reads every item; Bedrock and Textract fire only on the inbound parsing lane and the monthly summary, so they’re small slivers. At 2,000 tracked items the bill lands around $12.
- Which AWS services does it use?
- Lambda (Python 3.14, arm64) with Function URLs for the acknowledgment endpoint, EventBridge Scheduler for the daily tick and deferred-dispatch one-offs, DynamoDB on-demand, S3 (with versioning), SES inbound + outbound, Secrets Manager, CloudWatch Logs (7-day retention), AWS Budgets, and Bedrock (Claude Haiku 4.5 via Global cross-Region inference) for the inbound parsing and monthly summary. No API Gateway, no NAT Gateway, no always-on compute, no Knowledge Base.
- Where does the registry live?
- In a Google Sheet in a Drive folder. One row per item with name, category, owner email, vendor, expiry date, renewal cost, contract value, and a link to the source document. A small
drive-syncLambda mirrors the sheet to S3 every 15 minutes; the watcher reads from S3 to keep Drive API calls predictable and to get S3 versioning for free. - Does the watcher use AI?
- Sparingly. The daily tick uses no AI — it’s plain Python that reads dates and decides on a move. Bedrock Haiku 4.5 fires only when somebody forwards a contract PDF (Textract + Haiku propose a registry row for human approval) and once a month for the board-summary narrative. Most of the system is deterministic by design.
- How does an alert reach me without being noisy?
- Each category has its own window chain in the rules doc — legal contracts get 90/60/30/14/3 days, insurance gets 60/30/7, software gets 30/14/3. Pings respect quiet hours (default 6pm–8am local) and the holiday calendar. Acknowledged items stop pinging until renewal. Ack-only stops the chain entirely without changing the expiry. Snooze defers without dismissing; you get up to three snoozes per chain before the watcher escalates anyway.
- What happens when I act on an alert?
- Three buttons on every alert: Renew opens a modal with the new expiry date and renewal cost; on save, the registry is updated via the Sheets API and the chain is archived. Snooze defers N days (default 7). Ack-only silences the chain without changing the expiry. Every action is recorded in the
ew-auditDynamoDB table with timestamp, item, action, by-user, and a before-and-after snapshot, so changes are reversible and the trail is auditable for years.