Project Tracker
A self-hosted project tracking web app. Dark-themed, minimal, fast.
Quick Start (One Command)
On a fresh Debian/Ubuntu server with Docker:
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:
- Updates system packages
- Installs Docker (if not present)
- Clones this repo
- Builds and starts the app via Docker Compose
- Shows you the URL when done
To interactively confirm before running, download first:
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:
# 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:
docker exec -it project-tracker-api node -e "
const db = require('better-sqlite3')('/app/data/projects.db');
const items = [
{name:'Pi-hole Ad Blocking',priority:'Medium',url:'https://pi-hole.net/',notes:'Network-wide ad blocking via DNS. Run on a dedicated Pi or LXC.',status:'Backlog',owner:'Admin',tags:'dns,network,security'},
{name:'Home Assistant Upgrade',priority:'Medium',url:'https://www.home-assistant.io/',notes:'Upgrade HA to latest version. Check for breaking changes in release notes first.',status:'Backlog',owner:'Admin',tags:'homeassistant,automation'},
{name:'Backup Strategy Review',priority:'Low',url:'',notes:'Audit current backup coverage. Verify VM and NAS backups are actually working.',status:'Backlog',owner:'Admin',tags:'backup,storage'},
{name:'Portainer Migration',priority:'Low',url:'https://www.portainer.io/',notes:'Move away from Portainer to native Docker CLI or Docker Compose.',status:'Backlog',owner:'Admin',tags:'docker,management'},
{name:'VLAN Segregation Audit',priority:'Low',url:'',notes:'Review VLAN configuration. Ensure IoT devices are isolated from main network.',status:'Backlog',owner:'Admin',tags:'networking,vlan,security'},
];
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
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
# 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)
{
"name": "Project Name",
"priority": "High|Med-High|Medium|Low",
"url": "https://...",
"notes": "Description...",
"status": "Active|Backlog|On Hold|Completed",
"owner": "Admin",
"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