Personal website and CMS stack built with Vue 3, Payload CMS, and MongoDB, then shipped as Docker images for self-hosting on TrueNAS Scale.
The frontend is statically rendered with Vite SSG. The CMS runs separately on Next.js + Payload. The day-to-day dev loop is intentionally simple: run the frontend locally, point it at the real backend, and move quickly.
| Area | Stack |
|---|---|
| Frontend | Vue 3, TypeScript, Vite, Vite SSG |
| CMS | Payload CMS 3, Next.js 15 |
| Data | MongoDB 7 |
| Delivery | Docker, Nginx, GitHub Actions, GHCR |
.
├── src/ # Vue frontend app
├── cms/ # Payload CMS app
├── nginx/ # Nginx configs for local and production serving
├── public/ # Frontend public assets
├── .github/workflows/ # CI and deployment pipelines
└── TODO/ # Local KanStack task board
For most frontend work, use the production CMS while running the frontend locally.
npm install
npm run dev:prodThat proxies /api and /media to https://galen.green, so you get real content without needing to boot the full local stack.
Use CMS_URL to point the Vite dev proxy at any CMS instance.
CMS_URL=http://localhost:3000 npm run devUse this when you need to work on the CMS itself, local schema changes, or local content.
- Install dependencies:
npm install
npm --prefix cms install- Start MongoDB:
docker run -d --name mongodb -p 27017:27017 mongo:7- Create
cms/.envfromcms/.env.exampleand set at least:
MONGODB_URIPAYLOAD_SECRET
- Start the CMS:
npm --prefix cms run dev- Start the frontend:
CMS_URL=http://localhost:3000 npm run dev| Variable | Purpose |
|---|---|
CMS_URL |
Dev-only Vite proxy target used by npm run dev |
VITE_PAYLOAD_URL |
CMS origin used during SSR/static builds |
For local frontend builds against a local CMS:
VITE_PAYLOAD_URL=http://localhost:3000 npm run buildSee .env.example and cms/.env.example for the current variable set.
| Command | Description |
|---|---|
npm run dev |
Start Vite with the default local CMS proxy |
npm run dev:prod |
Start Vite against the production CMS |
npm run build |
Type-check and build the static frontend |
npm run build-only |
Build the static frontend without type-checking |
npm run preview |
Preview the built frontend locally |
npm run lint |
Run ESLint |
npm run type-check |
Run vue-tsc |
npm run format |
Format src/ with Prettier |
| Command | Description |
|---|---|
npm --prefix cms run dev |
Start the Payload CMS dev server |
npm --prefix cms run build |
Build the CMS |
npm --prefix cms run start |
Start the built CMS |
npm --prefix cms run generate:types |
Generate Payload TypeScript types |
npm --prefix cms run generate:importmap |
Generate the Payload import map |
.github/workflows/ci.ymlruns frontend lint, type-check, build, and a CMS build job..github/workflows/deploy.ymlbuilds and pushes versioned frontend and CMS images to GitHub Container Registry.- The frontend Docker build expects
VITE_PAYLOAD_URLso prerendering can fetch CMS content at build time.