FERILO free-tier open-source demo stack:
| Piece | Service | Current demo |
|---|---|---|
| Database | Neon | Project database |
| Backend API | Render | https://ferilo.onrender.com |
| Frontend | Cloudflare Pages | https://ferilo.pages.dev |
Push main to GitHub, then connect each service. Never commit .env.
- Create a project at https://console.neon.tech
- Copy the pooled connection string (
sslmode=require). You can omitchannel_binding=requireif Node/pg warns. - From your machine:
$env:DATABASE_URL="postgresql://USER:PASS@HOST/neondb?sslmode=require"
$env:ADMIN_EMAIL="admin@ferilo.local"
$env:ADMIN_PASSWORD="testing01"
npm run db:setup
npm run db:seed-productsdb:setup creates schema + categories + admin/demo users.
db:seed-products adds demo listings (public picsum image URLs — works on Render).
- New → Web Service → connect
pradipNP/ferilo - Settings:
| Field | Value |
|---|---|
| Runtime | Node |
| Branch | main |
| Root Directory | (empty) |
| Build Command | npm install |
| Start Command | npm run start -w backend |
| Instance | Free |
- Environment variables:
NODE_ENV=production
PORT=10000
DATABASE_URL=<Neon connection string>
CLIENT_URL=https://ferilo.pages.dev
PUBLIC_API_URL=https://ferilo.onrender.com
JWT_SECRET=<long random string>
JWT_REFRESH_SECRET=<another long random string>
ADMIN_EMAIL=admin@ferilo.local
ADMIN_PASSWORD=testing01
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=300
AUTH_RATE_LIMIT_MAX=40
Important: CLIENT_URL must match the browser origin exactly — no trailing slash.
- Health check: https://ferilo.onrender.com/api/v1/health
Free Render sleeps when idle; first request can take 30–60s.
- Workers & Pages → Create → Pages → Connect to Git →
ferilo - Framework preset: None (not VitePress)
- Build from repo root:
| Field | Value |
|---|---|
| Root directory | (empty) |
| Build command | npm run build |
| Build output directory | frontend/dist |
| Node version | 20 |
- Production environment variable:
VITE_API_URL=https://ferilo.onrender.com
You must rebuild after adding/changing VITE_API_URL (it is baked in at build time).
- Confirm Render
CLIENT_URL=https://ferilo.pages.devand redeploy if needed.
- Neon:
db:setup(+ optionaldb:seed-products) - Render health shows
database: connected - Cloudflare
VITE_API_URLset and redeployed - Render
CLIENT_URLhas no trailing slash - Render
PUBLIC_API_URLset - Login works with demo accounts from the README
| Problem | Fix |
|---|---|
| Offline preview forever | Missing/wrong VITE_API_URL, or CORS CLIENT_URL mismatch (trailing slash) |
| Live badge but 0 listings | Run npm run db:seed-products against Neon |
| ACCOUNT_LOCKED / too many attempts | Unlock in Neon SQL, then npm run db:seed with ADMIN_PASSWORD=testing01 |
| Images broken | Prefer remote picsum URLs from current seed-products; set PUBLIC_API_URL for any /uploads paths |
| Root URL on Render returns JSON only | Expected — website is on Cloudflare Pages |
UPDATE users
SET failed_login_attempts = 0, locked_until = NULL
WHERE email = 'admin@ferilo.local';