AT EDUCACAO — TECHNICAL ANALYSIS

Financial Education
LMS Platform for Brazil

Technical analysis of architecture options for ATFX's Learning Management System. We evaluated two paths — a Modern Stack and WordPress — and present our findings below, including trade-offs, compliance considerations, and cost projections.

Time to Launch
8 weeks
Monthly Cost
~$100 - $175
LGPD Compliance
Modern Stack — native | WordPress — requires plugins
Data Residency
Sao Paulo, BR
Active document
Abril 2026
CONTEXT

The Challenge

BUSINESS NEED

ATFX Educacao needs a proprietary LMS platform to deliver financial education courses in Brazil. The platform must handle user authentication, paid course access, video delivery, and payment processing — all while complying with Brazil's LGPD data protection law (Lei 13.709/2018). The wrong architecture decision introduces legal liability, data portability risk, and potential rebuild costs.

CORE REQUIREMENTS
  • 01User registration and authentication for Brazilian students
  • 02Paid course access with PIX, Boleto, and credit card payments
  • 03Private video delivery with access control
  • 04LGPD compliance: data residency in Brazil, consent management, data portability (Art. 18)
  • 05Scalable infrastructure for LATAM expansion
ALTERNATIVES EVALUATED

Architecture Decision Record

EVALUATION

We evaluated WordPress as a potential platform for the LMS. WordPress is a proven CMS with a large ecosystem and faster initial setup. However, our technical assessment identified specific limitations that are worth considering before making an architecture decision.

01

Access Control Incompatibility

MemberPress — the access control plugin required for private courses — does not officially support WordPress Multisite. The core payment + access architecture cannot be built as intended. Alternative plugins (Paid Memberships Pro) exist but add complexity and reduce reliability.

02

Data Fragmentation Risk

Course, user, and payment data are stored across separate third-party plugin schemas (LearnDash, WooCommerce, Paid Memberships Pro). ATFX would not own or control the database structure, making LGPD data portability (Art. 18) and future platform migrations significantly more difficult.

03

LGPD Granular Compliance

Granular LGPD compliance cannot be fully guaranteed through third-party plugins whose code, storage behavior, and data handling ATFX does not control. In a regulated financial market, this introduces legal uncertainty that can be avoided with a purpose-built architecture.

Note: WordPress remains the recommended tool for the public marketing landing page (Module 6). The Elementor-based landing page fetches public course data from Supabase via anon key — no authentication, no payments, no user data is stored in WordPress.

Reference Comparison
Criterion
Modern Stack
WordPress
Frontend
Next.js + Vercel (Edge CDN)
WordPress 6.x + Elementor Pro
Database
Supabase PostgreSQL (Sao Paulo, RLS)
MySQL (Kinsta, fragmented across plugins)
Access Control
Database-level RLS + JWT + 3-layer
Plugin-dependent (MemberPress incompatible with Multisite)
Data Portability (LGPD Art. 18)
API endpoint (CSV/JSON), unified schema
Custom queries across 5+ plugin tables
Ongoing Maintenance
Low (managed services, fewer dependencies)
High (WP core + 6 plugins, update conflicts)
PROPOSED ARCHITECTURE

Modern Stack: Next.js + Supabase

TECHNICAL PROPOSAL

An architecture where each component is selected for LGPD compliance, data ownership, and long-term scalability. ATFX would control the full stack — from database schema to payment flow to data export APIs.

Layer
Technology
Detail
Frontend
Server Components, Edge CDN via Vercel
CMS
Headless, API-first content management
Database
Sao Paulo region, RLS, Realtime, unified schema
Authentication
JWT + OAuth, session management
Payments
PIX, Boleto, cards — inline checkout, no redirects
Video Storage
Sao Paulo region, 15-min signed URLs
Security Model
JWT + RLS + API route re-verification

System Architecture

