Solo SaaS MVP Stack
Ship a production SaaS in a weekend on tools verified to not waste your time. Built for solo founders and full-stack developers using Claude Code.
BUILD PROMPT
Paste into Claude, ChatGPT, or Cursor to start building.
Solo SaaS MVP Stack — AI-Executable Build Brief
You are helping a solo developer or founder ship a production SaaS from scratch. Follow this brief exactly.
What you are building
A full-stack SaaS application with:
- Server-side rendered pages (Node.js + Express + EJS)
- PostgreSQL database for persistent data
- Admin panel for content management
- Transactional email (Resend)
- Deployed to Railway, DNS via Cloudflare
Development environment setup (do this first)
Install these Claude Code tools before writing any code:
1. gstack — workflow skills
git clone --single-branch --depth 1 \
https://github.com/garrytan/gstack.git \
~/.claude/skills/gstack && \
cd ~/.claude/skills/gstack && ./setup
2. ECC — agent harness (inside Claude Code)
/plugin marketplace add \
https://github.com/affaan-m/everything-claude-code
/plugin install everything-claude-code@everything-claude-code
/reload-plugins
3. andrej-karpathy-skills — coding behavior (inside Claude Code)
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
/reload-plugins
Infrastructure setup (do this before building)
Railway (hosting):
- Create new Railway project
- Add PostgreSQL plugin — copy DATABASE_URL
- Create services as needed (website, cms, etc.)
- Set root directory per service in Railway settings
- Enable auto-deploy from GitHub main branch
Resend (transactional email):
- Create account at resend.com
- Verify your domain (add DNS records in Cloudflare)
- Create API key — save as RESEND_API_KEY
- Send from: [email protected]
Cloudflare (DNS):
- Add your domain to Cloudflare
- Use Railway one-click DNS setup when adding custom domain
- Keep orange cloud (proxied) for web traffic
- Use grey cloud (DNS only) for any subdomains serving
LLM requests (avoids 100s timeout)
Architecture pattern to follow
Services:
- website/ — public-facing Express + EJS app (port 3001)
- cms/ — admin panel Express + EJS app (port 3002)
- Both connect to the same PostgreSQL database
- Website reads published content only
- CMS reads and writes all content
Database pattern:
- Run CREATE TABLE IF NOT EXISTS on every service startup
- Use connection pooling (max 5 connections per service)
- SSL in production: { rejectUnauthorized: false }
- Seed config tables with ON CONFLICT DO NOTHING
Authentication pattern (CMS):
- Query param ?key=ADMIN_SECRET on all /admin routes
- Middleware checks process.env.ADMIN_SECRET
- Wrong or missing key returns 401 page
- Never redirect, just block
Environment variables (website):
PORT=3001
DATABASE_URL=<Railway PostgreSQL connection string>
NODE_ENV=production
SITE_URL=https://yourdomain.com
RESEND_API_KEY=<your Resend API key>
Environment variables (cms):
PORT=3002
DATABASE_URL=<same Railway PostgreSQL connection string>
NODE_ENV=production
ADMIN_SECRET=<strong random secret>
Build workflow (use ECC commands in this order)
1. /plan-eng-review
Run first. Produce complete file structure, all routes,
database schema, env vars, Railway config.
Wait for approval before writing any code.
2. /feature-dev
Build in this order:
- Database migration (CREATE TABLE IF NOT EXISTS)
- CMS service (admin CRUD)
- Website service (public pages)
- railway.toml for each service
- docker-compose.yml for local testing
3. /review
Full code review before any deploy.
Check: no secrets in code, parameterized queries only,
error handling on all database calls, health check
endpoints on each service.
4. /qa
Test all routes, all admin functions, all database
operations. Use curl for API endpoints.
Verify health checks pass.
5. Deploy
git push origin main
Railway auto-deploys from main branch
Add custom domain in Railway
Use Cloudflare one-click DNS setup
Known gotchas
- Cloudflare 100s timeout kills long LLM requests —
use DNS-only (grey cloud) for LLM-serving subdomains
- Session persistence breaks on Railway restarts —
use connect-pg-simple backed by PostgreSQL
- Subpath proxying causes cookie domain mismatches —
use subdomains instead
- Cloudflare + Railway custom domain: use Railway
one-click Cloudflare setup to avoid DNS conflicts
- Race conditions on concurrent writes — use UNIQUE
constraints + ON CONFLICT DO NOTHING
Proof this works
repoverifier.dev was built using exactly this stack.
Live at https://repoverifier.dev
Architecture
Dev Tools
- andrej-karpathy-skills — Coding behavior — stops Claude Code from making silent assumptions
- everything-claude-code (ECC) — Agent harness — 68 skills, 53 agents, 26 hooks
- gstack — Development workflow — /plan-eng-review, /feature-dev, /review, /qa, /ship
Infrastructure
- PostgreSQL via Railway — Database — persistent storage, managed hosting
- Railway — Hosting + Deploy — auto-deploy from GitHub
- Resend — Transactional email — notifications and alerts
- Cloudflare — DNS + CDN — domain routing and protection
Stack Components
| Tool / Service | Type | Role | Verdict |
|---|---|---|---|
| andrej-karpathy-skills★ 93.9k | Dev Tool | Coding behavior — stops Claude Code from making silent assumptions | SOLID |
| everything-claude-code (ECC)★ 172.0k | Dev Tool | Agent harness — 68 skills, 53 agents, 26 hooks | SOLID |
| gstack★ 88.4k | Dev Tool | Development workflow — /plan-eng-review, /feature-dev, /review, /qa, /ship | SOLID |
| PostgreSQL via Railway | Service | Database — persistent storage, managed hosting | |
| Railway | Service | Hosting + Deploy — auto-deploy from GitHub | |
| Resend | Service | Transactional email — notifications and alerts | |
| Cloudflare | Service | DNS + CDN — domain routing and protection |
Proof it works
Built with this exact stack: repoverifier.dev