Web App Build & Deploy Guide
Lessons from the Cadence Project
Overview
This guide documents the complete process of building and deploying a full-stack web application using Claude Code on a Chromebook. The Cadence task management app was built in two sessions totaling approximately 8 hours.
Final Stack:
- Frontend: React + Vite (hosted on Vercel)
- Backend: Express.js + Node.js (hosted on Railway)
- Database: PostgreSQL (hosted on Railway)
- Email: Resend
Live URLs:
- App: https://cadence.advisoryos.ai
- API: https://cadence-api.advisoryos.ai
Phase 1: Environment Setup (Chromebook)
Enable Linux on Chromebook
- Settings → Advanced → Developers → Linux development environment
- Turn on and wait for installation
Install Node.js
sudo apt update
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs -y
Verify:
node --version
npm --version
Install Claude Code
sudo npm install -g @anthropic-ai/claude-code
Authenticate Claude Code
claude
- Select "Anthropic account" when prompted
- Opens browser for authentication
- Requires Claude Pro subscription
Phase 2: Project Creation
Start a New Project
mkdir ~/project-name
cd ~/project-name
claude
Planning Interview
Claude Code will ask about:
- Structure: Monorepo (recommended - single repo with /client and /server folders)
- Auth: JWT tokens (recommended - stateless with access/refresh tokens)
- Language: JavaScript (simpler) or TypeScript
Auto-Approval Settings
Speed up development by allowing Claude Code to auto-approve common commands:
npm installnpm run devnode --checksqlite3(or database commands)curlpkillgit add
Phase 3: Development Workflow
Starting Development Servers
cd ~/project-name
npm run dev
This typically runs both:
- Frontend: http://localhost:5173
- Backend: http://localhost:3001
Giving Instructions to Claude Code
Be specific and detailed:
Good instruction:
Add a forgot password feature:
1. POST /api/auth/forgot-password - accepts email, generates reset token
2. POST /api/auth/reset-password - accepts token and new password
3. Add frontend pages for both flows
4. Add "Forgot password?" link on login page
Vague instruction (avoid):
Add password reset
When Claude Code Gets Stuck
- Press Esc to interrupt
- Try a simpler, more specific command
- Exit with
exitand restart withclaude - Do the task manually if needed
Phase 4: Git & GitHub
Initialize Git
git init
git add .
git commit -m "Initial commit"
Create GitHub Repository
- Go to https://github.com/new
- Create repo (can be private)
- Don't initialize with README
Generate Personal Access Token
- Go to https://github.com/settings/tokens/new
- Name it (e.g., "project-name")
- Expiration: 7-90 days
- Check repo scope
- Generate and copy token
Push to GitHub
git remote add origin https://github.com/USERNAME/REPO.git
git push -u origin master
When prompted:
- Username: your-github-username
- Password: paste the token (won't show as you type)
Subsequent Pushes
git add .
git commit -m "Description of changes"
git push origin master
Phase 5: Deployment
Backend: Railway
Initial Setup:
- Go to https://railway.app
- Sign in with GitHub
- Click New Project → Deploy from GitHub repo
- Select your repository
- In Settings, set Root Directory to
server
Add PostgreSQL:
- Inside your project, press Ctrl + K
- Type "postgres" and select "Add PostgreSQL"
- Click on your backend service → Variables
- Click New Variable → Add Reference → select Postgres DATABASE_URL
Required Environment Variables:
| Variable | Value |
|---|---|
| JWT_SECRET | any-random-string |
| JWTREFRESHSECRET | another-random-string |
| NODE_ENV | production |
| DATABASE_URL | (auto-linked from Postgres) |
| RESENDAPIKEY | (if using email) |
| RESENDFROMEMAIL | onboarding@resend.dev |
Custom Domain:
- Service → Settings → Networking/Domains
- Add custom domain (e.g., api.yourdomain.com)
- Add CNAME record in your DNS provider
Frontend: Vercel
Initial Setup:
- Go to https://vercel.com
- Sign in with GitHub
- Click Add New Project
- Import your repository
- Set Root Directory to
client - Framework Preset: Vite
Required Environment Variables:
| Variable | Value |
|---|---|
| VITEAPIURL | https://your-api-domain.com |
Custom Domain:
- Project → Settings → Domains
- Add your domain
- Add CNAME record: your-subdomain → cname.vercel-dns.com
vercel.json (in client folder):
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "vite",
"rewrites": [{"source": "/(.*)", "destination": "/index.html"}]
}
CORS Configuration
The backend must allow requests from the frontend domain. In server/src/index.js:
app.use(cors({
origin: ['https://your-frontend-domain.com', 'http://localhost:5173'],
credentials: true
}));
Phase 6: Troubleshooting
Deployment Not Working?
The #1 Lesson: Sometimes you need to wait. Deployments, DNS, and SSL all take time to sync. If you've done everything right, step away for 10-15 minutes.
Common Issues & Fixes
| Problem | Solution |
|---|---|
| Vercel: "No Output Directory named public" | Set outputDirectory to dist in vercel.json |
| API calls return 404 | Check VITEAPIURL in Vercel, ensure it includes https:// |
| CORS errors | Add frontend domain to CORS origin array in backend |
| "Server error" on registration | Check all environment variables are set in Railway |
| Data disappears after deploy | Switch from SQLite to PostgreSQL |
| Login doesn't work after deploy | Redeploy Vercel without build cache |
| Git push fails | Create new GitHub token and push manually |
Vercel Won't Auto-Deploy?
Manually redeploy:
- Go to Deployments tab
- Click three dots on latest → Redeploy
- Uncheck "Use existing build cache"
Check API Health
curl https://your-api-domain.com/api/health
Should return: {"status":"ok"}
View All Users (Admin)
curl https://your-api-domain.com/api/admin/users
Delete a User (Admin)
curl -X DELETE https://your-api-domain.com/api/admin/users/USER_ID
Test API Endpoint Directly
curl -X POST https://your-api-domain.com/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@test.com","password":"Test1234!"}'
Key Terminal Commands Reference
Navigation
cd ~/project-name # Go to project folder
pwd # Show current directory
ls # List files
Claude Code
claude # Start Claude Code
exit # Exit Claude Code
# Press Esc to interrupt a stuck command
Git
git status # Check what's changed
git add . # Stage all changes
git commit -m "message" # Commit with message
git push origin master # Push to GitHub
git log --oneline -5 # View last 5 commits
View/Edit Files (without nano)
cat filename # View entire file
cat filename | head -20 # View first 20 lines
cat filename | grep "text" # Search for text in file
Edit Files with sed
sed -i 's/old-text/new-text/' filename
Check if Server is Running
curl https://your-api-domain.com/api/health
Project Checklist
Before Starting
- [ ] Linux enabled on Chromebook
- [ ] Node.js installed
- [ ] Claude Code installed and authenticated
- [ ] GitHub account ready
- [ ] Railway account (sign in with GitHub)
- [ ] Vercel account (sign in with GitHub)
- [ ] Domain ready (if using custom domain)
- [ ] Resend account (if using email)
Before Deploying
- [ ] All features working locally
- [ ] Git repository initialized
- [ ] Code pushed to GitHub
- [ ] vercel.json configured in client folder
- [ ] CORS includes production frontend URL
After Deploying
- [ ] Environment variables set in Railway
- [ ] Environment variables set in Vercel
- [ ] Custom domains configured (if using)
- [ ] CNAME records added to DNS
- [ ] SSL certificates provisioned (wait 5-15 min)
- [ ] Test registration and login
- [ ] Test all major features
Costs
| Service | Free Tier |
|---|---|
| Claude Code | Requires Claude Pro ($20/month) |
| Railway | $5/month credit, then pay-as-you-go |
| Vercel | Free for hobby projects |
| Resend | 3,000 emails/month free |
| GitHub | Free for private repos |
Next Project Template
When starting your next project, tell Claude Code:
Create a [type of app] with:
- React frontend with [specific features]
- Express backend with JWT authentication
- PostgreSQL database
- These main features: [list features]
Use the same monorepo structure as Cadence with /client and /server folders.
Guide created from the Cadence build sessions, January 25-26, 2026