A secure full-stack task workspace built with FastAPI, SQLAlchemy, React, React Router, and Tailwind CSS. TaskFlow demonstrates authenticated CRUD, account-level data isolation, responsive product UI, automated backend tests, Docker packaging, and continuous integration.
Portfolio project by Hari Om Tiwari.
Live demo: taskflow-hariom.onrender.com
| Home | Authenticated dashboard |
|---|---|
![]() |
![]() |
- JWT authentication with bcrypt password hashing
- Strict task ownership enforced in database queries
- Validated request and response models with Pydantic 2
- Configurable database, token lifetime, secret, and CORS origins
- Responsive React interface with dashboard counts and inline editing
- FastAPI-generated OpenAPI documentation
- Backend test coverage for authentication, validation, CRUD, and cross-account isolation
- Separate production containers behind an Nginx reverse proxy
- GitHub Actions checks for tests, linting, typing, and frontend builds
- One-service Render deployment with a generated JWT secret and health check
flowchart LR
B[Browser] --> N[Nginx / React]
N -->|/api| A[FastAPI]
A --> J[JWT authentication]
A --> S[SQLAlchemy service layer]
S --> D[(SQLite / configurable SQL database)]
A --> O[OpenAPI docs]
The frontend stores the short-lived access token locally and attaches it to API requests. Every task query includes both task ID and authenticated user ID, preventing one account from reading or modifying another account’s work.
Requirements: Docker Engine with Compose.
docker compose up --buildOpen http://localhost:8080. API documentation is available at http://localhost:8080/docs.
For anything beyond local demonstration, set a strong secret first:
JWT_SECRET=replace-with-a-long-random-value docker compose up --buildThe root Dockerfile packages the React production build and FastAPI API into one
web service. The included render.yaml Blueprint selects Render's free plan,
generates a unique JWT secret, and configures /api/health as the health check.
The free demo stores data in SQLite under /tmp. Render's free filesystem is
ephemeral, so accounts and tasks can reset when the service restarts or redeploys.
That behavior is intentional for a portfolio demo; use managed PostgreSQL for a
durable production installation.
The tested development versions are Python 3.12 and Node.js 20 or newer.
python -m venv .venv
.venv/Scripts/activate
python -m pip install -r backend/requirements-dev.txt
uvicorn backend.main:app --reloadThe API starts at http://localhost:8000 and exposes interactive documentation at /docs.
In a second terminal:
cd frontend
npm ci
npm run devParcel starts at http://localhost:1234 and proxies /api to the backend.
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/api/signup |
Create an account |
POST |
/api/login |
Exchange credentials for a bearer token |
GET |
/api/users/me |
Read the authenticated account |
POST |
/api/tasks/ |
Create a task |
GET |
/api/tasks/ |
List the account’s tasks |
GET |
/api/tasks/{id} |
Read one owned task |
PUT |
/api/tasks/{id} |
Replace one owned task |
DELETE |
/api/tasks/{id} |
Delete one owned task |
GET |
/api/health |
Service liveness |
pytest -q
ruff check backend
mypy backend
cd frontend && npm run buildThe CI workflow runs these checks for every push and pull request.
- The repository contains no production secret.
JWT_SECRETis environment-configured. - CORS is restricted to configured origins instead of credentialed wildcard access.
- Passwords are bcrypt-hashed and never returned by API schemas.
- Unauthorized task IDs return
404, avoiding cross-account information disclosure. - SQLite is convenient for the demo; a managed SQL database, HTTPS, secure cookies, rate limiting, and key rotation are recommended for production.
MIT

