Skip to main content

Platform Architecture

Overview

This article provides the complete architectural blueprint for the uzdavines.ai platform -- a monorepo containing three independently deployed web applications unified by shared infrastructure, a consistent design language, and automated CI/CD pipelines.

  • Why it matters: Understanding the platform's architecture is essential for making informed decisions about development, deployment, and scaling. This document serves as the single source of truth for how the system is structured and why.
  • What you will learn: The application stack and framework choices, DNS and hosting configuration via Cloudflare and Render, the CI/CD deployment pipeline, monorepo directory structure, and the shared design language across all applications.

The uzdavines.ai platform is built as a monorepo with three independently deployed applications, unified by shared infrastructure and a consistent design language.

High-Level Architecture

                         ┌─────────────────────────┐
│ Cloudflare DNS │
│ (Proxy + SSL/TLS) │
└────┬─────┬─────┬────────┘
│ │ │
┌───────────┘ │ └───────────┐
│ │ │
v v v
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Homepage │ │ Docs │ │ API │
│ (Render │ │ (Render │ │ (Render │
│ Web Svc) │ │ Static) │ │ Web Svc) │
└──────────────┘ └─────────────┘ └──────────────┘
uzdavines.ai docs.uzdavines api.uzdavines
.ai .ai

Application Stack

ApplicationFrameworkRender TypeKey Features
HomepageNext.js + Tailwind CSSWeb Service (SSR)AI chatbot, scroll-snap sections, /coffee + /resume routes
DocsDocusaurus + TypeScriptStatic SiteKnowledge base, dual-tier content
APIExpress (Node.js)Web ServiceOTP-gated private docs (email + JWT)

The interactive resume (with the Pierre chatbot) is served by the homepage app at uzdavines.ai/resume. It previously had its own apps/resume app and resume.uzdavines.ai subdomain; that was retired in favor of the /resume route.

Why SSR for the Homepage?

The homepage requires server-side rendering because it includes API routes (/api/chat, /api/pierre) that proxy requests to the Claude API — the API key must stay server-side.

Why Static for Docs?

Docusaurus generates static HTML/CSS/JS at build time. No server-side logic is needed — the content is pre-rendered and served directly.

Infrastructure

DNS and CDN — Cloudflare

uzdavines.ai          CNAME --> Render homepage service
docs.uzdavines.ai CNAME --> Render docs service
api.uzdavines.ai CNAME --> Render API service
  • SSL/TLS mode: Full
  • Proxy status: Proxied (after Render TLS cert validation)
  • Cloudflare handles DNS resolution, CDN caching, and SSL termination

Hosting — Render

Each application is deployed as a separate Render service. Auto-deploy is disabled — deployments are triggered by GitHub Actions via deploy hooks.

CI/CD — GitHub Actions

Path-filtered workflows ensure only the affected application is built and deployed when changes are pushed to main.

Push to main

├── apps/homepage/** changed? --> deploy-homepage.yml
├── apps/docs/** changed? --> deploy-docs.yml
└── apps/api/** changed? --> deploy-api.yml

Monorepo Structure

uzdavines-platform/
├── apps/
│ ├── homepage/ # Next.js — uzdavines.ai
│ │ ├── src/app/ # App router pages
│ │ │ ├── api/chat/ # AI chatbot API route
│ │ │ ├── coffee/ # Cloud City Roasters page
│ │ │ ├── resume/ # Interactive resume + Pierre chatbot
│ │ │ ├── layout.tsx # Root layout
│ │ │ └── page.tsx # Homepage
│ │ ├── public/ # Static assets
│ │ └── package.json
│ │
│ ├── docs/ # Docusaurus — docs.uzdavines.ai
│ │ ├── docs/ # Public Markdown docs (Tier 1)
│ │ ├── static/ # Static assets
│ │ │ └── private/ # Hidden docs (Tier 2)
│ │ ├── src/css/ # Custom styling
│ │ └── package.json
│ │
│ └── api/ # Express — api.uzdavines.ai
│ ├── src/ # Routes, middleware, lib
│ │ └── routes/ # OTP: access, chat, otp
│ └── package.json

├── packages/
│ └── shared/ # Shared utilities

├── .github/
│ └── workflows/ # CI/CD pipelines
│ ├── deploy-homepage.yml
│ ├── deploy-docs.yml
│ ├── deploy-api.yml
│ ├── pr-check-homepage.yml
│ ├── pr-check-docs.yml
│ └── pr-check-api.yml

└── package.json # npm workspaces root

Design Language

All applications share a consistent visual identity:

AspectStandard
Color paletteMonochrome (black, white, grays) + dark navy (#0a1628 → #1a2744)
ModeDark mode default
TypographyPlus Jakarta Sans
LayoutMobile-first
AestheticSleek, professional, modern, understated