Add support for receiving push notifications, parsing JSON payload, displaying notifications with title, body, icon, badge and handling click actions to focus or open the associated URL, improving user experience with timely interactive alerts
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.