Project Management
A full-featured, open-source project management system built with Django. It helps teams organize, track, and manage their work through an intuitive Kanban board interface with ticket tracking, epics, and real-time collaboration features.
Whether you're running a software development team, a creative agency, or any project-driven organization, this tool replaces spreadsheets and scattered to-do lists with a centralized platform. Teams can create projects with custom ticket prefixes, organize work into epics, track progress with Kanban boards, and stay updated with in-app, email, and browser push notifications. The built-in role-based access (2 system roles — superadmin and manager — plus unlimited custom roles) with per-project, per-status board move permissions ensures the right people have the right access.
External stakeholders can view project dashboards via shareable read-only links without creating accounts. The UI is fully customizable with 19 color themes, sidebar or top navigation, and dark/light mode preferences — all stored per user.
The application follows a modern Django architecture with REST API endpoints (documented via Swagger), JWT authentication, Google OAuth, and a task queue for background processing. It ships with Docker Compose for production-ready MySQL + gunicorn deployment, comprehensive demo data seeding, and a GitHub Actions CI pipeline.
Tech Stack
| Layer |
Technology |
| Backend |
Django 6, Django REST Framework, SimpleJWT, Django Q2, pywebpush |
| Frontend |
HTMX, Alpine.js, Tailwind CSS v4 (via django-tailwind-cli), Service Worker API |
| Database |
SQLite (dev) / MySQL 8.0 (prod) |
| Task Queue |
Django Q2 (ORM broker, 2 workers) |
| API Docs |
drf-spectacular (Swagger UI + OpenAPI schema) |
| Admin |
django-jazzmin (themed admin panel) |
| Auth |
JWT (access 1h / refresh 30d) + Google OAuth |
| Package Manager |
uv |
Features
- Projects — create, manage, pin projects with colour labels, ticket prefixes, and member roles
- Tickets — full CRUD, bulk delete, Excel import/export, priority and status management
- Epics — group tickets into epics with progress tracking (% completion)
- Kanban Board — drag-and-drop ticket status columns per project with role-based per-status move permissions
- Roles & Permissions — dynamic custom role CRUD with per-project, per-status board move permissions (admin-managed via checkbox modals)
- Notifications — in-app, email, and browser push notifications on ticket events (create, update, assign, comment)
- User Management — role-based access with 2 system roles (superadmin, manager) plus unlimited custom user-defined roles
- External Access — share a read-only dashboard link with external users via a secure token
- Push Notifications — browser push via the Web Push API (VAPID), no third-party services; user opt-in popup
- Project Notes — attach rich-text notes to projects
- Google OAuth — sign in with Google
- Bulk Operations — bulk delete tickets, bulk delete notes
- Column Visibility — show/hide columns on project detail and list views
- Search & Filter — search, filter by status/priority, paginated lists
- UI Customization — 19 color themes, sidebar/top navigation, dark/light mode
- Site Branding — custom logo, favicon, brand name, copyright name via admin
Quick Start
Prerequisites
1. Clone & install
2. Configure environment
Minimal .env:
3. Run migrations & create superuser
4. Start development server
Open http://localhost:8000 in your browser. Authenticated users are redirected to the dashboard.
Seed demo data (optional)
Using just (recommended)
Install just, a command runner. See all available commands:
Development
| Command |
Description |
just dev |
Run development server on 0.0.0.0:8000 |
just dev-server HOST="127.0.0.1" PORT="9000" |
Dev server with custom host/port |
just shell |
Django shell |
just shell-plus |
Django shell_plus (IPython) |
just dbshell |
Database shell |
Database
| Command |
Description |
just migrate |
Run all migrations |
just makemigrations |
Create migrations for all apps |
just makemigrations-app APP |
Create migrations for a specific app |
just showmigrations |
Show migration status |
just reset-db |
Flush DB, recreate migrations, migrate |
just clear-cache |
Clear database cache |
Testing & Quality
| Command |
Description |
just test |
Run Django tests |
just test-coverage |
Run pytest with coverage (HTML + terminal) |
just lint |
Ruff lint check |
just format |
Ruff format |
just style |
Lint + format |
just check |
Django system checks |
just check-deploy |
Security checks (production settings) |
just ci |
Full CI: ruff check + format check + manage.py check |
Setup
| Command |
Description |
just setup |
uv sync → migrations → createcachetable → superuser |
just setup-complete |
Same as setup + collectstatic |
Production
| Command |
Description |
just server |
Start gunicorn (1 worker) |
just server-prod WORKERS="4" |
Start gunicorn with N workers |
just server-watch |
Gunicorn with --reload |
Package Management
| Command |
Description |
just install PACKAGE |
uv add a package |
just install-dev PACKAGE |
uv add --dev a package |
just remove PACKAGE |
uv remove a package |
just pin-deps |
Sync pyproject.toml from uv.lock |
just clean |
Remove Python cache, coverage, pytest cache |
Project Structure
API Documentation
When running in development mode:
| Endpoint |
Description |
http://localhost:8000/api/docs/ |
Swagger UI (drf-spectacular) |
http://localhost:8000/api/schema/ |
OpenAPI 3 schema (YAML) |
Key API routes
| Method |
Endpoint |
Description |
POST |
/api/auth/login/ |
JWT login (returns access + refresh tokens) |
POST |
/api/auth/token/refresh/ |
Refresh access token |
GET |
/api/auth/me/ |
Current user profile |
GET/POST |
/api/projects/ |
List / create projects |
GET/PUT/PATCH/DELETE |
/api/projects/<id>/ |
Project detail |
GET/POST |
/api/projects/<id>/members/ |
Project members |
GET/POST |
/api/tickets/ |
List / create tickets |
GET/PUT/PATCH/DELETE |
/api/tickets/<id>/ |
Ticket detail |
PATCH |
/api/tickets/<id>/move/ |
Move ticket between statuses |
GET/POST |
/api/epics/ |
List / create epics |
GET/POST |
/api/notes/ |
List / create notes |
GET/POST |
/api/notifications/ |
List notifications |
GET |
/api/projects/stats/ |
Aggregate project statistics |
UI Customization
Color Themes (19 themes)
Users can choose their accent color from 19 options via the UI Settings page (/settings/ui/):
| Name |
Hex |
Preview |
| Blue |
#3b82f6 |
Default |
| Emerald |
#10b981 |
|
| Green |
#22c55e |
|
| Indigo |
#6366f1 |
|
| Orange |
#f97316 |
|
| Purple |
#a855f7 |
|
| Red |
#ef4444 |
|
| Rose |
#f43f5e |
|
| Sky |
#0ea5e9 |
|
| Teal |
#14b8a6 |
|
| Violet |
#8b5cf6 |
|
| Amber |
#f59e0b |
|
| Yellow |
#eab308 |
|
| Pink |
#ec4899 |
|
| Cyan |
#06b6d4 |
|
| Lime |
#84cc16 |
|
| Slate |
#64748b |
|
| Gray |
#6b7280 |
|
| Zinc |
#71717a |
|
Navigation Layout
- Sidebar (default) — vertical nav on the left
- Top — horizontal nav bar at the top
Dark / Light Mode
Per-user dark/light mode preference, persisted in localStorage.
Docker Deployment
Build & run
This starts:
- MySQL 8.0 (
db service) with persistent volume
- Django app (
app service) behind gunicorn on port 8000
Services
| Service |
Image |
Port |
db |
mysql:8.0 |
3306 |
app |
(builds from Dockerfile) |
8000 |
The app container automatically runs migrations on startup via docker-entrypoint.sh.
CI / CD
GitHub Actions workflow (.github/workflows/ci.yml) runs on every push/PR to main and develop:
| Job |
Steps |
| Lint |
ruff check + ruff format --check |
| Test |
Django system check → pending migration check → manage.py test --verbosity=2 |
| Security |
manage.py check --deploy |
Management Commands
| Command |
Description |
python manage.py seed_data |
Seed priorities and admin user (idempotent) |
python manage.py demo_data |
Create comprehensive demo data (14 users, 8 projects, epics, tickets, comments, notifications) |
python manage.py demo_data --clear |
Clear existing demo data before re-seeding |
python manage.py generate_vapid_keys |
Generate VAPID key pair for browser push notifications |
Environment Variables Reference
| Variable |
Default |
Required |
Description |
DJANGO_SETTINGS_MODULE |
— |
Yes |
config.settings.development or config.settings.production |
SECRET_KEY |
— |
Yes |
Django secret key (used in prod) |
ALLOWED_HOSTS |
localhost,127.0.0.1 |
No |
Comma-separated allowed hostnames |
BASE_URL |
http://localhost:8000 |
Yes |
Base URL for email links and redirects |
SITE_NAME |
Project Management |
No |
Displayed in UI, emails, and page titles |
TIME_ZONE |
Asia/Kathmandu |
No |
Server timezone |
Database (Production)
| Variable |
Default |
Description |
DB_NAME |
project_management |
MySQL database name |
DB_USER |
project_user |
MySQL user |
DB_PASSWORD |
project_password |
MySQL password |
DB_HOST |
localhost |
MySQL host |
DB_PORT |
3306 |
MySQL port |
Email (Production)
| Variable |
Default |
Description |
EMAIL_HOST |
smtp.gmail.com |
SMTP server |
EMAIL_PORT |
587 |
SMTP port |
EMAIL_USE_TLS |
True |
Enable TLS |
EMAIL_HOST_USER |
— |
SMTP username |
EMAIL_HOST_PASSWORD |
— |
SMTP password |
Google OAuth
| Variable |
Default |
Description |
GOOGLE_CLIENT_ID |
— |
Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
— |
Google OAuth secret |
GOOGLE_REDIRECT_URI |
http://localhost:8000/api/auth/google/callback/ |
OAuth callback URL |
CORS
| Variable |
Default |
Description |
FRONTEND_URL |
http://localhost:8000 |
Allowed CORS origin (production) |
Push Notifications
| Variable |
Default |
Description |
VAPID_PUBLIC_KEY |
— |
VAPID public key (base64url) for Web Push; generate with manage.py generate_vapid_keys |
VAPID_PRIVATE_KEY |
— |
VAPID private key (PEM, single-line with \n) for Web Push |
Development Details
Settings Profiles
| Profile |
File |
Database |
Debug |
Static Files |
| Development |
config.settings.development |
SQLite (WAL mode) |
True |
Django static |
| Production |
config.settings.production |
MySQL |
False |
Whitenoise (compressed, manifest) |
Authentication
- JWT tokens via
djangorestframework-simplejwt (access: 1h, refresh: 30d, rotating)
- Session-based auth for browser (Django's
SessionMiddleware + cached_db backend)
- Google OAuth for social login
- REST API uses
TokenAuthentication (SimpleJWT) + SessionAuthentication
Task Queue (Django Q2)
| Setting |
Value |
| Workers |
2 |
| Timeout |
60s |
| Retry |
120s |
| Poll interval |
2s |
| Broker |
ORM (database-backed) |
Caching
Database-backed cache (django_cache table). Used for site branding (5 min TTL) and sessions (cached_db backend).
Performance (Dev SQLite)
SQLite is configured with WAL mode, memory-mapped I/O, and performance pragmas for development.