Files
project-tracker/deploy

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.

Resource requirements:

  • RAM: 512 MB minimum, 1 GB recommended
  • CPU: 1 vCPU
  • Disk: 2 GB
  • Ports: 80 (HTTP)

These are trivial requirements — runs comfortably on a 512 MB LXC or minimal VM.

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:

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