Add select_related optimizations and sync dependency versions across pyproject.toml and requirements.txt
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
- Python 3.13+
- uv
1. Clone & install
git clone https://github.com/S4NKALP/project-managment.git
cd project-managment
uv sync
2. Configure environment
cp .env.sample .env
Minimal .env:
DJANGO_SETTINGS_MODULE=config.settings.development
SECRET_KEY=your-secret-key
BASE_URL=http://localhost:8000
SITE_NAME=Project Management
3. Run migrations & create superuser
uv run python manage.py migrate
uv run python manage.py createcachetable
uv run python manage.py createsuperuser
4. Start development server
uv run python manage.py runserver
Open http://localhost:8000 in your browser. Authenticated users are redirected to the dashboard.
Seed demo data (optional)
uv run python manage.py seed_data # creates priorities + admin user
uv run python manage.py demo_data # creates rich demo content
Using just (recommended)
Install just, a command runner. See all available commands:
just
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
project-managment/
├── config/ # Django configuration
│ ├── settings/
│ │ ├── base.py # Shared settings (shared by dev & prod)
│ │ ├── development.py # Dev overrides (SQLite, DEBUG=True)
│ │ └── production.py # Prod overrides (MySQL, HTTPS, HSTS)
│ ├── urls.py # Root URL configuration
│ ├── wsgi.py
│ └── asgi.py
│
├── src/ # Application code
│ ├── accounts/ # Custom User model, auth, Google OAuth
│ ├── projects/ # Projects & members API, automation rules
│ ├── tickets/ # Tickets, statuses, priorities API
│ ├── epics/ # Epics API
│ ├── notes/ # Project notes API
│ ├── notifications/ # In-app, email & browser push notifications
│ ├── external/ # External token-based read-only access
│ └── dashboard/ # All HTML-rendering views
│ ├── views/ # Dashboard widgets & charts
│ ├── list_views/ # Paginated list views
│ ├── page_views/ # CRUD page views (create/edit forms)
│ ├── board_views/ # Kanban board views
│ ├── context_processors.py # Template context injection
│ └── filters.py # Ticket/project filter sets
│
├── templates/ # Django/Jinja HTML templates
│ ├── auth/ # Login page
│ ├── base.html # Base layout (nav, theme, modals)
│ ├── dashboard/ # Dashboard page, partials
│ ├── projects/ # Project detail, form, list, board
│ ├── tickets/ # Ticket detail, form, list
│ ├── epics/ # Epic overview, form
│ ├── notifications/ # Notification list, dropdown
│ ├── settings/ # UI settings (theme, nav, items per page)
│ ├── users/ # User profile, list, form
│ └── components/ # Reusable modals, rich text editor
│
├── static/ # Static files (CSS, JS, images)
├── manage.py
├── pyproject.toml # Dependencies, ruff config, project metadata
├── justfile # Task runner commands
├── Dockerfile # Production container (Python 3.13-slim)
├── docker-compose.yml # MySQL + app services
├── docker-entrypoint.sh # Runs migrations on container start
└── .env.sample # Environment variable template
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
docker compose up --build
This starts:
- MySQL 8.0 (
dbservice) with persistent volume - Django app (
appservice) 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_dbbackend) - 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.