2026-03-05 11:53:28 -06:00
# FabDash
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
**Fabrication Dashboard** — A sleek, modern project management & scheduling application built for fabrication workflows.
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00

2026-03-05 11:53:28 -06:00


2026-03-05 11:59:14 -06:00

2026-03-05 11:53:28 -06:00
---
## Table of Contents
- [Overview ](#overview )
- [Tech Stack ](#tech-stack )
- [Project Structure ](#project-structure )
- [Features ](#features )
2026-03-05 15:24:34 -06:00
- [Interaction Reference ](#interaction-reference )
2026-03-05 11:53:28 -06:00
- [API Reference ](#api-reference )
2026-03-05 15:24:34 -06:00
- [Component Architecture ](#component-architecture )
2026-03-05 12:13:22 -06:00
- [Unraid Installation ](#unraid-installation )
2026-03-05 12:20:22 -06:00
- [Updating FabDash on Unraid ](#updating-fabdash-on-unraid )
2026-03-05 11:59:14 -06:00
- [Local Development ](#local-development )
2026-03-05 11:53:28 -06:00
- [Environment Variables ](#environment-variables )
- [Database Schema ](#database-schema )
- [Roadmap ](#roadmap )
2026-03-05 11:59:14 -06:00
2026-03-05 11:53:28 -06:00
---
## Overview
2026-03-05 15:24:34 -06:00
FabDash is a self-hosted, full-stack project management dashboard built for fabrication teams. It features a large interactive calendar, multi-deliverable project tracking, drag-and-drop scheduling, a per-project timeline Focus View, and a rich right-click context menu system. All wrapped in a dark/gold UI and deployed as a single Docker container with no external dependencies.
2026-03-05 11:53:28 -06:00
---
## Tech Stack
2026-03-05 15:24:34 -06:00
### Frontend
| Package | Version | Purpose |
|---|---|---|
| React | ^18.3.1 | UI framework |
| Vite | ^5.4.11 | Build tool and dev server |
| Tailwind CSS | ^3.4.15 | Utility-first styling |
| @fullcalendar/core | 6.1.15 | FullCalendar core (pinned) |
| @fullcalendar/react | 6.1.15 | Calendar component |
| @fullcalendar/daygrid | 6.1.15 | Month/week grid view |
| @fullcalendar/timegrid | 6.1.15 | Time-slot view |
| @fullcalendar/interaction | 6.1.15 | Drag-and-drop, click events |
| react-chrono | 2.6.0 | Focus View timeline (pinned — last React 18 compatible) |
| Zustand | ^4.5.5 | Global state management |
| Axios | ^1.7.9 | HTTP client |
| date-fns | ^3.6.0 | Date formatting |
> **Note:** All FullCalendar packages are pinned to exactly `6.1.15` to prevent version mismatch errors during Docker builds. `react-chrono` is pinned to `2.6.0` — versions ≥ 2.7.0 require React 19.
### Backend
| Package | Version | Purpose |
|---|---|---|
| Flask | 3.1.0 | REST API + static file serving |
| Flask-SQLAlchemy | 3.1.1 | ORM for SQLite |
| Flask-Migrate | 4.0.7 | Schema migration support |
| Flask-CORS | 5.0.0 | Cross-origin support (dev) |
| Gunicorn | 23.0.0 | Production WSGI server |
### Database
- **SQLite** — Zero-config, file-based persistence at `/app/data/fabdash.db`
- Mounted as a named Docker volume so data survives all container restarts and rebuilds
- **Inline migrations** — New columns are applied automatically on startup via `_run_migrations()` in `app/__init__.py` ; no manual migration commands required
2026-03-05 11:53:28 -06:00
---
## Project Structure
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
fabdash/
2026-03-05 11:59:14 -06:00
├── Dockerfile
├── docker-compose.yml
2026-03-05 11:53:28 -06:00
├── .env.example
├── .gitignore
2026-03-05 11:59:14 -06:00
├── README.md
│
├── backend/
│ ├── run.py
│ ├── config.py
│ ├── requirements.txt
│ └── app/
2026-03-05 15:24:34 -06:00
│ ├── __init __ .py # App factory + inline migrations
2026-03-05 11:59:14 -06:00
│ ├── extensions.py
2026-03-05 15:24:34 -06:00
│ ├── models.py # Project + Deliverable models
2026-03-05 11:59:14 -06:00
│ └── routes/
2026-03-05 12:13:22 -06:00
│ ├── __init __ .py
2026-03-05 11:59:14 -06:00
│ ├── projects.py
│ └── deliverables.py
│
└── frontend/
├── package.json
2026-03-05 15:24:34 -06:00
├── vite.config.js # optimizeDeps for FullCalendar
2026-03-05 11:59:14 -06:00
├── tailwind.config.js
2026-03-05 12:13:22 -06:00
├── postcss.config.js
2026-03-05 11:59:14 -06:00
├── index.html
└── src/
├── main.jsx
├── App.jsx
├── api/
│ ├── projects.js
│ └── deliverables.js
├── components/
│ ├── Calendar/
2026-03-05 15:24:34 -06:00
│ │ └── MainCalendar.jsx # dblclick + right-click on events
2026-03-05 11:59:14 -06:00
│ ├── Projects/
│ │ ├── ProjectList.jsx
2026-03-05 15:24:34 -06:00
│ │ ├── ProjectCard.jsx # dblclick + right-click, Drive link
│ │ └── ProjectModal.jsx # Drive URL input field
2026-03-05 11:59:14 -06:00
│ ├── Deliverables/
2026-03-05 12:13:22 -06:00
│ │ └── DeliverableModal.jsx
2026-03-05 11:59:14 -06:00
│ ├── FocusView/
│ │ ├── FocusDrawer.jsx
2026-03-05 15:24:34 -06:00
│ │ ├── FocusTimeline.jsx # Click any card to activate
│ │ └── DeliverableCard.jsx # dblclick + right-click, status menu
2026-03-05 11:59:14 -06:00
│ └── UI/
│ ├── Button.jsx
│ ├── Badge.jsx
│ ├── Modal.jsx
2026-03-05 15:24:34 -06:00
│ ├── Drawer.jsx
│ └── ContextMenu.jsx # Floating right-click menu
2026-03-05 11:59:14 -06:00
├── store/
│ ├── useProjectStore.js
2026-03-05 15:24:34 -06:00
│ └── useFocusStore.js # setActiveDeliverable action
2026-03-05 11:59:14 -06:00
├── utils/
│ ├── dateHelpers.js
│ └── statusHelpers.js
└── styles/
└── globals.css
```
2026-03-05 11:53:28 -06:00
---
2026-03-05 12:13:22 -06:00
## Features
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
### Calendar
- **Large full-width calendar** — Month, Week, and Day views via FullCalendar
- **Drag-and-drop rescheduling** — Move any deliverable to a new date; backend patches immediately
- **Click empty date cell** — Opens Add Deliverable modal pre-filled with that date
- **Single-click event** — Opens Deliverable Focus View
- **Double-click event** — Opens Edit Deliverable modal directly
- **Right-click event** — Context menu (Edit, Focus View, Open Drive, Delete)
### Projects
- **Multi-deliverable projects** — Add unlimited deliverables per project, each with its own title, due date, and status
- **Inline creation** — Add all deliverables while creating the project in a single form submission
- **Color coding** — 12-swatch palette + custom hex input; color appears on calendar events and sidebar cards
- **Google Drive link** — Optional Drive folder URL stored per project; appears as a button on the project card and in context menus
- **Double-click project header** — Opens Edit Project modal instantly
- **Right-click project header** — Context menu (Edit, Open Drive, Delete)
### Deliverables
- **Status tracking** — Upcoming / In Progress / Completed / Overdue
- **Auto-overdue detection** — Any deliverable whose due date has passed is automatically returned as `overdue` by the API unless it is marked `completed` . Logic is computed at read time — no cron job needed
- **Double-click sidebar row** — Opens Edit Deliverable modal
- **Right-click sidebar row** — Context menu (Edit, Focus View, Delete)
### Deliverable Focus View
- **Slide-up drawer** — Triggered by clicking any calendar event or sidebar deliverable
- **Horizontal timeline** — All deliverables for the project rendered in date order
- **Active card highlighting** — Clicked deliverable glows in gold with a "Selected" badge
- **Click any card** — Switches the active/selected card without closing the drawer
- **Double-click any card** — Opens Edit Deliverable modal
- **Right-click any card** — Context menu with quick status change (all 4 statuses), Edit, and Delete
### Right-Click Context Menu
A custom floating `ContextMenu` component appears at the cursor position and auto-adjusts to stay within the viewport. It closes on outside click or `Escape` . Available everywhere:
| Trigger | Menu Items |
|---|---|
| Calendar event | Edit Deliverable, Open Focus View, Open Drive*, Delete |
| Sidebar project header | Edit Project, Open Drive*, Delete Project |
| Sidebar deliverable row | Edit Deliverable, Open Focus View, Delete |
| Focus View card | Edit Deliverable, Mark Upcoming/In Progress/Completed/Overdue, Delete |
*Only shown when a Drive URL is set on the project.
### Theme & Design System
```js
// tailwind.config.js — custom tokens
colors: {
gold: '#C9A84C ', // Primary accent
'gold-light': '#E8C96A ',
'gold-muted': '#8A6E2F ',
surface: '#111111 ', // Page background
'surface-raised': '#1A1A1A ', // Sidebar, drawer
'surface-elevated': '#242424 ', // Cards
'surface-border': '#2E2E2E ', // Borders
'text-primary': '#F5F5F5 ',
'text-muted': '#888888 ',
}
```
---
## Interaction Reference
| Location | Single Click | Double Click | Right Click |
|---|---|---|---|
| Calendar event | Open Focus View | Edit Deliverable modal | Context menu |
| Calendar empty cell | Add Deliverable (pre-filled date) | — | — |
| Sidebar project header | — | Edit Project modal | Context menu |
| Sidebar deliverable row | Open Focus View | Edit Deliverable modal | Context menu |
| Focus View card | Select / activate | Edit Deliverable modal | Context menu |
| Focus View active card Edit button | Edit Deliverable modal | — | — |
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
---
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
## API Reference
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
### Projects
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/projects` | List all projects with nested deliverables |
2026-03-05 12:20:22 -06:00
| `POST` | `/api/projects` | Create project (with optional inline deliverables) |
2026-03-05 12:13:22 -06:00
| `GET` | `/api/projects/:id` | Get single project |
2026-03-05 15:24:34 -06:00
| `PATCH` | `/api/projects/:id` | Update name, color, description, or drive_url |
2026-03-05 12:13:22 -06:00
| `DELETE` | `/api/projects/:id` | Delete project + cascade deliverables |
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
### Deliverables
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/deliverables?project_id=:id` | List deliverables for a project |
| `POST` | `/api/deliverables` | Create deliverable |
| `PATCH` | `/api/deliverables/:id` | Update title, due_date, or status |
| `DELETE` | `/api/deliverables/:id` | Delete deliverable |
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
**Example — Create Project:**
```json
POST /api/projects
{
"name": "CODA",
"color": "#4A90D9 ",
"description": "ADA Call Column and Shelter Equipment Box",
"drive_url": "https://drive.google.com/drive/folders/your-folder-id",
"deliverables": [
{ "title": "Cut Extrusion to Length", "due_date": "2026-03-05", "status": "in_progress" },
{ "title": "Cut Faceplates and Top Plates", "due_date": "2026-03-06", "status": "upcoming" },
{ "title": "Fabricate Shelter Assembly Box", "due_date": "2026-03-11", "status": "upcoming" }
]
}
```
---
## Component Architecture
```
App
├── Sidebar
│ ├── ProjectList
│ │ └── ProjectCard (× N) ← dblclick + right-click
│ │ ├── DeliverableRow (× N) ← dblclick + right-click
│ │ ├── DeliverableModal (local)
│ │ └── ContextMenu (local)
│ └── Button ["+ Project"]
│
├── MainCalendar ← FullCalendar + eventDidMount
│ ├── FullCalendar events ← dblclick + right-click via DOM
│ ├── DeliverableModal
│ └── ContextMenu
│
└── FocusDrawer (slide-up)
├── FocusTimeline
│ └── DeliverableCard (× N) ← click=select, dblclick=edit, right-click=menu
│ └── ContextMenu (local)
└── DeliverableModal
```
2026-03-05 12:13:22 -06:00
---
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
## Unraid Installation
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
FabDash is installed by cloning the repo and building the Docker image locally on your Unraid server via SSH, then managing the container through the Unraid Docker GUI.
2026-03-05 11:53:28 -06:00
---
2026-03-05 12:20:22 -06:00
### Step 1 — Enable SSH on Unraid
2026-03-05 12:13:22 -06:00
2026-03-05 15:24:34 -06:00
Go to **Settings → Management Access ** and confirm SSH is enabled. Note your Unraid server's local IP address from the dashboard header.
2026-03-05 12:13:22 -06:00
2026-03-05 12:20:22 -06:00
---
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
### Step 2 — SSH into Unraid and Clone the Repo
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
```bash
ssh root@YOUR_UNRAID_IP
cd /mnt/user/appdata
git clone https://github.com/yourname/fabdash.git
cd fabdash
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
---
2026-03-05 15:24:34 -06:00
### Step 3 — Build the Docker Image
2026-03-05 12:20:22 -06:00
2026-03-05 15:24:34 -06:00
Builds the image on your Unraid server and tags it `fabdash:latest` .
First build takes 3– 5 minutes (downloads Node + Python layers, compiles React).
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
```bash
2026-03-05 12:20:22 -06:00
docker build -t fabdash:latest .
2026-03-05 12:13:22 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
Verify the image exists:
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
```bash
docker images | grep fabdash
2026-03-05 12:13:22 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
---
### Step 4 — Create the Data Directory
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
```bash
2026-03-05 12:20:22 -06:00
mkdir -p /mnt/user/appdata/fabdash/data
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
---
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
### Step 5 — Add the Container via Unraid Docker GUI
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
1. Go to the **Docker ** tab in Unraid
2. Click **Add Container ** at the bottom
3. Toggle **Advanced View ** in the top-right of the form
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
#### Basic Settings
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
| Field | Value |
|---|---|
| **Name ** | `fabdash` |
| **Repository ** | `fabdash:latest` |
| **Docker Hub URL ** | * (leave blank — local image) * |
| **Network Type ** | `Bridge` |
| **Console shell command ** | `bash` |
| **Privileged ** | `Off` |
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
#### Port Mapping
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
Click **Add another Path, Port, Variable, Label or Device ** → **Port ** :
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
| Field | Value |
|---|---|
| **Name ** | `Web UI` |
| **Container Port ** | `8080` |
| **Host Port ** | `8080` |
| **Connection Type ** | `TCP` |
2026-03-05 12:13:22 -06:00
2026-03-05 15:24:34 -06:00
> Change Host Port if `8080` is already in use. Access FabDash at `http://YOUR_UNRAID_IP:8080`
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
#### Volume / Path Mapping
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
Click **Add another Path, Port, Variable, Label or Device ** → **Path ** :
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
| Field | Value |
|---|---|
| **Name ** | `AppData` |
| **Container Path ** | `/app/data` |
| **Host Path ** | `/mnt/user/appdata/fabdash/data` |
| **Access Mode ** | `Read/Write` |
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
> Your database (`fabdash.db`) lives here and survives all rebuilds and reboots.
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
#### Environment Variables
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
Add each as **Variable ** :
2026-03-05 11:53:28 -06:00
2026-03-05 12:20:22 -06:00
| Name | Key | Value |
|---|---|---|
2026-03-05 15:24:34 -06:00
| Secret Key | `SECRET_KEY` | * (generate below) * |
2026-03-05 12:20:22 -06:00
| Flask Environment | `FLASK_ENV` | `production` |
| Database URL | `DATABASE_URL` | `sqlite:////app/data/fabdash.db` |
2026-03-05 15:24:34 -06:00
Generate a strong `SECRET_KEY` from the Unraid terminal:
```bash
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 48 | head -n 1
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
#### Extra Parameters
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
| Field | Value |
|---|---|
2026-03-05 12:20:22 -06:00
| **Extra Parameters ** | `--restart unless-stopped` |
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
---
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
### Step 6 — Apply and Launch
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
Click **Apply ** . The container starts using your locally built image.
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
Open your browser: * * `http://YOUR_UNRAID_IP:8080` **
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
---
### Step 7 — Verify (Optional)
2026-03-05 15:24:34 -06:00
Check logs from the Unraid Docker tab → click `fabdash` → **Logs ** , or via SSH:
2026-03-05 12:20:22 -06:00
```bash
docker logs fabdash --tail 50
```
A healthy startup looks like:
```
[INFO] Starting gunicorn 23.0.0
[INFO] Listening at: http://0.0.0.0:8080
[INFO] Worker booting (pid: ...)
```
---
## Updating FabDash on Unraid
2026-03-05 15:24:34 -06:00
### Step 1 — Pull latest code and rebuild
2026-03-05 12:20:22 -06:00
```bash
ssh root@YOUR_UNRAID_IP
cd /mnt/user/appdata/fabdash
git pull
docker build -t fabdash:latest .
```
2026-03-05 15:24:34 -06:00
### Step 2 — Restart via Unraid Docker GUI
2026-03-05 12:20:22 -06:00
2026-03-05 15:24:34 -06:00
Go to **Docker ** tab → click the `fabdash` container icon → **Restart **
2026-03-05 12:20:22 -06:00
2026-03-05 15:24:34 -06:00
The container reloads with the new image. Your database is untouched.
New schema columns (if any) are applied automatically on startup.
2026-03-05 12:20:22 -06:00
### Step 3 — Verify
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
```bash
docker logs fabdash --tail 20
```
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
---
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
## Data Backup
2026-03-05 11:59:14 -06:00
2026-03-05 12:20:22 -06:00
Your database lives at:
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
```
/mnt/user/appdata/fabdash/data/fabdash.db
2026-03-05 11:59:14 -06:00
```
2026-03-05 12:20:22 -06:00
**Manual backup:**
2026-03-05 11:59:14 -06:00
```bash
2026-03-05 12:20:22 -06:00
cp /mnt/user/appdata/fabdash/data/fabdash.db \
/mnt/user/backups/fabdash-$(date +%Y%m%d-%H%M).db
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
**Automated backup:** Use the **Appdata Backup/Restore ** plugin from Unraid Community Applications to schedule regular backups of `/mnt/user/appdata/fabdash/` .
2026-03-05 12:20:22 -06:00
2026-03-05 11:53:28 -06:00
---
2026-03-05 11:59:14 -06:00
## Local Development
2026-03-05 15:24:34 -06:00
**Terminal 1 — Flask backend:**
2026-03-05 11:59:14 -06:00
```bash
2026-03-05 11:53:28 -06:00
cd backend
2026-03-05 11:59:14 -06:00
python -m venv venv
2026-03-05 12:20:22 -06:00
source venv/bin/activate # Windows: venv\Scripts\activate
2026-03-05 11:59:14 -06:00
pip install -r requirements.txt
2026-03-05 12:13:22 -06:00
export FLASK_ENV=development
2026-03-05 11:53:28 -06:00
flask run --port 5000
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
**Terminal 2 — React frontend:**
2026-03-05 11:59:14 -06:00
```bash
2026-03-05 11:53:28 -06:00
cd frontend
2026-03-05 15:24:34 -06:00
npm install --legacy-peer-deps
2026-03-05 12:20:22 -06:00
npm run dev # http://localhost:5173
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
Vite proxies all `/api/*` requests to Flask on port 5000 via `vite.config.js` . No CORS configuration needed in development.
2026-03-05 11:53:28 -06:00
---
## Environment Variables
2026-03-05 12:20:22 -06:00
| Variable | Required | Default | Description |
|---|---|---|---|
2026-03-05 15:24:34 -06:00
| `SECRET_KEY` | **Yes ** | — | Flask session secret. Use a long random string |
| `FLASK_ENV` | No | `production` | Set to `development` for debug mode and auto-reload |
| `DATABASE_URL` | No | `sqlite:////app/data/fabdash.db` | Full SQLite path (4 slashes = absolute path) |
2026-03-05 11:53:28 -06:00
---
## Database Schema
2026-03-05 11:59:14 -06:00
```sql
2026-03-05 11:53:28 -06:00
CREATE TABLE projects (
2026-03-05 11:59:14 -06:00
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
color TEXT NOT NULL DEFAULT '#C9A84C ',
2026-03-05 11:53:28 -06:00
description TEXT,
2026-03-05 15:24:34 -06:00
drive_url VARCHAR(500),
2026-03-05 11:53:28 -06:00
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE deliverables (
2026-03-05 11:59:14 -06:00
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
title TEXT NOT NULL,
due_date DATE NOT NULL,
status TEXT NOT NULL DEFAULT 'upcoming'
CHECK(status IN ('upcoming','in_progress','completed','overdue')),
2026-03-05 11:53:28 -06:00
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
2026-03-05 11:59:14 -06:00
CREATE INDEX idx_deliverables_project ON deliverables(project_id);
2026-03-05 11:53:28 -06:00
CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
2026-03-05 11:59:14 -06:00
```
2026-03-05 11:53:28 -06:00
2026-03-05 15:24:34 -06:00
> `drive_url` is applied to existing databases automatically via the inline migration in `app/__init__.py` — no manual SQL required.
### Auto-Overdue Logic
The `Deliverable.effective_status()` method is called on every API read:
```python
def effective_status(self):
if self.status != 'completed' and self.due_date < date.today():
return 'overdue'
return self.status
```
- Past-due + not completed → returns `overdue` to the frontend
- `completed` deliverables are never auto-downgraded regardless of date
- The stored database value is never modified by this logic
2026-03-05 11:53:28 -06:00
---
## Roadmap
2026-03-05 12:13:22 -06:00
### v1.0 — Core Release *(current)*
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
- [x] Dark/gold Tailwind design system
2026-03-05 15:24:34 -06:00
- [x] FullCalendar — Month, Week, and Day views
2026-03-05 11:53:28 -06:00
- [x] Drag-and-drop deliverable rescheduling
2026-03-05 12:13:22 -06:00
- [x] Multi-deliverable project creation with inline rows
2026-03-05 11:59:14 -06:00
- [x] Add / Edit / Delete for projects and deliverables
2026-03-05 15:24:34 -06:00
- [x] Color-coded projects (12-swatch palette + custom hex)
- [x] Google Drive folder link per project
- [x] Deliverable Focus View — slide-up drawer, horizontal timeline
- [x] Click any Focus View card to activate/select it
2026-03-05 12:13:22 -06:00
- [x] Active deliverable gold highlight in Focus View
2026-03-05 15:24:34 -06:00
- [x] Status badges — Upcoming / In Progress / Completed / Overdue
- [x] Auto-overdue detection (computed at API read time, no cron job)
- [x] Right-click context menus — calendar events, sidebar rows, Focus View cards
- [x] Double-click shortcuts — events, sidebar rows, project header, Focus View cards
- [x] Quick status change from Focus View right-click menu
2026-03-05 12:13:22 -06:00
- [x] Flask REST API + SQLite persistence
2026-03-05 11:53:28 -06:00
- [x] Cascade delete (project → deliverables)
2026-03-05 15:24:34 -06:00
- [x] Inline schema migrations (no manual flask db upgrade needed)
- [x] Single Docker container deployment (multi-stage build)
2026-03-05 12:20:22 -06:00
- [x] Unraid installation — local build + Docker GUI management
2026-03-05 11:53:28 -06:00
### v1.1 — Polish & UX
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
- [ ] Keyboard shortcuts (`N` = new project, `Esc` = close modal/drawer, arrow keys = calendar nav)
2026-03-05 12:13:22 -06:00
- [ ] 30-second undo toast for drag-and-drop moves
2026-03-05 15:24:34 -06:00
- [ ] Animated modal and drawer enter/exit transitions
2026-03-05 12:13:22 -06:00
- [ ] Hover tooltip on calendar events (preview without opening Focus View)
- [ ] Responsive layout with collapsible sidebar
- [ ] Empty state illustrations
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
### v1.2 — Calendar Enhancements
2026-03-05 11:59:14 -06:00
- [ ] Agenda sidebar showing all upcoming deliverables across projects
- [ ] Date range selection for bulk deliverable creation
2026-03-05 12:13:22 -06:00
- [ ] "Today" jump button
- [ ] Week numbers in calendar header
2026-03-05 15:24:34 -06:00
- [ ] Mini calendar thumbnail for quick date navigation
2026-03-05 11:53:28 -06:00
2026-03-05 12:13:22 -06:00
### v2.0 — Auth & Multi-user
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
- [ ] User login (Flask-Login + JWT)
- [ ] Multi-user support with project ownership
2026-03-05 11:59:14 -06:00
- [ ] Role-based access per project (Owner / Editor / Viewer)
2026-03-05 15:24:34 -06:00
- [ ] Activity log per project
- [ ] Comment threads on deliverables
2026-03-05 11:53:28 -06:00
### v2.1 — Notifications & Integrations
2026-03-05 11:59:14 -06:00
2026-03-05 11:53:28 -06:00
- [ ] In-app notification center for approaching due dates
2026-03-05 12:13:22 -06:00
- [ ] Email reminders at configurable intervals (Flask-Mail)
2026-03-05 15:24:34 -06:00
- [ ] iCal / Google Calendar export per project
2026-03-05 12:13:22 -06:00
- [ ] Slack webhook for deliverable status changes
2026-03-05 15:24:34 -06:00
- [ ] CSV import/export for bulk project setup
2026-03-05 11:53:28 -06:00
### v2.2 — Advanced Views
2026-03-05 11:59:14 -06:00
2026-03-05 12:13:22 -06:00
- [ ] Gantt view alternate layout
- [ ] Kanban board (columns by status)
- [ ] Cross-project timeline view
2026-03-05 15:24:34 -06:00
- [ ] Workload heatmap — deliverable density per day
- [ ] Archived projects with searchable history
2026-03-05 11:53:28 -06:00
### v3.0 — Intelligence Layer
2026-03-05 11:59:14 -06:00
2026-03-05 15:24:34 -06:00
- [ ] AI-assisted scheduling suggestions based on project cadence
- [ ] Conflict detection — flag overloaded days
- [ ] Natural language deliverable input ("Add final draft due next Friday to CODA")
2026-03-05 11:53:28 -06:00
---
*Built with intention. No subscriptions. No bloat. Just your fabrication workflow.*