Part 7 of 7 · Warranty registration handler series ~10 min read

Engineering reference: the warranty registration handler architecture

This is the warranty registration handler with the friendly labels removed: the real resource names, the runtime, the serial ledger and the expiry index, the single public Function URL, the reminder schedule, and the IAM scope. If you want to build it rather than understand it, start here.

Key takeaways

  • Seven Lambda functions, all Python 3.14 on arm64, wired through one SQS queue with a dead-letter queue.
  • One public surface: a single Lambda Function URL on wrhr-register that takes the QR post and the web form — no API Gateway.
  • Five DynamoDB tables, all on-demand: the warranties record (keyed by serial), the submission ledger, the orders mirror, the opt-out list, and an append-only audit log.
  • The warranties table carries a reminder GSI keyed by due date; one EventBridge Scheduler drives the daily reminder sweep and the orders sync.
  • One Bedrock model, Claude Haiku 4.5 via Global cross-Region inference, called only by the notifier. Single region, eu-west-2.

The architecture, for engineers

This is the same system as Part 1 with the friendly labels removed and the real resources named. Everything is in one region, eu-west-2 (London), in one account. There is no API Gateway, no NAT Gateway, and nothing always-on; the only inbound surface is one Lambda Function URL, customer messages go out through SES and SNS, and work is buffered on a single SQS queue.

Engineering architecture: the registration Function URL, SQS, seven Lambdas, five DynamoDB tables, Bedrock, SES and SNS, and the scheduled jobs An external box at the top, the buyer’s phone or browser posting the QR scan or the web form, posts to a single Lambda Function URL, wrhr-register, inside a dotted AWS account container labelled eu-west-2. wrhr-register verifies the signed token with a secret from Secrets Manager, de-duplicates the submission against the DynamoDB serial ledger wrhr-submissions with a conditional write, and enqueues a job on the SQS queue wrhr-jobs with dead-letter queue wrhr-jobs-dlq. From the queue, three processing Lambdas run, all Python 3.14 arm64: wrhr-verify matches the serial against the orders mirror wrhr-orders and the warranties table wrhr-warranties, rejecting never-sold, duplicate, or out-of-window submissions; wrhr-store computes the term and expiry, claims the serial with a conditional write into wrhr-warranties (populating a reminder GSI keyed by due date) and writes wrhr-audit; and wrhr-notify makes the single Bedrock Claude Haiku 4.5 call and sends the confirmation via SES email or SNS SMS, checking the opt-out table wrhr-optout first. A fourth Lambda, wrhr-escalator, emails the support inbox via SES for claims and near-miss confirmations. On the left, EventBridge Scheduler drives two scheduled Lambdas: wrhr-orders-sync, which pulls the shop’s sales into wrhr-orders, and wrhr-sweep, which daily queries the reminder GSI on wrhr-warranties for due maintenance and pre-expiry reminders and enqueues them. The five DynamoDB tables sit in a column on the right: wrhr-warranties keyed by serial with a reminder GSI, wrhr-submissions keyed by serial with a TTL, wrhr-orders keyed by serial, wrhr-optout keyed by contact, and wrhr-audit keyed by serial and timestamp. Secrets Manager holds two secrets. Bedrock is called only by wrhr-notify. Buyer’s phone / browser QR scan or web form; serial + proof AWS account · eu-west-2 wrhr-register Function URL · verify, dedup form in wrhr-jobs SQS + wrhr-jobs-dlq EventBridge Scheduler 2 rules wrhr-orders-sync shop sales → wrhr-orders wrhr-sweep reminders, daily wrhr-verify match orders, 3 checks wrhr-store term + expiry, claim serial wrhr-notify Bedrock + SES / SNS send wrhr-escalator claims + near-miss via SES Secrets Manager 2 secrets Bedrock Haiku 4.5, Global SES (email) confirm, remind, claim SNS (SMS) opt-in reminders Buyer + team external wrhr-warranties PK serial · GSI reminder-due wrhr-submissions PK serial · TTL dedup wrhr-orders PK serial (mirror) wrhr-optout PK contact wrhr-audit PK serial, SK ts All Lambdas: Python 3.14, arm64 · CloudWatch Logs 7-day retention · AWS Budgets cost alarm · one Function URL, no API Gateway, no NAT
Fig 7. The warranty registration handler drawn for engineers: one Function URL on wrhr-register, an SQS-buffered set of seven Lambdas, five DynamoDB tables with a reminder GSI on wrhr-warranties, Bedrock called only by the notifier, SES and SNS for messages, and two scheduled jobs. One region, one account, no API Gateway.

Lambda functions

