JPA_ Case study

Case study · Loyalty SaaS platform · In production

VecinoClub

Serverless loyalty platform for local businesses in Chile

View VecinoClub
[ LIVE ]Multi-tenant23 ADRs
The context

Local businesses need to build relationships with returning customers beyond each individual sale.

The need

Many have no way to thank loyal customers or know who they are and how often they return.

First business

Imaquinaria, a manga and Japanese culture shop in Temuco, is VecinoClub’s first business and proving ground.

Customer experience

  • — Scan a QR code to get started, with no app to install
  • — Check stamps and points on a phone
  • — Review purchases and available benefits
  • — Redeem rewards from the business

Business dashboard

  • — Define benefits and program rules
  • — Register purchases at the counter
  • — Manage rewards and stamps
  • — View customer and purchase statistics
Zone 1 — Edge / Public
CloudFront (CDN, SPA routing)S3 Bucket (React static build)HTTPS via Route 53
Zone 2 — Authentication
API Gateway (HTTP API)Cognito User PoolJWT validation on every request
Zone 3 — Compute / Private
AWS Lambda (FastAPI + Mangum)DynamoDB single-table (by tenant_id)SSM · SES · CloudWatch
CI/CD

GitHub Actions — deploys frontend (S3 / CloudFront) and backend (sam deploy). Manual gate required before production.

01

Multi-tenant from day one

The system was designed for more than one business from day one: every query carries a business identifier, so adding another business means registering it, without changing the business logic. Imaquinaria remains the first club, and the Bushidō program is one configuration of the platform, not its limit.

02

DynamoDB single-table

ADR-0006

More than ten entities share one table. PK/SK keys follow access patterns, and every query includes the business identifier.

03

Pipeline with manual gate

ADR-0023

GitHub Actions deploys to staging automatically. Production requires manual approval via issue. Five bugs caught in staging before reaching the live system.

04

Data migrations as code

ADR-0019

Idempotent Python runner integrated in the CI/CD pipeline. Every DynamoDB data change goes through a PR, is versioned in git, and is applied automatically on deploy — zero manual post-deploy steps.

Requests in production 3.397 last 30 days
Error rate (5xx) 0% Lambda + API Gateway
p50 end-to-end latency 151 ms API Gateway + Cognito JWT
DynamoDB latency 14–17 ms average across all operations
Cold start rate 0.7% 24 of 3,397 invocations
Lambda / DynamoDB throttles 0 last 30 days

CloudWatch data · Lambda + API Gateway + DynamoDB · last 30 days

The Imaquinaria Bushidō

Level system with points multipliers — the multipliers are not arbitrary: they are calibrated so that reward redemption is attractive at exactly the average purchase volume of an Imaquinaria customer.

×1.0 Rōnin
×1.3 Samurai
×1.7 Hatamoto
×2.0 Daimyō
Premium Kamon tierDigital stamp cardsDōjō mental state sub-levels
FastAPIPython 3.13React 19TypeScriptMangumAWS LambdaAPI GatewayDynamoDBCognitoCloudFrontS3SESCloudWatchSSMAWS SAMGitHub Actions