# Platform Deep Dive

Everything under the hood — and why it's there.

By AgentSite · Updated 2026-05-23

## The Platform

This isn't a boilerplate. It's a production-grade SaaS foundation built from years of shipping real products — every layer deliberate, every pattern battle-tested. Here's everything under the hood.

* * *

## Architecture Overview

External

Data

Application

Edge

Client

Vue 3 SPA

Service Worker

CDN / Static Assets

Load Balancer

NestJS API Server

WebSocket Gateway

Mastra AI Agents

Scheduled Jobs

PostgreSQL

Redis - Sessions

Stripe Billing

SendGrid Email

Google OAuth

Uploadcare CDN

* * *

## Authentication & Identity

Four auth strategies, zero compromise. Every path leads to a secure JWT session stored in HTTP-only cookies — not localStorage, not session tokens in headers. Cookies. Because the browser's built-in security model is better than anything we'd build.

Protected

Auth Pipeline

Entry Points

Magic Link Email

Password + Argon2

Google OAuth

Ghost Mode

Validate Credentials

Sign JWT

Set HTTP-Only Cookie

Create Session

AuthGuard

Role Check

API Access

**Magic Links** — Passwordless login. User enters email, gets a signed token link, clicks it, done. No password to forget, no credential stuffing to worry about. The token is single-use, time-limited, and tied to the requesting IP.

**Password Auth** — Argon2id hashing. Not bcrypt, not SHA-256. Argon2id — memory-hard, GPU-resistant, winner of the Password Hashing Competition. Password reset flows with signed tokens, not security questions.

**Google OAuth** — One-click sign-in with automatic account linking. If the email already exists, it links. If not, it creates. No friction, no "which account did I use?" confusion.

**Ghost Mode** — Development and demo sessions without real accounts. Perfect for trade shows, investor demos, or automated testing. Full platform access with a synthetic identity that self-destructs.

**Role-Based Access** — Three decorator-driven authorization levels: `@Public()` (no auth), `@RequireAuth()` (any authenticated user), `@RequireEdit()` (admin/editor). Applied at the controller method level. No middleware chains to debug.

* * *

## Database Philosophy

### Flyway Over ORMs

We use Flyway for migrations. Not TypeORM migrations, not Knex migrations, not Prisma migrations. Flyway.

Why? Because database migrations are **SQL**. They should be written in SQL, reviewed as SQL, and executed as SQL. ORM-generated migrations are a leaky abstraction — they guess what you want, generate bloated DDL, and break in ways that are hard to debug.

Guarantees

Migration Pipeline

Developer writes SQL

Versioned file: V01\_\_description.sql

Flyway validates + applies

PostgreSQL

flyway\_schema\_history table

Strict ordering

Checksum verification

Repeatable migrations

Full audit trail

Every migration is a versioned `.sql` file: `V01__create_users.sql`, `V02__add_billing_tables.sql`. Flyway checksums them — if someone modifies a migration that already ran, deployment fails. Loudly. That's a feature.

The result: migrations that are readable, auditable, and identical across every environment. No ORM version drift. No "works on my machine."

### TypeORM for Application Code

TypeORM handles the application layer — entity mapping, query building, repository pattern. But it doesn't touch the schema. Clean separation: SQL owns the structure, TypeORM owns the access.

**Snake case everywhere.** A `NamingStrategy` maps TypeScript's `camelCase` properties to PostgreSQL's `snake_case` columns automatically. No `@Column({ name: 'user_id' })` decorators cluttering entity files.

**Entities are simple.** No active record pattern, no lifecycle hooks on entities, no magic. An entity is a typed row. Services contain the logic.

* * *

## Entity System

has

has

has

has

has

has

references

parent

receives

User

string

id

PK

string

email

string

name

string

role

string

status

Membership

string

id

PK

string

userId

FK

string

orgId

FK

string

role

Session

Profile

Organization

string

id

PK

string

name

string

slug

string

domain

Subscription

BillingCustomer

Plan

Content

string

id

PK

string

slug

string

title

string

type

string

status

jsonb

metadata

text

data

Form

string

id

PK

string

title

jsonb

schema

string

status

FormResponse

Every entity ID is generated with **ashid** — prefixed, collision-resistant, sortable identifiers. `usr_abc123`, `org_def456`, `cnt_ghi789`. You can look at an ID and know what it is. Grep a log file and find every user mention. No UUIDs, no auto-incrementing integers leaking your row count.

* * *

