# 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`