190 lines
5.4 KiB
Markdown
190 lines
5.4 KiB
Markdown
# Project Tracker
|
|
|
|
A self-hosted project tracking web app. Dark-themed, minimal, fast.
|
|
|
|
**Live:** https://projects.ledrew.me
|
|
|
|
---
|
|
|
|
## Quick Start (One Command)
|
|
|
|
On a **fresh Debian/Ubuntu** server with Docker:
|
|
|
|
```bash
|
|
curl -sL https://gitea.ledrew.me/ledadmin/project-tracker/raw/branch/master/deploy/setup.sh -o setup.sh && bash setup.sh
|
|
```
|
|
|
|
That's it. The script handles everything: system update → Docker → Docker Compose → clone → build → start.
|
|
|
|
**Requires:** Debian/Ubuntu, root access, port 80 available.
|
|
|
|
**What it does:**
|
|
1. Updates system packages
|
|
2. Installs Docker (if not present)
|
|
3. Clones this repo
|
|
4. Builds and starts the app via Docker Compose
|
|
5. Shows you the URL when done
|
|
|
|
To interactively confirm before running, download first:
|
|
```bash
|
|
curl -sL https://gitea.ledrew.me/ledadmin/project-tracker/raw/branch/master/deploy/setup.sh -o setup.sh
|
|
bash setup.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Manual Docker Install
|
|
|
|
If you prefer to install manually or already have Docker:
|
|
|
|
```bash
|
|
# Install Docker
|
|
apt-get update
|
|
apt-get install -y docker.io docker-compose
|
|
|
|
# Clone and start
|
|
git clone https://gitea.ledrew.me/ledadmin/project-tracker.git
|
|
cd project-tracker/deploy
|
|
docker compose up -d --build
|
|
```
|
|
|
|
---
|
|
|
|
## Seed Sample Projects
|
|
|
|
After first deploy, populate with sample projects:
|
|
|
|
```bash
|
|
docker exec -it project-tracker-api node -e "
|
|
const db = require('better-sqlite3')('/app/data/projects.db');
|
|
const items = [
|
|
{name:'Bastion setup with Headscale/Tailscale',priority:'Medium',url:'',notes:'Use i3-4130T as hardened jump-box/gateway into homelab.',status:'Active',owner:'Ada',tags:'vpn,homelab,security'},
|
|
{name:'Outline',priority:'Med-High',url:'https://www.getoutline.com/',notes:'Self-hosted knowledge base/wiki (Notion alternative).',status:'Backlog',owner:'Ada',tags:'wiki,notes'},
|
|
{name:'Tinyauth',priority:'Med-High',url:'https://tinyauth.app/',notes:'Self-hosted zero-trust authentication platform.',status:'Backlog',owner:'Ada',tags:'auth,security'},
|
|
{name:'TDarr',priority:'Medium',url:'https://github.com/HaveAGitGat/Tdarr',notes:'Video transcode automation for Plex/Jellyfin.',status:'Backlog',owner:'Ada',tags:'media,transcode'},
|
|
{name:'Retro ROM Collection Organization',priority:'Low',url:'',notes:'Catalog and organize extensive ROM collection.',status:'Backlog',owner:'Ada',tags:'gaming,retro,emulation'},
|
|
];
|
|
const stmt = db.prepare('INSERT INTO projects (name,priority,url,notes,status,owner,tags) VALUES (?,?,?,?,?,?,?)');
|
|
items.forEach(i => stmt.run(i.name,i.priority,i.url,i.notes,i.status,i.owner,i.tags));
|
|
console.log('Seeded', items.length, 'projects');
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
## Useful Commands
|
|
|
|
```bash
|
|
docker compose logs -f # View logs
|
|
docker compose logs -f backend # Backend logs only
|
|
docker compose restart # Restart
|
|
docker compose down # Stop
|
|
docker compose down -v # Stop and DELETE database (CAREFUL!)
|
|
docker exec -it project-tracker-api sh # Shell into backend
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `PORT` | `3000` | Backend port (internal) |
|
|
| `NODE_ENV` | `production` | Node environment |
|
|
| `DATA_DIR` | `/app/data` | SQLite data directory |
|
|
|
|
---
|
|
|
|
## Ports
|
|
|
|
| Port | Service |
|
|
|---|---|
|
|
| `80` | nginx (frontend + API proxy) |
|
|
| `3000` | Backend API (internal only) |
|
|
|
|
---
|
|
|
|
## Updating
|
|
|
|
```bash
|
|
# With setup.sh (pulls latest, rebuilds):
|
|
curl -sL https://gitea.ledrew.me/ledadmin/project-tracker/raw/branch/master/deploy/setup.sh -o setup.sh && bash setup.sh
|
|
|
|
# Manual update:
|
|
cd project-tracker
|
|
git pull
|
|
docker compose down
|
|
docker compose up -d --build
|
|
```
|
|
|
|
---
|
|
|
|
## SSL / HTTPS
|
|
|
|
For HTTPS, put nginx behind a reverse proxy (e.g., NginxProxyManager, Traefik, Caddy) on port 80/443. The nginx container should NOT be exposed directly to the internet.
|
|
|
|
---
|
|
|
|
## Stack
|
|
|
|
- **Backend:** Node.js + Express + better-sqlite3
|
|
- **Frontend:** Vanilla JS + CSS (no framework, no build step)
|
|
- **Web Server:** nginx (reverse proxy + static files)
|
|
- **Database:** SQLite (single file, no server process)
|
|
- **Deploy:** Docker Compose (2 containers: backend + nginx)
|
|
|
|
---
|
|
|
|
## API
|
|
|
|
| Method | Endpoint | Description |
|
|
|---|---|---|
|
|
| GET | `/api/projects` | List all projects |
|
|
| GET | `/api/projects/:id` | Get single project |
|
|
| POST | `/api/projects` | Create project |
|
|
| PUT | `/api/projects/:id` | Update project |
|
|
| DELETE | `/api/projects/:id` | Delete project |
|
|
|
|
### Body (POST/PUT)
|
|
|
|
```json
|
|
{
|
|
"name": "Project Name",
|
|
"priority": "High|Med-High|Medium|Low",
|
|
"url": "https://...",
|
|
"notes": "Description...",
|
|
"status": "Active|Backlog|On Hold|Completed",
|
|
"owner": "Ada",
|
|
"tags": "tag1,tag2"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
```
|
|
project-tracker/
|
|
├── deploy/
|
|
│ ├── docker-compose.yml # Services definition
|
|
│ ├── Dockerfile # Backend (Node.js)
|
|
│ ├── Dockerfile.nginx # nginx + frontend
|
|
│ ├── nginx.conf # Reverse proxy config
|
|
│ ├── setup.sh # One-shot deploy script
|
|
│ ├── www/ # Frontend (baked into nginx)
|
|
│ │ ├── index.html
|
|
│ │ └── favicon.png
|
|
│ └── README.md
|
|
└── backend/
|
|
├── server.js # Express API
|
|
└── package.json
|
|
```
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- No authentication on the API — intended for internal use behind a reverse proxy
|
|
- CORS is open for development; restrict in production if needed
|
|
- Database persists in Docker named volume — survives `docker compose down/up`
|