## Billing & Subscriptions

Full Stripe integration — not a wrapper, not a "billing microservice." Direct Stripe API usage with webhook-driven state management.

**Checkout Sessions** — Not custom payment forms. Stripe Checkout handles PCI compliance, 3D Secure, Apple Pay, Google Pay, and every edge case we'd never think to handle.

**Webhook-Driven** — Subscription state is never polled. Stripe tells us when something changes. `invoice.paid`, `customer.subscription.updated`, `customer.subscription.deleted` — each one triggers precise state transitions.

**Plan Enforcement** — Middleware checks subscription status on protected routes. Expired? Graceful degradation, not a brick wall. Usage limits? Tracked per-organization with clear upgrade paths.

* * *

## Admin Dashboard

A full admin panel at `/admin` with granular control over every entity in the system. Not a bolted-on afterthought — it's built with the same component library (NaiveUI) and shares the same API layer.

**What's in the admin:**

-   **User Management** — Search, filter, view activity, impersonate, suspend, change roles
-   **Organization Management** — View members, subscription status, usage metrics
-   **Content Editor** — WYSIWYG markdown editing with live preview, draft/publish workflow
-   **Form Builder** — Dynamic form creation with schema-driven fields
-   **Billing Overview** — Subscription status across all organizations, revenue metrics
-   **System Health** — Active sessions, error rates, webhook delivery status

Every admin action is audit-logged. Who did what, when, to what entity. Not optional, not configurable — always on.

* * *

## Content Management System

A file-based CMS that syncs markdown files to the database on startup. No headless CMS vendor, no API rate limits, no monthly fees.

flowchart LR subgraph File System MD1\[content/about.md\] MD2\[content/blog/post-1.md\] MD3\[content/platform.md\] end subgraph ContentSyncService PARSE\[Parse YAML Frontmatter\] MERGE\[Date-Based Merge\] SYNC\[Upsert to DB\] end subgraph Database CT\[(Content Table)\] end subgraph Delivery API\[GET /content/:slug\] VUE\[Markdown Component\] MERMAID\[Mermaid Renderer\] end MD1 --> PARSE MD2 --> PARSE MD3 --> PARSE PARSE --> MERGE --> SYNC --> CT CT --> API --> VUE --> MERMAID

**Date-Based Merge** — File wins only if its date is newer than the database record. Edit content in the admin panel? Those changes stick until the file is explicitly updated. No accidental overwrites.

**YAML Frontmatter** — Standard metadata: slug, title, type, status, date. Arbitrary metadata in a nested object for flexibility.

**Mermaid Diagrams** — Fenced code blocks with `mermaid` language tags render as interactive SVG diagrams. Architecture charts, flow diagrams, sequence diagrams — all in markdown.

**Admin Editing** — Content synced from files can also be edited through the admin CMS. The merge strategy ensures neither side clobbers the other.

* * *

## Frontend Architecture

### Component System

Vue 3 with TypeScript, class-based components via `vue-facing-decorator`, and auto-imported components via `unplugin-vue-components`. Write a component, use it anywhere — no import statements needed.

graph TB subgraph Build Pipeline VITE\[Vite Dev Server\] TW\[Tailwind CSS v4\] AUTO\[Auto Component Import\] SVG\[SVG Loader\] PAGES\[File-Based Routing\] LAYOUTS\[Layout System\] end subgraph Component Layers NAIVE\[NaiveUI Primitives\] SHARED\[Shared Components\] PAGE\[Page Components\] end subgraph Patterns DEC\[Class Decorators\] PROPS\[@Prop / @Watch\] EMIT\[@Emit\] API\[ApiCore Composable\] end VITE --> TW VITE --> AUTO --> NAIVE VITE --> SVG VITE --> PAGES VITE --> LAYOUTS NAIVE --> SHARED --> PAGE DEC --> PROPS --> EMIT --> API

### File-Based Routing

No router configuration files. Drop a `.vue` file in `src/pages/`, it becomes a route. `pages/about/index.vue` → `/about`. `pages/settings/billing.vue` → `/settings/billing`. Nested layouts, dynamic segments, route meta — all from file conventions.

### Design Token System

CSS custom properties mirrored in TypeScript. Change a color in one place, it updates across CSS, Tailwind utilities, NaiveUI theme overrides, and Storybook simultaneously.

