A production-ready Task & Project Management REST API + Web App — built as a portfolio project demonstrating real-world backend engineering practices.
| URL | |
|---|---|
| 🖥️ Web App | [https://planify-api-iota.vercel.app] |
| 📚 API Docs (Swagger) | [https://collective-mahala-ricothenfx-0fa7db9e.koyeb.app/docs] |
| 📖 API Docs (ReDoc) | [https://collective-mahala-ricothenfx-0fa7db9e.koyeb.app/redoc] |
| ❤️ Health Check | [https://collective-mahala-ricothenfx-0fa7db9e.koyeb.app/health] |
- JWT Authentication with Access + Refresh Token rotation
- Account Lockout — auto-lock after 5 failed attempts (30 min)
- Password Reset via email (Resend)
- Change Password for authenticated users
- bcrypt password hashing, UUID-based user IDs
- Full CRUD for Projects and Tasks
- Kanban-style task status:
todo→in_progress→done - Task priority levels:
low,medium,high - Due dates, assignees, descriptions
- Pagination + Filter + Sort on all list endpoints
- AI Task Generation — describe your project, get 5-8 actionable tasks instantly
- AI Smart Suggestions — move a task status, get contextual next-action suggestions
- WebSocket notifications for all project events
- Events:
task_created,task_updated,task_deleted,comment_created,ai_tasks_generated
- Project Members — invite users, manage roles (Owner/Member)
- Task Comments — threaded comments with real-time updates
- File Attachments — upload images, PDFs, documents (Cloudinary CDN)
- Activity Log — full audit trail for every action
- Redis caching with smart cache invalidation
- Rate limiting per IP via Redis
- PostgreSQL with async SQLAlchemy 2.0
- Alembic database migrations
- Docker + docker-compose — one command setup
HTTP Request
↓
Routes (FastAPI) ← Input validation (Pydantic v2)
↓
Services ← Business logic
↓
Repositories ← Database operations (async)
↓
Models (SQLAlchemy) ← PostgreSQL via asyncpg
Side effects:
Services → Cache (Redis)
Services → Activity Log
Services → WebSocket broadcast
Services → AI (Gemini API)
Design principles:
- Layered architecture — each layer has one responsibility
- Repository pattern — all DB operations isolated
- Dependency injection via FastAPI
Depends() - Async throughout — non-blocking I/O
| Layer | Technology |
|---|---|
| Framework | FastAPI |
| Database | PostgreSQL 16 + SQLAlchemy 2.0 async |
| Cache | Redis 7 |
| Auth | JWT (python-jose) + bcrypt |
| AI | Google Gemini 2.5 Flash |
| Storage | Cloudinary |
| Resend | |
| Migration | Alembic |
| Container | Docker + docker-compose |
| Validation | Pydantic v2 |
| Package Manager | uv |
| Frontend | React 18 + Vite + Tailwind CSS |
- Docker + Docker Compose
- Git
git clone https://github.com/ricothenfx/planify-api.git
cd planify-apicp .env.example .envEdit .env with your credentials:
SECRET_KEY=your-secret-key-here
GEMINI_API_KEY=your-gemini-api-key
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-cloudinary-api-key
CLOUDINARY_API_SECRET=your-cloudinary-api-secret
RESEND_API_KEY=your-resend-api-key
RESEND_FROM_EMAIL=onboarding@resend.dev
FRONTEND_URL=http://localhost:5173docker-compose up --builddocker exec planify-backend uv run alembic upgrade head- Web App: http://localhost:5173
- API Docs: http://localhost:8000/docs
planify-api/
├── backend/
│ ├── app/
│ │ ├── api/v1/
│ │ │ └── routes/ # HTTP endpoints
│ │ ├── core/
│ │ │ ├── config.py # Settings (pydantic-settings)
│ │ │ ├── database.py # Async DB connection
│ │ │ ├── security.py # JWT + bcrypt
│ │ │ ├── cache.py # Redis cache service
│ │ │ ├── dependencies.py # FastAPI dependencies
│ │ │ ├── middleware.py # Request logging
│ │ │ └── exceptions.py # Custom error handlers
│ │ ├── models/ # SQLAlchemy models
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # Business logic
│ │ └── repositories/ # Database operations
│ ├── alembic/ # DB migrations
│ ├── Dockerfile
│ └── pyproject.toml
├── frontend/
│ ├── src/
│ │ ├── api/ # API client functions
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── stores/ # Zustand state
│ │ └── lib/ # Axios config
│ └── Dockerfile
├── docker-compose.yml
└── README.md
POST /api/v1/auth/login # Login → access + refresh token
POST /api/v1/auth/refresh # Rotate tokens
POST /api/v1/auth/forgot-password # Send reset email
POST /api/v1/auth/reset-password # Reset with token
POST /api/v1/auth/change-password # Change password (auth required)
GET /api/v1/projects # List with pagination + search
POST /api/v1/projects # Create project
GET /api/v1/projects/:id # Get project detail
PATCH /api/v1/projects/:id # Update project
DELETE /api/v1/projects/:id # Delete project
GET /api/v1/projects/:id/tasks # List with filters
POST /api/v1/projects/:id/tasks # Create task
PATCH /api/v1/projects/:id/tasks/:id # Update task → AI suggestions
DELETE /api/v1/projects/:id/tasks/:id # Delete task
POST /api/v1/ai/projects/:id/generate-tasks # AI task generation
WS /api/v1/ws/projects/:id?token=JWT # Real-time events
Full API documentation available at
/docs(Swagger UI) or/redoc
| Variable | Description | Required |
|---|---|---|
SECRET_KEY |
JWT signing key (min 32 chars) | ✅ |
DATABASE_URL |
PostgreSQL connection string | ✅ |
REDIS_URL |
Redis connection string | ✅ |
GEMINI_API_KEY |
Google AI Studio API key | ✅ |
CLOUDINARY_CLOUD_NAME |
Cloudinary cloud name | ✅ |
CLOUDINARY_API_KEY |
Cloudinary API key | ✅ |
CLOUDINARY_API_SECRET |
Cloudinary API secret | ✅ |
RESEND_API_KEY |
Resend email API key | ✅ |
FRONTEND_URL |
Frontend URL for email links | ✅ |
Built by Rico — Backend Developer
MIT