Production-ready fullstack application built with React (Vite) and a custom Express API secured with JWT and backed by PostgreSQL (Prisma ORM). The project uses environment-safe configuration, CORS allowlist, and automated CI checks for frontend and API.
- Application: https://kenzie-hub-seven-blue.vercel.app/
- Source code: https://github.com/JrValerio/Kenzie-Hub
Frontend
- React + Vite
- React Router
- Axios
- SCSS
- Context API
Backend
- Express
- JWT authentication
- Prisma ORM
- PostgreSQL
DevOps and Quality
- Vercel (frontend hosting)
- Railway (API + database)
- GitHub Actions (CI)
- Supertest + Vitest (API testing)
Frontend (Vercel / React)
|
v
API (Railway / Express + JWT)
|
v
PostgreSQL (Railway)
# install frontend dependencies (root)
npm ci
# install API dependencies
npm --prefix api ci
# run frontend + API together
npm run dev:allRun in separate terminals:
npm run dev:api
npm run devAPI tests:
npm --prefix api run test- User registration
- Login and logout
- JWT session persistence
- Private dashboard
- Technology CRUD
This project demonstrates:
- End-to-end authentication flow with protected routes.
- Domain validation and normalization across frontend and backend.
- Environment-safe configuration for local and production.
- Production deployment with CI gates for lint, build, and tests.
- Secure CORS strategy based on allowlist.
- React frontend integrated with a dedicated REST API.
- Monorepo includes its own backend, removing reliance on unstable third-party endpoints.
- Production guardrails: required
JWT_SECRETand restricted CORS viaFRONTEND_URL.
src/components: reusable UI componentssrc/pages: application pagessrc/providers: app state contextssrc/routers: public and private routingsrc/services: frontend API layersrc/styles: SCSS stylesapi: backend (Express + Prisma + PostgreSQL)
The frontend uses VITE_API_URL to target the API.
In development, if VITE_API_URL is not defined, fallback is http://localhost:3333.
- Create
.envat the project root:
VITE_API_URL=http://localhost:3333You can also copy from .env.example:
cp .env.example .env- Start everything:
npm run dev:allThe local API lives in api/ and exposes:
POST /sessionsPOST /usersGET /profilePOST /users/techsPUT /users/techs/:techIdDELETE /users/techs/:techId
API setup:
cd api
npm ciConfigure api/.env based on api/.env.example.
Run migrations before starting the API for the first time:
cd api
npm run migrate:dev
npm run seedThis project runs in production with:
- Frontend: Vercel (React + Vite)
- API: Railway (Express + JWT + Prisma)
- Database: Railway PostgreSQL
- Create a Railway project and connect this repository.
- Add a PostgreSQL service in the same Railway project.
- Configure API service settings:
- Root Directory:
api - Build Command:
npm install - Start Command:
npm run start:prod
- Configure API environment variables:
NODE_ENV=production
JWT_SECRET=your-strong-secret
FRONTEND_URL=https://kenzie-hub-seven-blue.vercel.app
DATABASE_URL=postgresql://...In NODE_ENV=production, FRONTEND_URL is required for CORS allowlist.
- After first deploy, apply migrations:
npm run migrate:deployOptional (demo account):
npm run seedHealthcheck:
GET /health->{ "status": "ok" }
- Configure environment variable:
VITE_API_URL=https://YOUR-API.railway.app- Trigger a new deploy.
- Frontend:
https://YOUR-FRONT.vercel.app - API:
https://YOUR-API.railway.app
- JWT issued on login (
POST /sessions) - Stateless authentication via bearer token
- Protected routes enforced by middleware
- CORS restricted to production frontend domain (
FRONTEND_URL) - Secrets and connection strings managed through environment variables
JWT_SECRETmust be strong and unique per environment.FRONTEND_URLmust point only to the official frontend domain in production..envfiles must stay out of version control.
- Register user (
POST /users) ->201 - Login (
POST /sessions) ->200+ token - Profile (
GET /profile) ->200 - Create tech (
POST /users/techs) ->201 - Update tech (accented or ASCII status) ->
200 - Invalid status ->
400 - Delete tech ->
204
Originally built as an academic project, this application was redesigned into a production-ready mini-product with its own backend, secure authentication, and CI pipeline.
- Removed external API dependency.
- Built dedicated backend (
Express + JWT). - Migrated persistence from file storage to PostgreSQL with Prisma.
JWT_SECRETrequired in production.- CORS restricted by
FRONTEND_URL(allowlist). .envisolated and ignored in version control.
- Technology status validation and normalization.
- Compatibility with accented and ASCII input variants.
- Single source of truth for domain rules across frontend and backend.
- Single
dev:allscript (frontend + backend). - API tests with Supertest (auth + CRUD + protected routes).
- Automatic CI with lint/build/test on push and pull request.
- CORS allowlist: API only accepts the official frontend domain in production.
appandserverseparation: enables testing without starting HTTP listener.- Prisma + PostgreSQL: transactional persistence and migration-based schema versioning.
- Normalized technology status: prevents accent/encoding inconsistencies.
- Mandatory CI: validates frontend and API on every push to
main.
