🇰🇷 칸반 보드, 목록 뷰, 멤버 관리, 알림, Google OAuth 로그인을 갖춘 오픈소스 설치형 이슈 트래커.
🇺🇸 Open source self-hosted issue tracker with Kanban board, list view, member management, notifications, and Google OAuth login.
🇪🇸 Rastreador de incidencias de código abierto autoalojado con tablero Kanban, vista de lista, gestión de miembros, notificaciones e inicio de sesión con Google OAuth.
🇫🇷 Outil de suivi d'incidents open source auto-hébergé avec tableau Kanban, vue liste, gestion des membres, notifications et connexion Google OAuth.
🇯🇵 カンバンボード、リストビュー、メンバー管理、通知、Google OAuthログインを備えたオープンソースのセルフホスト型イシュートラッカー。
🇨🇳 开源自托管问题追踪工具,支持看板视图、列表视图、成员管理、通知和 Google OAuth 登录。
🇹🇼 開源自托管問題追蹤工具,支援看板檢視、清單檢視、成員管理、通知與 Google OAuth 登入。
🇭🇰 開源自架問題追蹤工具,支援睇板、清單、成員管理、通知同 Google OAuth 登入。
🇻🇳 Công cụ theo dõi sự cố mã nguồn mở tự lưu trữ với bảng Kanban, chế độ xem danh sách, quản lý thành viên, thông báo và đăng nhập Google OAuth.
🇮🇩 Pelacak isu open source yang dapat dihosting sendiri dengan papan Kanban, tampilan daftar, manajemen anggota, notifikasi, dan login Google OAuth.
Demo: https://boxer.coroke.net
Tasks
PROJ-42)Projects
Team
Notifications
Search
GitHub Integration
PROJ-42) are logged in the activity historyfixes, closes, or resolves followed by the task referenceOutgoing Webhooks
task.created, task.updated, task.status_changed, task.commentX-Boxer-Signature-256 header for payload verificationUX
git clone https://github.com/rainygirl/boxer.git
cd boxer
Go to Google Cloud Console → APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID.
Web applicationhttp://localhost:5173/accounts/google/login/callback/https://your-domain.com/accounts/google/login/callback/
```cp .env.example .env
Open .env (project root) and fill in the required values:
SECRET_KEY=<a-long-random-string>
JWT_SECRET=<another-long-random-string>
GOOGLE_CLIENT_ID=<your-google-client-id>
GOOGLE_CLIENT_SECRET=<your-google-client-secret>
Security notes
SECRET_KEYandJWT_SECRETmust be long, random, and different from each other.- Generate them with:
python3 -c "import secrets; print(secrets.token_hex(50))"- Never commit
.envto version control. It is already listed in.gitignore. Only.env.example(which contains no real secrets) should be committed.- Set
DEBUG=Falsein any environment accessible from the internet.
npm run setup
This runs the following in sequence:
.venv.venv/bin/pip3python3 manage.py migrate (creates server/boxer.db)npm install inside client/No need to manually activate the virtual environment — all scripts use .venv automatically.
From the project root, start both backend and frontend with a single command:
npm run dev
| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend API | http://localhost:4000 |
| API docs (Swagger) | http://localhost:4000/api/docs |
| Django admin | http://localhost:4000/admin |
To run them separately:
# Backend only
cd server && python3 manage.py runserver 4000
# Frontend only
cd client && npm run dev
npm run build
Builds the frontend and collects Django static files.
npm start
Gunicorn serves both the frontend and API on a single port.
| Service | URL |
|---|---|
| App (frontend + API) | http://localhost:4173 |
| API docs (Swagger) | http://localhost:4173/api/docs |
| Django admin | http://localhost:4173/admin |
Production still uses port 4173 (gunicorn).
Notes
- Set
DEBUG=FalseandALLOWED_HOSTS=your-domain.comin.env.- Set
CLIENT_URL=https://your-domain.comin.env.
boxer/
├── package.json # Root dev scripts (concurrently)
├── .env # Local secrets — NOT committed (gitignored)
├── .env.example # Template — safe to commit
│
├── server/ # Django backend
│ ├── manage.py
│ └── requirements.txt
│ ├── boxer.db # SQLite database — NOT committed
│ ├── config/
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── api.py # Django Ninja router root
│ ├── accounts/ # User model, JWT auth, OAuth callback
│ ├── projects/ # Project + member CRUD
│ ├── tasks/ # Task CRUD + kanban move
│ └── notifications/ # In-app notifications
│
└── client/ # SvelteKit frontend
├── vite.config.ts # Proxy: /api, /auth, /accounts → :4000 (dev)
└── src/
├── lib/
│ ├── api/ # Axios API clients
│ ├── components/ # UI components (Sidebar, Kanban, Table, …)
│ ├── i18n/ # Translations (10 languages)
│ ├── stores/ # Svelte stores (auth, theme, ui)
│ └── types/ # TypeScript types
└── routes/
├── login/ # Google login page
├── auth/callback/ # Receives JWT from backend
└── app/ # Protected area (auth guard)
├── project/[projectId]/
├── my-issues/
├── notifications/
└── members/
Full interactive docs available at http://localhost:4000/api/docs (dev) or http://localhost:4173/api/docs (production).
All endpoints require Authorization: Bearer <JWT>.
| Method | Path | Description |
|---|---|---|
| GET | /api/auth/me |
Get current user |
| PATCH | /api/auth/me |
Update profile (nickname) |
| GET | /api/projects/ |
List projects |
| POST | /api/projects/ |
Create project |
| PATCH | /api/projects/{id} |
Update project (owner only) |
| DELETE | /api/projects/{id} |
Delete project (owner only) |
| GET | /api/projects/{id}/members |
List members |
| POST | /api/projects/{id}/members |
Invite member by email |
| PATCH | /api/projects/{id}/members |
Change member role |
| DELETE | /api/projects/{id}/members |
Remove member |
| GET | /api/tasks/project/{projectId} |
List tasks |
| POST | /api/tasks/project/{projectId} |
Create task |
| PATCH | /api/tasks/{id} |
Update task |
| PATCH | /api/tasks/{id}/move |
Move task (drag & drop) |
| DELETE | /api/tasks/{id} |
Delete task |
| GET | /api/notifications/ |
List notifications |
| PATCH | /api/notifications/{id}/read |
Mark as read |
| POST | /api/notifications/read-all |
Mark all as read |
1. Browser → /accounts/google/login/
2. Google login → /accounts/google/login/callback/ (allauth)
3. allauth creates Django session → redirects to /auth/jwt/
4. /auth/jwt/ issues JWT, clears session
→ redirects to http://localhost:5173/auth/callback?token=<JWT>
5. SvelteKit stores token in localStorage → navigates to /app
6. All subsequent API calls send Authorization: Bearer <JWT>
cd server
python3 manage.py makemigrations
python3 manage.py migrate
cd server
rm boxer.db
python3 manage.py migrate
| Variable | Required | Description |
|---|---|---|
SECRET_KEY |
Yes | Django cryptographic signing key |
JWT_SECRET |
Yes | JWT token signing key |
GOOGLE_CLIENT_ID |
Yes | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
Yes | Google OAuth client secret |
DEBUG |
No | True (default) or False for production |
ALLOWED_HOSTS |
No | Comma-separated hostnames (default: localhost,127.0.0.1) |
CLIENT_URL |
No | Frontend origin for CORS (default: http://localhost:5173) |
BACKEND_URL |
No | Internal Django URL for SvelteKit → Django webhook proxy (default: http://127.0.0.1:4000) |
DISABLE_FILE_UPLOAD |
No | Set to True to disable file uploads across the entire app (default: False) |
DEMO_MODE |
No | Set to True to auto-add every logged-in user to the demo project and redirect them to it on entry (default: False) |
DEMO_PROJECT_ID |
No | UUID of the project to use as the demo workspace (required when DEMO_MODE=True) |
R2_ACCOUNT_ID |
No | Cloudflare R2 account ID (file attachments) |
R2_ACCESS_KEY_ID |
No | Cloudflare R2 access key |
R2_SECRET_ACCESS_KEY |
No | Cloudflare R2 secret key |
R2_BUCKET_NAME |
No | R2 bucket name (default: boxer) |
R2_PUBLIC_URL |
No | Public URL of the R2 bucket |
🇰🇷 기여를 환영합니다! 새로운 기능, UI 개선, 워크플로우 아이디어 등 Boxer를 더 좋게 만들 수 있다고 생각하는 것이라면 무엇이든 코드로 제안해 주세요. 정해진 범위는 없습니다. 창의적인 아이디어가 있다면 PR로 자유롭게 올려주세요.
🇺🇸 Contributions are welcome! Feel free to open a PR with any ideas you'd like to explore — new features, UI improvements, workflow enhancements, or anything else you think would make Boxer better. There's no strict scope; if you have a creative idea, bring it as code.
🇪🇸 ¡Las contribuciones son bienvenidas! Siéntete libre de abrir un PR con cualquier idea que quieras explorar: nuevas funcionalidades, mejoras de UI, flujos de trabajo u otras ideas que creas que mejorarían Boxer. No hay un alcance estricto; si tienes una idea creativa, preséntala como código.
🇫🇷 Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une PR avec vos idées — nouvelles fonctionnalités, améliorations de l'interface, flux de travail ou tout ce qui pourrait améliorer Boxer. Il n'y a pas de périmètre strict ; si vous avez une idée créative, proposez-la sous forme de code.
🇯🇵 コントリビューションを歓迎します!新機能、UIの改善、ワークフローのアイデアなど、Boxerをより良くするためのアイデアがあれば、コードとしてPRを送ってください。範囲に制限はありません。クリエイティブなアイデアがあれば、ぜひ提案してください。
🇨🇳 欢迎贡献!无论是新功能、UI 改进、工作流优化,还是任何你认为能让 Boxer 更好的想法,都欢迎以代码形式提交 PR。没有严格的范围限制,如果你有创意想法,尽管提出来吧。
🇹🇼 歡迎貢獻!無論是新功能、UI 改進、工作流程優化,或任何你認為能讓 Boxer 更好的想法,都歡迎以程式碼形式提交 PR。沒有嚴格的範圍限制,有創意的想法儘管提出來吧。
🇭🇰 歡迎貢獻!無論係新功能、UI 改進、工作流程優化,定係任何你覺得可以令 Boxer 更好嘅想法,都歡迎以程式碼形式提交 PR。冇嚴格嘅範圍限制,有創意嘅想法儘管提出嚟囉。
🇻🇳 Đóng góp luôn được chào đón! Hãy thoải mái mở PR với bất kỳ ý tưởng nào bạn muốn thử — tính năng mới, cải tiến giao diện, luồng công việc hay bất cứ điều gì bạn nghĩ sẽ giúp Boxer tốt hơn. Không có phạm vi cứng nhắc; nếu bạn có ý tưởng sáng tạo, hãy đưa nó vào code.
🇮🇩 Kontribusi sangat disambut! Silakan buka PR dengan ide apa pun yang ingin kamu eksplorasi — fitur baru, peningkatan UI, alur kerja, atau hal lain yang menurutmu bisa membuat Boxer lebih baik. Tidak ada batasan ketat; jika kamu punya ide kreatif, sampaikan dalam bentuk kode.
MIT