A full-stack project management application built with FastAPI (Python) backend and React (Vite) frontend. This system allows users to manage projects and tasks with role-based access control, email notifications, and a modern drag-and-drop Kanban board interface.
- User Authentication & Authorization: JWT-based authentication with role-based access (Admin/User)
- Project Management: Create, update, delete, and list projects with pagination and search
- Task Management: Assign tasks to users with status tracking (To Do, In Progress, Done)
- Kanban Board: Drag-and-drop interface for task management
- Email Notifications: Automated emails for task assignments and status updates
- User Management: List all users with role identification for task assignment
- Real-time Updates: React Query for optimistic updates and cache management
- Responsive Design: Modern UI built with Tailwind CSS
- Tech Stack
- Architecture Overview
- Prerequisites
- Setup Instructions
- Environment Variables
- Database Migrations
- Running the Application
- Create Admin User โญ
- API Documentation
- Project Structure
- FastAPI (v0.120.4) - Modern, fast web framework for building APIs
- SQLAlchemy (v2.0.36) - SQL toolkit and ORM
- Alembic (v1.14.0) - Database migration tool
- PostgreSQL - Primary database (via psycopg2-binary)
- Pydantic (v2.12.3) - Data validation using Python type annotations
- Python-JOSE - JWT token creation and validation
- Bcrypt - Password hashing
- FastAPI-Mail - Email service integration
- Uvicorn - ASGI server
- React (v19.1.1) - UI library
- Vite (v7.1.7) - Build tool and dev server
- React Router DOM (v6.22.3) - Client-side routing
- Redux Toolkit (v2.2.1) - State management
- React Query (v5.28.4) - Data fetching and caching
- Axios (v1.6.8) - HTTP client
- Tailwind CSS (v3.4.1) - Utility-first CSS framework
- @hello-pangea/dnd (v16.6.0) - Drag and drop for Kanban board
- React Hot Toast (v2.4.1) - Toast notifications
- React Icons (v5.0.1) - Icon library
Server/
โโโ app/
โ โโโ core/ # Core configuration and utilities
โ โ โโโ config.py # Environment configuration
โ โ โโโ database.py # Database connection and session
โ โ โโโ security.py # JWT and password hashing
โ โ โโโ logger.py # Logging configuration
โ โ โโโ email.py # Email configuration
โ โโโ models/ # SQLAlchemy ORM models
โ โ โโโ user.py # User model (auth + roles)
โ โ โโโ project.py # Project model
โ โ โโโ task.py # Task model
โ โโโ schemas/ # Pydantic schemas (request/response)
โ โ โโโ user.py
โ โ โโโ project.py
โ โ โโโ task.py
โ โ โโโ common.py
โ โโโ routers/ # API route handlers
โ โ โโโ auth.py # Authentication endpoints
โ โ โโโ projects.py # Project CRUD endpoints
โ โ โโโ task.py # Task CRUD endpoints
โ โโโ services/ # Business logic and external services
โ โ โโโ email_service.py
โ โโโ templates/ # Email templates (Jinja2)
โ โโโ dependencies.py # Dependency injection (auth, roles)
โ โโโ main.py # FastAPI application entry point
โโโ alembic/ # Database migrations
โโโ requirements.txt # Python dependencies
client/
โโโ src/
โ โโโ components/ # Reusable React components
โ โ โโโ ui/ # Base UI components (Button, Input, Modal, etc.)
โ โ โโโ layout/ # Layout components (Navbar, Sidebar, Dashboard)
โ โ โโโ tasks/ # Task-specific components (TaskCard, TaskModal)
โ โ โโโ projects/ # Project-specific components
โ โ โโโ kanban/ # Kanban board components
โ โโโ pages/ # Route pages
โ โ โโโ auth/ # Login and Register pages
โ โ โโโ dashboards/# Admin and User dashboards
โ โ โโโ ...
โ โโโ services/ # API service layer
โ โ โโโ api.js # Axios instance with interceptors
โ โ โโโ authService.js
โ โ โโโ projectService.js
โ โ โโโ taskService.js
โ โโโ store/ # Redux store
โ โ โโโ slices/ # Redux slices (auth, projects, tasks)
โ โโโ utils/ # Utility functions and constants
โ โโโ main.jsx # Application entry point
โโโ package.json
- JWT Authentication: Token-based authentication for stateless API
- Role-Based Access Control: Admin and User roles with middleware-level enforcement
- Background Tasks: Async email sending to avoid blocking API responses
- React Query: Efficient data fetching, caching, and synchronization
- Optimistic Updates: Immediate UI updates with automatic rollback on failure
- Component-Based Architecture: Reusable, maintainable React components
- Service Layer Pattern: Separation of API calls from components
- Database Migrations: Alembic for version-controlled schema changes
Before you begin, ensure you have the following installed:
- Python 3.10+
- Node.js 18+ and npm/yarn
- PostgreSQL 14+
- Git
git clone <repository-url>
cd project-managementcd Server
python -m venv fastapiWindows:
fastapi\Scripts\activatemacOS/Linux:
source fastapi/bin/activatepip install -r requirements.txtCreate a .env file in the Server directory:
# Server/.env
DATABASE_URL=postgresql://username:password@localhost:5432/project_management
SECRET_KEY=your-super-secret-key-change-this-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=600
# Email Configuration
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_FROM=your-email@gmail.com
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
# Frontend URL (for CORS)
CLIENT_URL=http://localhost:5173Note: For Gmail, you need to create an App Password instead of using your regular password.
cd ../clientnpm install
# or
yarn installCreate a .env file in the client directory:
# client/.env
VITE_API_BASE_URL=http://localhost:8000| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://user:pass@localhost:5432/dbname |
SECRET_KEY |
JWT secret key (use strong random string) | your-secret-key-here |
ALGORITHM |
JWT algorithm | HS256 |
ACCESS_TOKEN_EXPIRE_MINUTES |
Token expiration time in minutes | 600 |
MAIL_USERNAME |
SMTP email username | your-email@gmail.com |
MAIL_PASSWORD |
SMTP email password/app password | your-app-password |
MAIL_FROM |
Email sender address | your-email@gmail.com |
MAIL_SERVER |
SMTP server address | smtp.gmail.com |
MAIL_PORT |
SMTP server port | 587 |
CLIENT_URL |
Frontend URL for CORS | http://localhost:5173 |
| Variable | Description | Example |
|---|---|---|
VITE_API_BASE_URL |
Backend API base URL | http://localhost:8000 |
First, create a PostgreSQL database:
CREATE DATABASE project_management;cd Server
alembic upgrade headalembic revision --autogenerate -m "description of changes"
alembic upgrade headThe application uses three main tables:
- users: User accounts with authentication and role information
- projects: Projects created by admin users
- tasks: Tasks assigned to users within projects
cd Server
# Make sure virtual environment is activated
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000The API will be available at: http://localhost:8000
API Documentation (Swagger UI): http://localhost:8000/docs
cd client
npm run dev
# or
yarn devThe frontend will be available at: http://localhost:5173
The project includes a professional CLI management tool for user administration.
# Navigate to Server directory
cd Server
# Create a new admin user (interactive)
python manage.py create-admin
# List all users
python manage.py list-users
# Change user role (promote user to admin or demote admin to user)
python manage.py change-role
# Show help
python manage.py helpDevelopment:
cd Server
python manage.py create-adminYou'll be prompted for:
- Email address (validated format)
- Full name (3-100 characters)
- Password (must meet security requirements)
- Password confirmation
Production Deployment:
# SSH into production server
ssh user@your-server.com
# Navigate to project
cd /path/to/project-management/Server
# Activate virtual environment
source fastapi/bin/activate
# Create admin user
python manage.py create-adminThe system enforces strong password policies:
- โ Minimum 8 characters
- โ At least one uppercase letter (A-Z)
- โ At least one lowercase letter (a-z)
- โ At least one number (0-9)
- โ At least one special character (!@#$%^&*(),.?":{}|<>)
Example Valid Password: Admin@2024Pass
$ python manage.py create-admin
============================================================
CREATE ADMIN USER
============================================================
Admin email: admin@company.com
Full name: System Administrator
Password: ********
Confirm password: ********
โณ Creating admin user...
============================================================
โ
ADMIN USER CREATED SUCCESSFULLY!
============================================================
ID: 1
Email: admin@company.com
Name: System Administrator
Role: admin
Created: 2024-01-01 10:30:00
============================================================$ python manage.py list-users
================================================================================
ALL USERS
================================================================================
ID Email Name Role Active
--------------------------------------------------------------------------------
1 admin@company.com System Administrator admin Yes
2 john@example.com John Doe user Yes
3 jane@example.com Jane Smith user Yes
--------------------------------------------------------------------------------
Total users: 3$ python manage.py change-role
============================================================
CHANGE USER ROLE
============================================================
Enter user email or ID: john@example.com
๐ Current User Info:
ID: 2
Email: john@example.com
Name: John Doe
Role: user
Available roles: admin, user
Enter new role (current: user): admin
Change role from 'user' to 'admin'? (y/n): y
โ
User role updated successfully!
john@example.com is now an 'admin'If you absolutely need to manually update the database:
# Connect to database
psql -U username -d project_management
# Update user role
UPDATE users SET role = 'admin' WHERE email = 'admin@example.com';For development convenience, you can modify the registration endpoint to make the first user an admin automatically (not recommended for production):
# In Server/app/routers/auth.py (for development only)
user_count = db.query(User).count()
role = "admin" if user_count == 0 else "user"- Create admin using CLI:
python manage.py create-admin - Use strong passwords even in development
- Don't commit admin credentials to version control
-
Initial Setup:
- SSH into production server
- Run
python manage.py create-admin - Use environment-specific strong password
-
Credential Management:
- Store credentials in password manager (1Password, LastPass, etc.)
- Share with client through encrypted channels
- Force password change on first login
-
Security:
- Use unique passwords for each environment
- Enable 2FA if implemented
- Regularly audit admin accounts:
python manage.py list-users - Remove unused admin accounts
-
Handover to Client:
- Create initial admin account
- Provide credentials securely (encrypted email, password manager)
- Client logs in and changes password immediately
- Client can promote other users via CLI or create additional admins
http://localhost:8000
POST /api/auth/register
Content-Type: application/json
{
"full_name": "John Doe",
"email": "john@example.com",
"password": "securepassword123"
}
Response: 200 OK
{
"success": true,
"data": {
"id": 1,
"full_name": "John Doe",
"email": "john@example.com",
"role": "user",
"is_active": true,
"created_at": "2024-01-01T00:00:00"
},
"message": "User registered successfully"
}POST /api/auth/login
Content-Type: application/json
{
"email": "john@example.com",
"password": "securepassword123"
}
Response: 200 OK
{
"success": true,
"data": {
"id": 1,
"full_name": "John Doe",
"email": "john@example.com",
"role": "user"
},
"message": "Login successful",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}GET /api/auth/me
Authorization: Bearer {token}
Response: 200 OK
{
"success": true,
"data": {
"id": 1,
"full_name": "John Doe",
"email": "john@example.com",
"role": "user"
}
}GET /api/auth/users
Authorization: Bearer {token}
Response: 200 OK
{
"success": true,
"data": [
{
"id": 1,
"full_name": "John Doe",
"email": "john@example.com",
"role": "user",
"is_active": true
},
{
"id": 2,
"full_name": "Admin User",
"email": "admin@example.com",
"role": "admin",
"is_active": true
}
],
"message": "Users fetched successfully"
}POST /api/project/
Authorization: Bearer {token}
Content-Type: application/json
{
"title": "New Website Project",
"description": "Build a modern website with React and FastAPI"
}
Response: 200 OK
{
"id": 1,
"title": "New Website Project",
"description": "Build a modern website with React and FastAPI",
"created_by": 2,
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T00:00:00"
}GET /api/project/?page=1&size=10&search=website&created_by=2
Authorization: Bearer {token}
Query Parameters:
- page: Page number (default: 1)
- size: Items per page (default: 10, max: 100)
- search: Search in title and description (optional)
- created_by: Filter by creator user ID (optional)
Response: 200 OK
{
"success": true,
"data": {
"projects": [
{
"id": 1,
"title": "New Website Project",
"description": "Build a modern website",
"created_by": 2,
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T00:00:00",
"task_count": 5
}
],
"total": 1,
"page": 1,
"size": 10,
"total_pages": 1
}
}GET /api/project/{project_id}
Authorization: Bearer {token}
Response: 200 OK
{
"success": true,
"data": {
"id": 1,
"title": "New Website Project",
"description": "Build a modern website",
"created_by": 2,
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T00:00:00",
"tasks": [
{
"id": 1,
"title": "Design homepage",
"status": "todo",
"assigned_to": 1
}
]
}
}PATCH /api/project/{project_id}
Authorization: Bearer {token}
Content-Type: application/json
{
"title": "Updated Project Title",
"description": "Updated description"
}
Response: 200 OK
{
"id": 1,
"title": "Updated Project Title",
"description": "Updated description",
"created_by": 2,
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T10:00:00"
}DELETE /api/project/{project_id}
Authorization: Bearer {token}
Response: 200 OK
{
"success": true,
"data": null,
"message": "Project deleted successfully"
}POST /api/task/
Authorization: Bearer {token}
Content-Type: application/json
{
"title": "Design homepage",
"description": "Create wireframes and mockups",
"project_id": 1,
"assigned_to": 3,
"status": "todo",
"due_date": "2024-12-31"
}
Response: 200 OK
{
"id": 1,
"title": "Design homepage",
"description": "Create wireframes and mockups",
"project_id": 1,
"assigned_to": 3,
"status": "todo",
"due_date": "2024-12-31T00:00:00",
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T00:00:00"
}
Note: Sends email notification to assigned userGET /api/task/?page=1&size=10&search=design&status=todo&project_id=1&assigned_to=3
Authorization: Bearer {token}
Query Parameters:
- page: Page number (default: 1)
- size: Items per page (default: 10, max: 100)
- search: Search in title and description (optional)
- status: Filter by status (todo, in-progress, done) (optional)
- project_id: Filter by project ID (optional)
- assigned_to: Filter by assigned user ID (optional)
Response: 200 OK
{
"success": true,
"data": {
"tasks": [
{
"id": 1,
"title": "Design homepage",
"description": "Create wireframes and mockups",
"project_id": 1,
"assigned_to": 3,
"status": "todo",
"due_date": "2024-12-31T00:00:00"
}
],
"total": 1,
"page": 1,
"size": 10,
"total_pages": 1
}
}GET /api/task/assigned?page=1&size=10&status=todo
Authorization: Bearer {token}
Query Parameters:
- page: Page number (default: 1)
- size: Items per page (default: 10, max: 100)
- status: Filter by status (optional)
Response: 200 OK
{
"success": true,
"data": {
"tasks": [...],
"total": 5,
"page": 1,
"size": 10,
"total_pages": 1
}
}GET /api/task/{task_id}
Authorization: Bearer {token}
Response: 200 OK
{
"id": 1,
"title": "Design homepage",
"description": "Create wireframes and mockups",
"project_id": 1,
"assigned_to": 3,
"status": "todo",
"due_date": "2024-12-31T00:00:00",
"created_at": "2024-01-01T00:00:00",
"updated_at": "2024-01-01T00:00:00"
}
Note: Users can only view tasks assigned to them (admins can view all)PATCH /api/task/{task_id}
Authorization: Bearer {token}
Content-Type: application/json
{
"title": "Updated task title",
"status": "in-progress",
"due_date": "2024-12-25"
}
Response: 200 OK
{
"id": 1,
"title": "Updated task title",
"status": "in-progress",
"due_date": "2024-12-25T00:00:00",
...
}
Note: Status changes trigger email notifications to project creatorDELETE /api/task/{task_id}
Authorization: Bearer {token}
Response: 200 OK
{
"success": true,
"data": null,
"message": "Task deleted successfully"
}
Note: Users can only delete their own tasks (admins can delete any)| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request (validation error) |
| 401 | Unauthorized (invalid/missing token) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found |
| 422 | Unprocessable Entity (validation error) |
| 500 | Internal Server Error |
- id: Integer (Primary Key)
- email: String (Unique)
- full_name: String
- hashed_password: String
- role: String (default: "user") # admin or user
- is_active: Boolean (default: True)
- disabled: Boolean (default: False)
- created_at: DateTime
- updated_at: DateTime- id: Integer (Primary Key)
- title: String
- description: String (Optional)
- created_by: Integer (Foreign Key -> users.id)
- created_at: DateTime
- updated_at: DateTime- id: Integer (Primary Key)
- title: String
- description: String (Optional)
- project_id: Integer (Foreign Key -> projects.id)
- assigned_to: Integer (Foreign Key -> users.id)
- status: String (default: "todo") # todo, in-progress, done
- due_date: Date (Optional)
- created_at: DateTime
- updated_at: DateTime- Password Hashing: Bcrypt with automatic salt generation
- JWT Authentication: Secure token-based authentication
- CORS Protection: Configured for specific frontend origin
- Role-Based Access: Middleware-level permission checking
- SQL Injection Prevention: SQLAlchemy ORM with parameterized queries
- Input Validation: Pydantic models for request validation
The system sends automated emails for:
- Welcome Email: Sent when a new user registers
- Task Assignment: Sent when a task is assigned to a user
- Status Update: Sent to project creator when task status changes
Email templates are located in Server/app/templates/email/ and use Jinja2 templating.
You can test the API using:
- Swagger UI: Visit
http://localhost:8000/docs - Postman: Import the endpoints from the API documentation
- cURL: Use command-line HTTP requests
Example cURL request:
curl -X POST "http://localhost:8000/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password123"}'Database Connection Error:
- Verify PostgreSQL is running
- Check
DATABASE_URLin.env - Ensure database exists:
CREATE DATABASE project_management;
Migration Issues:
# Reset migrations (WARNING: deletes all data)
alembic downgrade base
alembic upgrade headEmail Not Sending:
- Verify SMTP credentials in
.env - For Gmail, use App Password, not regular password
- Check firewall/antivirus blocking port 587
API Connection Error:
- Verify backend is running on port 8000
- Check
VITE_API_BASE_URLin.env - Check browser console for CORS errors
Build Errors:
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm installThis project is licensed under the MIT License.
Built with โค๏ธ by the development team.
- File attachments for tasks
- Task comments and activity log
- Real-time notifications with WebSockets
- Task dependencies and subtasks
- Calendar view for tasks
- Team/workspace management
- Advanced analytics and reporting
- Mobile application (React Native)
- Integration with external tools (Slack, GitHub, etc.)
For more information or support, please open an issue on the repository.