Seven functions, all Python 3.14 on arm64, all with CloudWatch Logs at 7-day retention. Each does one job and hands off; the SQS queue (wrhr-jobs, with wrhr-jobs-dlq as its dead-letter queue after five attempts) decouples the public form from the slower verification, store, and model calls, and carries a typed job (verify, store, confirm, remind) from one stage to the next.

  • wrhr-register — the only public surface. Backs the single Lambda Function URL and receives both the QR post and the typed form. Verifies the signed token against the secret, rate-limits per source, de-duplicates against wrhr-submissions with a conditional write on the serial (TTL a few minutes), normalises the serial, and enqueues a verify job. Nothing slow happens here — no order lookup, no compute, no send.
  • wrhr-verify — SQS-triggered on verify jobs. Looks the serial up in wrhr-orders, confirms the sale exists, checks wrhr-warranties for an existing record, and tests the purchase date against the product’s registration window. A pass enqueues a store job; a fail records the reason; a genuine near-miss (a receipt with no clean match) goes to wrhr-escalator.
  • wrhr-store — SQS-triggered on store jobs. Reads the warranty rule for the product line, computes the term and exact expiry dates from the verified purchase date, and claims the serial with a conditional PutItem into wrhr-warranties (attribute_not_exists(serial)), populating the reminder GSI and writing wrhr-audit. On success it enqueues a confirm job.
  • wrhr-notify — SQS-triggered on confirm and remind jobs. Makes the single Bedrock call, validates the draft (right dates, sane length, template fallback), checks wrhr-optout, and sends via SES (email) or SNS (SMS). It writes the send to wrhr-audit. This is the only function that calls Bedrock.
  • wrhr-escalator — builds the handover (serial + verified sale + computed coverage + reason), de-duplicates against open cases, and emails the support inbox via SES. This is the lane for later claims and for near-miss confirmations.
  • wrhr-orders-sync — scheduled. Pulls the shop’s sales (platform API, dealer feed, or export) and upserts rows into wrhr-orders keyed by serial.
  • wrhr-sweep — scheduled. Queries the reminder-due GSI on wrhr-warranties for reminders due on or before today and not yet sent, enqueues a remind job for each, and marks the reminder sent and the next one due so it’s only ever fired once.

Data stores, schedules, and messaging

  • DynamoDB (all on-demand). wrhr-warranties — PK serial; one item per registered unit with its coverage, the computed expiry dates, the reminder schedule and “sent” markers, and a state field; a GSI reminder-due (PK due_date, SK due_ts) is the sweep’s query path. The conditional write on serial is what guarantees one warranty per unit. wrhr-submissions — PK serial, short-lived with a TTL, the dedup ledger for the register step. wrhr-orders — PK serial, the sales mirror holding purchase date and channel. wrhr-optout — PK contact (email or E.164), checked before every send. wrhr-audit — PK serial, SK ts, append-only, holding each confirmation and reminder and the facts it was built from.
  • Function URL. One, on wrhr-register, with signed-token and signature verification in-function; AuthType NONE at the edge because authenticity is enforced by the shared secret and rate limit, not by IAM. No API Gateway.
  • SES and SNS. SES sends confirmations, reminders, and claim handovers from a verified domain with DKIM; SNS sends SMS reminders to the buyers who opted for them. Both go through wrhr-notify (customer) or wrhr-escalator (team).
  • EventBridge Scheduler. Two rules — wrhr-sweep at rate(1 day) for the reminder sweep, and wrhr-orders-sync at rate(1 hour) to keep the orders mirror current so a sale can be registered soon after it’s made.
  • Secrets Manager. Two secrets — the form signing key and the order-lookup API key — fetched at call time, never in env vars or the settings doc.
  • Bedrock. Model id anthropic.claude-haiku-4-5 via the Global cross-Region inference profile, invoked only by wrhr-notify.

Idempotency and failure handling

Exactly-once registration rests on one thing: the conditional write in wrhr-store. Because PutItem with attribute_not_exists(serial) can succeed only for the first writer, the entire pipeline behind it can be at-least-once without risk. SQS may deliver a job twice, a Lambda may retry after a timeout, two submissions may race — and at most one of them creates the warranty; the rest see the condition fail and treat it as “already registered”. The earlier dedup in wrhr-register is a cheap first filter, not the guarantee. Jobs that keep failing — a malformed payload, an order feed that’s down — land in wrhr-jobs-dlq after five attempts, where they can be inspected and replayed rather than lost or retried forever. The reminder sweep is idempotent for the same reason on the read side: a reminder marked sent is skipped, so a re-run never double-messages.

IAM scope and region

Each function gets its own execution role scoped to exactly what it touches, no wildcards. wrhr-register can read the signing secret, conditionally write wrhr-submissions, and send to wrhr-jobs — it cannot read orders, call Bedrock, or send a message. wrhr-verify can read wrhr-orders and wrhr-warranties and enqueue, nothing more. wrhr-store can conditionally write wrhr-warranties and append to wrhr-audit, but cannot delete from any table and cannot send. wrhr-notify is the only role with bedrock:InvokeModel, scoped to the one Haiku profile; it can publish to SNS and send via SES and read wrhr-optout, but touches no order data. wrhr-escalator can send via SES and read its inputs only. The scheduled functions hold the narrow permissions they need — wrhr-orders-sync writes only wrhr-orders, wrhr-sweep reads the reminder GSI and enqueues — and neither has an inbound surface. Everything runs in eu-west-2; the only cross-Region path is Bedrock’s Global inference profile, which routes the model call for capacity and is not a data store. An AWS Budgets alarm watches the monthly spend — with SMS the line most likely to move, it’s the cheapest early warning that volume (or a loop) is running hot.

That’s the whole system: a QR scan or a short form, verified against real orders, computed into a dated record that can only ever be written once, explained in plain language, and diarised so the customer hears back at exactly the right moment — with a person on the one decision, a claim, that should never be automated. Seven small functions, five tables, one model call per message, and no always-on anything, for a couple of dollars a month.

Design rules that shaped the build

  • One job per function. Seven small Lambdas beat one that does everything; the queue decouples the slow calls from the public form.
  • One public surface. Only wrhr-register is reachable from outside, on a single Function URL, authenticated by a signed token.
  • One conditional write is the guarantee. attribute_not_exists(serial) in wrhr-store makes registration exactly-once under any retry or race.
  • Least privilege, per role. Only the notifier can call Bedrock; only verify reads orders; only store writes warranties.
  • Dates live with the data. The expiry and reminder dates sit on the record and drive the GSI the sweep queries — no separate timers.
  • One region, one model. eu-west-2 throughout; Bedrock Haiku 4.5 via Global inference, called once per message.
All posts