← WorkCase Study — Client Engagement

PROTESAFrom website to platform

Next.js 15React 19SupabasePostgreSQLStrapi CMSTailwind 4Framer MotionTypeScript
protesacr.com
01
The Client

An electrical protection company that needed more than a brochure

Protesa is an electrical protection and technology company in Costa Rica. The engagement started as a corporate website — services, company story, and a product catalog backed by a Strapi CMS with filtering, search, and pagination.

It didn't stay a website. As trust built, the scope grew: first a full brand redesign, then an entire private learning platform for training on electrical protection — designed, built, and shipped inside the same codebase.

Client WorkB2BCosta RicaElectrical Engineering
02
The Redesign

From generic to industrial-tech

The original site read as template-built: lime gradients, glassmorphism cards, floating particles — and structural problems underneath. No real font ever loaded, the brand green didn't match the logo, and the HTML declared English on a fully Spanish site.

The redesign rebuilt the foundation as a design system: CSS design tokens, the true logo green (#588e19) with its yellow bolt accent as precise solids instead of gradients, Space Grotesk and Inter loaded via next/font, a “power-on” loading animation, and motion only where it adds meaning. Clean industrial-tech — the way a B2B engineering company should feel.

Design SystemTypographyBrandFramer Motion
03
The Academy

A private learning platform inside the site

Protesa Academy is an invite-only, Udemy-style LMS living at /academia. Instructors publish video courses and configurable tests, students take randomly assembled evaluations and track their grades, and a super-admin manages accounts and platform settings. All UI in Spanish, shipped only when complete.

Courses

Video courses & lessons

Instructors publish courses of video classes through a two-pane editor — content on the left, settings on the right — with readiness badges showing what a course still needs before publishing.

Test Engine

Randomized evaluations

Each course has a shared question bank. Every attempt assembles a fresh random test with configurable question counts, time limits, and retry rules.

Roles

Three portals, invite-only

Admin, instructor, and student portals in one app. Public signup is disabled — accounts exist only through email invites with password setup.

Results

Grades & attempt history

Students review their own grades and past attempts; instructors and admins get per-course results dashboards.

04
System Design

One frontend, two backends

The Academy runs on Supabase — Auth, Postgres with Row Level Security, and Storage — while the product catalog stayed on the existing Strapi CMS. Pages are guarded server-side, and Next.js API routes holding the service-role key exist only for admin operations, always gated on the caller's role.

Client
Corporate sitepublic
Product catalogpublic
Academyinvite-only
App layer
Next.js 15 (Pages Router)getServerSideProps session guards
API routes (service role)admin ops only, role-gated
Academy backend
Supabase Authinvite-only
Postgres + RLSSECURITY DEFINER RPCs
Storagecourse videos
Catalog backend
Strapi CMSapi.protesacr.com
ClientThree surfaces in one codebase — public site, product catalog, and the private Academy.
App layerPages are protected server-side via getServerSideProps; the service-role key never reaches the client.
Academy backendThe LMS security model lives in Postgres: RLS for isolation, SECURITY DEFINER RPCs for the sensitive paths.
Catalog backendProducts stayed on the existing Strapi instance — no migration, no rewrite.
05
Tech Deep-Dives

Four decisions worth talking about

The LMS security model was the interesting problem. These were the decisions that mattered.

SecurityDatabase-level test integrity

Students must never see correct answers, other students’ data, or bypass timers and retry limits. That is enforced in Postgres — RLS policies plus SECURITY DEFINER functions — not in untrusted browser code.

AuthInvite-only accounts

Supabase public signup is disabled entirely. Roles are read exclusively from server-controlled app_metadata, so a public caller can never choose their own role.

TestingRandom per-attempt assembly

Tests are assembled at attempt time by a Postgres RPC that draws from the per-course question bank — each attempt gets a different test, with per-test question counts set by the instructor.

ArchitectureTwo backends, zero migration

The product catalog stayed on the existing Strapi CMS while the Academy was built on Supabase alongside it. Each system owns its domain; nothing was rewritten.

06
Outcome

Shipped through real UAT cycles

The Academy was delivered iteratively against real client feedback — multiple UAT fix batches, instructor-authoring UX revisions, and auth-flow hardening — and is live in production for a real company, alongside the redesigned site and catalog.

3Roles & portals — admin, instructor, student
10+Postgres migrations, RLS-first schema
LiveIn production at protesacr.com
protesacr.com — live