Files
project-managment/README.md
T
sankalp 612a3dd151 feat(push): add browser push notifications via Web Push API
Enable user opt‑in for real‑time ticket updates without third‑party services.
2026-06-30 10:22:04 +05:45

427 lines
16 KiB
Markdown

# 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](https://github.com/astral-sh/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](https://github.com/astral-sh/uv)
### 1. Clone & install
```bash
git clone https://github.com/S4NKALP/project-managment.git
cd project-managment
uv sync
```
### 2. Configure environment
```bash
cp .env.sample .env
```
Minimal `.env`:
```ini
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
```bash
uv run python manage.py migrate
uv run python manage.py createcachetable
uv run python manage.py createsuperuser
```
### 4. Start development server
```bash
uv run python manage.py runserver
```
Open **http://localhost:8000** in your browser. Authenticated users are redirected to the dashboard.
### Seed demo data (optional)
```bash
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](https://github.com/casey/just), a command runner. See all available commands:
```bash
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
```bash
docker compose up --build
```
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.