```typescript
// design-tokens.ts — single source of truth
export const colors = {
  brand: {
    primary: 'var(--color-brand-primary)',     // #11203C
    accent: 'var(--color-brand-accent)',        // #DDDAC0
    secondary: 'var(--color-brand-secondary)',  // #0e7490
  },
  ui: {
    bgPrimary: 'var(--ui-bg-primary)',         // #09090b
    textPrimary: 'var(--ui-text-primary)',      // #fafafa
  }
} as const
```

### Tailwind CSS v4

No `tailwind.config.js`. Tailwind v4 uses CSS-native configuration with `@theme` blocks. Custom utilities defined with `@utility`. A Vite plugin auto-injects `@reference` directives into Vue style blocks — Tailwind utilities work everywhere without manual imports.

### Rich Text Editing

Tiptap editor with markdown import/export via `tiptap-markdown`. Supports images (Uploadcare CDN), links, text alignment, subscript/superscript, character counts, and placeholder text. Content stored as markdown, rendered as HTML.

* * *

## API Layer

### Object-Oriented First

Every service is a class. Every controller is a class. Dependency injection via NestJS's IoC container. No scattered utility functions, no "just import this helper." Services have clear boundaries, single responsibilities, and injectable dependencies.

graph LR subgraph Controllers UC\[UserController\] OC\[OrgController\] CC\[ContentController\] BC\[BillingController\] FC\[FormController\] end subgraph Services US\[UserService\] OS\[OrgService\] CS\[ContentService\] BS\[BillingService\] FS\[FormService\] ES\[EmailService\] TS\[TrackingService\] end subgraph Cross-Cutting AUTH\[AuthGuard\] LOG\[LoggDecorator\] VALID\[ValidationPipe\] ERR\[ExceptionFilter\] end UC --> US OC --> OS CC --> CS BC --> BS FC --> FS US --> ES BS --> ES US --> TS AUTH --> UC & OC & CC & BC & FC LOG --> US & OS & CS & BS & FS

### Structured Logging

The `@Logged()` decorator wraps any service method with structured logging — method name, duration, parameters, result flags. Not `console.log`. Not a logging library you have to configure. A decorator that makes every service method observable with zero boilerplate.

### API Client Pattern

Frontend API calls go through `ApiCore` — a typed Axios wrapper that handles auth headers, error normalization, pagination, and response unwrapping. One import, consistent behavior everywhere:

```typescript
const users = await api.get<User[]>('/user')
const user = await api.post<User>('/user', { name: 'Alice' })
```

* * *

## Real-Time Communication

### WebSocket Gateway

Socket.IO-based real-time channel. Authenticated connections tied to user sessions. Server-pushed events for notifications, live updates, and AI streaming responses.

### AI Agent Integration

Mastra framework for AI agent orchestration. Agents stream responses over WebSocket — not polling, not long-polling. The user sees tokens appear as they're generated.

sequenceDiagram participant U as User participant WS as WebSocket participant M as Mastra Agent participant LLM as Language Model U->>WS: Send prompt WS->>M: Execute agent M->>LLM: Stream request loop Token streaming LLM-->>M: Token M-->>WS: Push token WS-->>U: Render token end M-->>WS: Complete WS-->>U: Done

* * *

## DevOps & Deployment

### CI/CD Pipeline

GitHub Actions with a two-stage pipeline: test everything, then deploy. No manual steps, no "just SSH in and restart."

flowchart LR subgraph CI PUSH\[Git Push\] TEST\[Run Tests\] LINT\[Type Check\] BUILD\[Build Images\] end subgraph CD REG\[Push to Registry\] K8S\[Apply K8s Manifests\] MIGRATE\[Run Flyway Migrations\] DEPLOY\[Rolling Update\] HEALTH\[Health Check\] end PUSH --> TEST --> LINT --> BUILD BUILD --> REG --> K8S --> MIGRATE --> DEPLOY --> HEALTH

### Kubernetes Deployment

Production runs on Kubernetes with:

-   **Rolling updates** — Zero-downtime deployments. New pods spin up, health checks pass, old pods drain.
-   **Resource limits** — CPU and memory bounds per container. No runaway processes eating the node.
-   **ConfigMaps & Secrets** — Environment configuration without baking values into images.
-   **DigitalOcean Container Registry** — Private image storage. Images tagged with commit SHA for traceability.

### DevOps Scripts

A comprehensive `devops/scripts/` toolkit:

