Case Study — Solo Full-Stack Rebuild

RadioPaint

One domain model, one entitlement engine, one real payment flow — rebuilt end to end, backend and frontend, without ever taking the live site down to get there.

Role — Solo Full-Stack Engineer, Systems Architecture Period — 2025–2026 Status — Live Stack — C# · ASP.NET Core · React · SQL Server
01 — The Brief

An art school outgrows its own scaffolding

RadioPaint started life as a bare-bones DIY site builder bundled with a bank's own CMS platform — enough to take a payment, nothing close to what the studio's founder actually needed. I volunteered to architect and build a real platform for her, from scratch, to support where she wanted to take the business: live mentored residencies, a proper commerce and admissions engine, secure video hosting, and a portfolio system her own students could point a gallery or curator to.

The project ran long enough that it went through several full rewrites as the business's ambitions grew alongside it. By the time I sat down to consolidate everything, the studio had a real, working business running on infrastructure that had quietly drifted from itself — SQL tables that no longer matched the C# models reading them, a React frontend built and fully mocked against a backend contract that didn't exist yet, secure video with three stacked half-designs never wired together, and a checkout endpoint that computed its total from whatever price the client happened to send it.

The fragmented, five-app state a later audit turned up wasn't inherited from anyone — it was my own earlier iterations.

None of it was hypothetical. Real applications, real event registrations, and real payments already existed and had to survive the rebuild, alongside the 300+ residents who already had working dashboards.

02 — In Numbers

What the rebuild actually shipped

459
passing backend tests
~215 / 10
frontend↔backend contracts reconciled, across 10 bounded domains
7
Architecture Decision Records
300+
residents kept live through the entire rebuild
03 — Five Pieces

The systems, gallery-labeled

Fig. 01

Domain-Driven Commerce & Entitlement Engine

Chain of Responsibility · State · T-Bank webhooks

Modeled every sellable shape — Residency (Sparta/Light), Course, Seance, Basic Course — as one Grant-based entitlement waterfall instead of scattered access checks, and closed a real P0 gap where checkout trusted a client-submitted price outright.

  • ShoppingCart/Order rebuild: pending carts as real rows, one Order row per cart mutated in place by T-Bank webhooks — never an append-only ledger
  • Server-side re-pricing on every checkout — no line item is ever trusted from the client
  • Unified Grant model replacing parallel Subscription/UserContentGrant tables, with a first-match-wins access chain
Fig. 02

Sparta Admissions & Residency Lifecycle

State machine · Offer Windows

Built the gatekept admissions funnel the studio actually runs on: applications, personalized decisions, time-boxed discounted offers, and an exactly-one-active-residency lifecycle — reconciled field-for-field against contract tests already written for this exact behavior.

  • Application → Decision (reject / accept-full / accept-discounted / accept-free) → time-boxed Offer Window → real T-Bank checkout → Grant
  • Residency lifecycle: one active Sparta/Light pair at a time, auto-archiving the previous cycle on publish
  • Guest Purchase + unexpiring Claim Link — buying a seat for someone else without ever needing their email up front
Fig. 03

Secure Video & Media Pipeline

Proxy · Caddy forward_auth · S3

Replaced three half-built streaming designs stacked on top of each other with one real pipeline: per-user signed tokens, a reverse proxy that fully masks the storage bucket, and dedicated worker containers for transcode and image processing.

  • Token-issuing stream service and manifest rewriter that builds proxy-domain URLs from the video's storage key — no raw bucket hostname ever reaches the client
  • Dedicated transcode and image-processing worker containers, each polling its own job queue independently of the web app
  • Entitlement check on every manifest request — authenticated and subscribed/granted, not just logged in
Fig. 04

Data Migration & Production Hygiene

Template Method · CSV bulk import

Reconciled a production schema that had drifted mid-refactor from the domain model reading it, then built a real migration path for the studio's existing business — real applicants, real registrants, real payments — onto the corrected schema.

  • Hand-rolled CSV import pipeline routing every historical row through the same live business rules a real user action would trigger — capacity checks and grant issuance included, never bypassed
  • Mechanical domain/repository realignment after independent schema drift, verified with zero live database access via static cross-reference and full compilation
  • Closed a real IDOR on application submission and swept every bare authorization attribute onto real permission-claim policies
Fig. 05

Storefront, LMS Dashboard & Artist Portfolio

React · Vite · JWT session

Built the public storefront, gallery, and resident dashboard as a content-driven SPA — every pixel of the studio founder's own layout and typography locked, every piece of content swappable through data files instead of a code change. Doubles as a public portfolio system: approved work and a CV/BIO surface on a real, shareable profile page.

  • Bento-grid public gallery with author/theme/medium/availability filtering, shopping cart, and guest-to-account cart merge on login
  • Resident dashboard: residency/course timeline, personal gallery with an instructor feedback inbox, CV/BIO portfolio builder, prompt generator with saved presets
  • JWT-decoded client-side session wired end-to-end against the real Identity backend — login, register, password reset, sign-out-everywhere
04 — Architecture

A backend-for-frontend, not a public API

The API is a dedicated Backend-for-Frontend: one surface shaped specifically around the React SPA's own screens — checkout, admissions, admin CRUD, gallery, auth — not a general-purpose public API serving unrelated clients. It sits as a Facade over the Application and Infrastructure layers beneath it, backed by raw ADO.NET against a single SQL Server instance, deliberately with zero ORM.

Presentation
React SPA — design-frozen storefront, gallery, dashboard
Session — client-decoded JWT, no whoami call
↓
API — Backend-for-Frontend
Facade — minimal API groups + controllers, composition root
Identity — JWT issuance, revocable refresh tokens
Rate limiting — fixed-window on auth & checkout
↓
Application (Business Logic)
Chain of Responsibility — GrantService entitlement walk
Observer + Command — domain event pub-sub, durable queue
↓
Infrastructure
Repository — raw ADO.NET behind a Facade, no ORM
Command queues — video transcode / image workers, own containers
↓
Data
SQL Server — single source of truth, DBA-editable DDL
External Services
  • Caddy — Proxy; masks storage, validates stream tokens via forward_auth
  • AWS S3 — video, manifests, gallery images
  • T-Bank / Robokassa — checkout, receipts, webhooks
05 — Materials & Methods

Patterns, named plainly

Facade (BFF) Chain of Responsibility Observer Command Repository State Proxy Template Method
06 — A Walkthrough

What it feels like end to end

Persona — Vika, a self-taught painter

She wants real mentorship and a portfolio she can point a gallery to.

Vika submits a Sparta application with her portfolio and motivation letter. The studio's founder reviews it and sends a personalized, discounted offer with a three-day window to accept. Vika pays through a real T-Bank checkout and is inside her dashboard within minutes.

Through the residency's live sessions she gets direct, real-time feedback from her mentor and works alongside the same cohort of peers week over week; between sessions she uploads new pieces and requests written feedback the same way Light-format residents do async. Once a piece is approved, it surfaces on her public artist profile — a real portfolio page with her bio, CV, and gallery she can point a curator or exhibition organizer to directly, not just a private class folder.

What this replaced

  • A payment gateway that actually confirms, not a promise to invoice later
  • Real-time mentor feedback in Sparta, async written feedback in Light
  • A public artist profile doubling as a real portfolio, not an internal record
  • Video that can't be scraped — every stream is a per-user, time-bound token