01
Campaign homepage
Sticky header with PL/EN switch; the hero artwork swaps with the language. All copy lives in i18next.
Case study · 08 / 09
Consumer contest campaign
A bilingual contest site for Dumle: upload a receipt, tell your side quest, win. Fast and fun on the front — serverless, fully coded infrastructure on AWS behind it.
Dumle · Fazer
FMCG · Brand campaign
Landing page + serverless AWS
Design build, backend & infrastructure
The product
Shoppers fill in a form, upload a photo of their receipt and describe their “side quest”. Entries land in a Google Sheet for the organiser and the entrant gets a confirmation e-mail — in Polish or English.
Our part
A React 19 + TypeScript SPA with i18next, a serverless backend on Lambda and API Gateway, uploads direct to private S3, SES e-mails with DKIM, and five Terraform modules with separate state per campaign — shipped by a GitLab pipeline with smoke tests and Slack alerts.
Under the hood
The browser uploads to a presigned URL (SigV4, valid 600 s), skipping Lambda entirely; Lambda only signs the URL and then records the entry.
Contest date window, 200-character limit, consents that pass only on an explicit true, and duplicate receipt numbers rejected with a 409 pinned to the right field.
Five Terraform modules, state per campaign, DNS and ACM certificates in two regions, SES DKIM and least-privilege IAM — down to a SES condition on the from-address.
Clarity, Sentry Replay and the Meta and TikTok pixels load only after consent; withdrawing it clears their cookies. Decisions are versioned and expire after 12 months.
The outcome
Inside the product
Demo data · click any screen to enlarge
01
Sticky header with PL/EN switch; the hero artwork swaps with the language. All copy lives in i18next.
02
Hero, stores, what a side quest is, four steps, prizes, the entry form and FAQ — one scroll.
03
A keyboard-accessible date picker of our own — days outside the contest are blocked. The native date input lost because iOS ignores min and max.
04
POST /presign, PUT the file straight to S3, then POST /submit that returns the entry number.
05
Hamburger menu, the calendar in English and a 409 “duplicate receipt” error from Lambda attached to the exact field.
06
Categories and a table of every cookie — name, provider, purpose, lifetime. Analytics and marketing scripts load only after consent.
07
Our Python script parses the client’s .docx (numbered lists included) into HTML, headless Chrome renders the PDF, and the document lazy-loads as its own chunk.
08
Drawn from the Terraform code: CloudFront + S3 with OAC, API Gateway, Lambda, receipts bucket, Secrets Manager, Google Sheets, SES with DKIM, six CloudWatch alarms, budget, SNS, Slack and the GitLab pipeline.
Stack
Next case