┌──────────────────────────────────────────────┐ │ BROWSER / CLIENT │ │ Next.js + React (PT-BR Interface) │ └──────────────────────────────────────────────┘ ↓ ┌──────────────────────────────────────────────┐ │ VERCEL EDGE (Next.js App Router) │ │ /api/auth/* | /api/payments/* | Middleware │ └──────────────────────────────────────────────┘ ↓ ↓ ↓ ┌────────┐ ┌──────────┐ ┌──────────┐ │ CLERK │ │ PAYLOAD │ │ STRIPE │ │ JWT │ │ CMS │ │ API │ └────────┘ └──────────┘ └──────────┘ ↓ ↓ ↓ ┌──────────────────────────────────────────────┐ │ SUPABASE (São Paulo - LGPD) │ │ ├─ users, courses, enrollments │ │ ├─ payments, audit_log │ │ └─ Row-Level Security (RLS) │ └──────────────────────────────────────────────┘ ↓ ↓ ↓ ↓ ┌──────┐┌──────┐┌──────┐┌────────┐ │ GCS ││Redis ││Resend││Sentry │ │Video││Cache ││Email ││Monitor │ └──────┘└──────┘└──────┘└────────┘

Payment Flow (Stripe Elements — inline)

Browser → POST /api/payments/create-intent ↓ Clerk JWT verification ↓ Query Supabase for course price ↓ Create Stripe Payment Intent (BRL, PIX/Boleto) ↓ Return client_secret to frontend ↓ Render Stripe Elements (custom payment form) ↓ User fills PIX/Boleto details via Elements ↓ POST /api/payments/confirm-intent ↓ stripe.confirmPayment() processes payment ↓ Stripe webhook → /api/webhooks/stripe ↓ Supabase inserts: payments + enrollments + audit_log ↓ Resend sends receipt email (PT-BR) ↓ ✅ Redirect to /courses/[id]/watch
COMPLIANCE

LGPD Compliance

DATA SOVEREIGNTY

Brazil's LGPD (Lei 13.709/2018) requires any platform processing personal data of Brazilian citizens to guarantee data residency, explicit consent, and portability rights. Both architecture options can achieve compliance, but the implementation path and long-term maintenance differ. Below is how the Modern Stack addresses each requirement.

LGPD Requirement
Modern Stack
Data Residency
Supabase Sao Paulo region (native)
Access Control
Database-level RLS (Row-Level Security)
User Consent
Custom consent flow (granular, per-purpose)
Data Export (Art. 18)
Dedicated API endpoint (CSV/JSON), unified schema
Security Updates
Managed (Vercel + Supabase), zero plugin dependencies
Audit Trail
Native audit_log table with consent versioning
LGPD Implementation Checklist
  • +Legal basis for data collection (user consent on signup)
  • +Data stays in Brazil (Sao Paulo region hosting)
  • +Collect only necessary data (no excessive tracking)
  • +User rights honored (export, correct, delete data)
  • +Encrypted access, automatic logging, data isolation
  • +Privacy policy page in PT-BR
  • +Payment via Stripe (PCI DSS Level 1 compliant)
Pending Decisions & Governance
DPO (Data Protection Officer)Define internal responsible or hire external
DPA with Clerk (Data Processing Agreement)Sign on Pro plan or evaluate alternative
Legal documents in PT-BRPrivacy Policy, Terms of Use, Cookie Policy
PIX payment method (Stripe Brazil)Verify activation and webhook flow
Staging environmentSupabase BR staging + Clerk staging + Stripe test
PRICING

Monthly Cost Projection

ESTIMATED

Costs are approximate and usage-based. Stripe charges 2.9% + $0.30 per transaction (not included in monthly totals). Stripe Brazil supports PIX, Boleto, and credit cards.

Modern Stack

Estimated Monthly Total~$100 - $175
Estimated Migration Cost (if architecture change is needed later)

If the initial architecture requires a full rebuild due to access control or compliance limitations:

$25,000 – $40,000+ 6–8 months delay
ROADMAP

Implementation Roadmap

LAUNCH PLAN
MODERN STACK
8 weeks to production
Phase 1
Infrastructure & Platform Setup
Cloud infra deployed, DB created, auth configured
Phase 2
User Registration & Content Publishing
First course published, student registration live
Phase 3
Payment Processing & Course Access
End-to-end purchase flow tested, refunds working
Phase 4
Student Profiles & Marketing Site
Public catalog live, profiles editable
Phase 5
Compliance, Testing & Launch
LGPD audit passed, monitoring active, go-live
Reference:

6 Functional Modules

Module 1 — Identity

User signs up via Clerk -> Clerk webhook -> Supabase Edge Function creates user row -> Resend sends welcome email

Clerk + Webhook + Supabase Edge Function
Browser
  ↓
User submits signup form (email, password)
  ↓
Clerk.users.create()
  ↓
Clerk webhook triggered
  ↓
Supabase Edge Function receives webhook
  ↓
INSERT INTO users table
  ↓
Resend API: send welcome email
  ↓
✅ User authenticated (JWT issued)
Module 2 — Content

Admin logs into Payload CMS -> Creates course -> Uploads media directly to GCS via Signed URL -> Payload saves metadata + calls revalidateTag on Next.js

Payload CMS + GCS + Signed Upload URLs
Admin Portal
  ↓
Payload CMS (headless)
  ↓
Admin creates course → uploads video
  ↓
Signed URL generator (GCS)
  ↓
Upload directly to GCS bucket
  ↓
Payload saves metadata
  ↓
revalidateTag() on Next.js
  ↓
✅ Course published + cached
Module 3 — Payments

User clicks Buy -> API route reads price from Supabase -> Creates Stripe Payment Intent -> Stripe processes payment -> Webhook confirms -> Purchase row created -> Realtime notifies frontend

Stripe Payment Intent + Webhook + Supabase Realtime
Frontend
  ↓
User clicks "Comprar Curso"
  ↓
POST /api/payments/create-intent
  ↓
Verify JWT + Query Supabase price
  ↓
stripe.paymentIntents.create()
  (amount, currency: BRL, PIX/Boleto)
  ↓
Return client_secret to frontend
  ↓
Render Stripe Elements inline
  ↓
User pays via PIX QR or Boleto (stays on platform)
  ↓
Stripe webhook confirmation
  ↓
✅ Order recorded in Supabase
Module 4 — Access Control

Layer 1: Clerk JWT verification -> Layer 2: Next.js middleware checks purchase in Supabase -> Layer 3: API route re-verifies -> Generates 15-min Signed URL

Clerk + Next.js Middleware + GCS Signed URLs
Request → middleware.ts
  ↓
Layer 1: Verify Clerk JWT token
  ↓
Layer 2: Check course enrollment in Supabase RLS
  ↓
Layer 3: Re-verify in API route
  ↓
Generate 15-min signed URL (GCS)
  ↓
Return video stream URL
  ↓
Browser plays video
  ↓
✅ Access granted for enrolled users only
Module 5 — Profile

User updates name/bio (Supabase UPDATE). Avatar: API route deletes old file -> uploads new to GCS -> updates avatar_url. If upload fails, previous avatar preserved.

Supabase UPDATE + GCS
User dashboard
  ↓
Edit profile (name, bio)
  ↓
POST /api/profile/update
  ↓
UPDATE users table (Supabase)
  ↓
Avatar upload? → Delete old GCS file
  ↓
POST to GCS (signed URL)
  ↓
UPDATE avatar_url in Supabase
  ↓
If upload fails → Rollback to previous
  ↓
✅ Profile synced
Module 6 — Landing

Separate project (Elementor/Next.js static). Uses Supabase anon key to read published courses only. RLS ensures anon key accesses only public fields.

Elementor (WordPress) + Supabase RLS
Public landing page
  ↓
Load separate Next.js project
  ↓
Use Supabase anon key
  ↓
Query published courses
  ↓
RLS policy: anon key → public fields only
  ↓
Display course catalog
  ↓
SEO optimized (Open Graph, Schema.org)
  ↓
✅ Public-facing course list

System Architecture

3 independent projects + cloud services

PROJECTS
Student App (Next.js)Vercel Edge
Next.js 15 + React
Student registration, course catalog, purchase, content access
Admin CMS (Payload)Vercel / Railway
Payload CMS 3.0
Course creation, media upload, admin management
Public LandingWordPress Hosting
Elementor (WordPress)
Marketing only — fetches public course data from Supabase via anon key. No auth, no payments, no user data stored in WordPress.
CLOUD SERVICES
Service
Role
Region
Supabase
Database + RLS + Realtime
São Paulo, BR
Clerk
Authentication + JWT + OAuth
Cloud
Stripe
Payments (PIX, Boleto, Cards)
Brazil
GCS
Private media storage
southamerica-east1
Upstash Redis
Rate limiting
Brazil

Critical Flows

Purchase Flow
1. User clicks Buy → API route reads price from Supabase (server)
2. API creates Stripe Payment Intent → returns client_secret
3. Stripe processes payment → sends webhook payment_intent.succeeded
4. Edge Function verifies signature → creates purchase row (status=completed)
5. Supabase Realtime notifies frontend → course unlocked
Access Control (3-Layer)
Layer 1: Clerk middleware → verifies JWT + authenticated user
Layer 2: Next.js middleware → queries Supabase for completed purchase
Layer 3: API route → re-verifies access before generating Signed URL
Layer 4: Signed URL expires in 15 minutes

Security Best Practices

Area
Detail
Never Trust Frontend
All prices, access validation, and business logic run on server.
Webhook Signature Verification
All webhooks (Stripe, Clerk) verify signature with svix before processing.
Temporary Signed URLs
All course media served via GCS Signed URLs with 15-minute expiration.
RLS on All Tables
Row-Level Security on all Supabase tables. Users access only their own data.
Rate Limiting
Payment Intent: 5 req/min. Signed URLs: 20 req/min per user.

Testing Strategy

Type
Tool
Scope
Unit Tests
Jest + React Testing Library
Component rendering, utility functions
Integration Tests
API routes + Database
Payment Intent creation, Webhook processing, Purchase flow
E2E Tests
Playwright
Full user journey: signup -> purchase -> access content
Load Testing
k6 or Artillery
Stripe webhook processing under load

Deployment Checklist

  • +All env vars configured in Vercel
  • +Supabase RLS policies tested and verified
  • +Stripe webhook endpoint configured for production
  • +Clerk webhook endpoint configured for production
  • +GCS private bucket + CORS configured
  • +Rate limiting verified (Upstash Redis)
  • +Sentry DSN configured for error monitoring
  • +Custom domain configured in Vercel + DNS verified
  • +Full E2E test suite passing before deploy

Acceptance Criteria (MVP Ready)

  • 01User can register via Clerk -> Supabase row created
  • 02Admin can create course in Payload -> uploads to GCS -> appears in catalog
  • 03User can purchase course via Stripe -> webhook confirms -> access unlocked
  • 04Only users with completed purchase can access content (3-layer verification)
  • 05Signed URLs for media expire after 15 minutes
  • 06All Brazilian user data resides in Sao Paulo region
  • 07RLS policies enforced on all tables
  • 08Webhook signature verification for Stripe + Clerk
  • 09Rate limiting: 5 req/min Payment Intent, 20 req/min Signed URLs
  • 10E2E test passes: full user journey from signup to content access

Post-Launch Monitoring

Metric
Tool
Target
Error Rate
Sentry
<1%
Webhook Success Rate
Stripe + Clerk
>99%
Purchase Completion Rate
Stripe
Track funnel
Signed URL Generation
API routes
<200ms p95
Page Load Time
Vercel Analytics
LCP <2.5s

Scenario A: MVP Scope (WordPress has these + more)

Multi-language SupportMVP is PT-BR only. Future: i18n via next-intl
Course Progress TrackingMVP: access yes/no only. Future: per-module tracking
CertificatesMVP: none. Future: PDF on completion
Discussion ForumsMVP: none. Future: per-course boards
Live ClassesMVP: pre-recorded only. Future: Zoom integration