Case study · 08 / 09

Side Quest z Dumle

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.

  • Campaign
  • Serverless
  • AWS
  • Terraform

Partner

Dumle · Fazer

Industry

FMCG · Brand campaign

Platform

Landing page + serverless AWS

Our role

Design build, backend & infrastructure

The product

What it does

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

What we built

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 hard parts

  1. 01

    Receipts straight to S3

    The browser uploads to a presigned URL (SigV4, valid 600 s), skipping Lambda entirely; Lambda only signs the URL and then records the entry.

  2. 02

    Rules enforced on the server

    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.

  3. 03

    Infrastructure as code

    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.

  4. 04

    Consent that means it

    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

A campaign site with no servers to babysit — and infrastructure that can be cloned for the next campaign from code.

Inside the product

8 screens, explained

Demo data · click any screen to enlarge

01

Campaign homepage

Sticky header with PL/EN switch; the hero artwork swaps with the language. All copy lives in i18next.

02

The whole page

Hero, stores, what a side quest is, four steps, prizes, the entry form and FAQ — one scroll.

03

Entry form

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

How an entry is sent

POST /presign, PUT the file straight to S3, then POST /submit that returns the entry number.

05

Mobile, in both languages

Hamburger menu, the calendar in English and a 409 “duplicate receipt” error from Lambda attached to the exact field.

06

Cookie settings

Categories and a table of every cookie — name, provider, purpose, lifetime. Analytics and marketing scripts load only after consent.

07

Terms generated from Word

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

Architecture on AWS

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

Frontend

  • React 19
  • TypeScript
  • Vite 6
  • SCSS
  • React Router 7
  • i18next
  • Sentry

Serverless

  • AWS Lambda (Node 20)
  • API Gateway
  • S3 presigned URLs
  • SES v2
  • Secrets Manager
  • Google Sheets API

Infrastructure

  • CloudFront + OAC
  • Route 53
  • ACM
  • CloudWatch
  • SNS
  • Budgets
  • Terraform

Delivery

  • GitLab CI/CD
  • Playwright
  • Slack alerts

Next case

Samtrening Online →

White-label personal training SaaS

Want a product
like this?

Get a free estimate