-   **`start-backend.sh`** — Runs Flyway migrations, then starts NestJS. Migrations always run first. Always.
-   **`local-docker-compose.sh`** — Full local stack: PostgreSQL, Redis, backend, frontend. One command.
-   **`generate-dev-env-js.sh`** — Injects environment variables into the frontend at build time without rebuilding.
-   **`repo-discovery.sh`** — Finds sibling projects using this template. Powers the update-child sync workflow.
-   **`util-diff.sh`** — Diffs a child project against the template. Shows what's customized vs. what can be synced.

* * *

## Testing Infrastructure

### Unit Tests

Jest with TypeScript via `ts-jest`. Backend services tested with real database connections — not mocks. When a test passes, it means the SQL actually works against a real PostgreSQL instance.

### End-to-End Tests

Playwright for browser automation. Full user journey tests: sign up, create content, manage billing, admin workflows. Tests run in CI against a deployed preview environment.

### Storybook

Component development and visual testing with Storybook 10. NaiveUI theme integration, accessibility auditing (`@storybook/addon-a11y`), dark/light theme switching. Every shared component has a story.

* * *

## Form System

Dynamic form builder with schema-driven rendering and AI-powered question generation.

flowchart TD subgraph Builder SCHEMA\[JSON Schema Definition\] FIELDS\[Field Types: text, select, rating, etc.\] VALID\[Validation Rules\] end subgraph Runtime RENDER\[Dynamic Renderer\] COLLECT\[Response Collection\] STORE\[FormResponse Entity\] end subgraph AI Optional TAG\[Tag-Based Context\] GEN\[AI Question Generation\] ADAPT\[Adaptive Follow-ups\] end SCHEMA --> FIELDS --> VALID --> RENDER RENDER --> COLLECT --> STORE TAG --> GEN --> ADAPT --> RENDER

Forms are stored as JSONB schemas — not hardcoded templates. Create a form through the admin, it renders automatically. Add validation rules, they enforce automatically. The entire form lifecycle is data-driven.

* * *

## Email System

SendGrid integration with template-based transactional emails. Not raw HTML strings concatenated in a service method.

-   **Magic link login** — Branded email with single-use auth link
-   **Password reset** — Time-limited token with clear expiration messaging
-   **Welcome emails** — Post-registration onboarding
-   **Notification digests** — Batched updates, not individual spam

Email templates are maintainable HTML with variable interpolation. Preview them locally before deploying.

* * *

## Tracking & Analytics

PostHog integration for product analytics with a backend `TrackingService` for server-side events. Client-side page views and interactions. Server-side conversion events, API usage metrics, and funnel tracking.

Events are typed — not arbitrary strings. A `TrackingEvent` enum ensures consistency across the codebase. No "did we call it `user_signup` or `userSignup` or `sign_up`?" confusion.

* * *

## Protocol System

Knowledge management through protocol files — executable documentation that lives alongside the code.

graph TB subgraph Protocol Types PROC\[Procedures - How to do things\] IMPL\[Implementations - How to build things\] REF\[References - Where to find things\] end subgraph Lifecycle WRITE\[Write Protocol\] PUBLISH\[Publish to API\] FETCH\[Fetch On-Demand\] EXECUTE\[Follow Steps\] end subgraph Examples SETUP\["@codebase/setup"\] UPDATE\["@codebase/update-parent"\] FEATURE\["@codebase/feature/\*"\] INNOV\["@codebase/innovations"\] end PROC --> WRITE IMPL --> WRITE REF --> WRITE WRITE --> PUBLISH --> FETCH --> EXECUTE SETUP --> PROC UPDATE --> PROC FEATURE --> IMPL INNOV --> REF

Protocols are published to an API and fetched on demand. They're not stale wiki pages — they're versioned, searchable, and used by both humans and AI agents. When you bootstrap a session, you load the protocols that matter. When you need to do something, you fetch the procedure.

* * *

## What This Adds Up To

This isn't a starter template you'll outgrow in a month. It's the infrastructure layer of a real SaaS product — authentication, billing, content, email, real-time, AI, admin, deployment, testing, and documentation. All integrated. All production-ready. All yours to build on.

Every pattern here exists because we hit the wall without it. Every architectural decision has a scar behind it. This is what years of shipping looks like, compressed into a single `git clone`.

* * *

## Further reading

The architecture above implements the technical layers of [agent readability](/agent-readability). The five-layer model the system delivers against is documented in [the five layers of AEO](/five-layer-aeo). The specific Layer-1 failure modes that drive most install conversations are catalogued in [SSR-junk and bot walls](/ssr-junk-bot-wall).