Add files via upload

This commit is contained in:
jasonMPM
2026-03-05 16:13:12 -06:00
committed by GitHub
parent 4676627bfd
commit 1569f2e635

406
README.md
View File

@@ -16,9 +16,11 @@
- [Project Structure](#project-structure)
- [Features](#features)
- [Interaction Reference](#interaction-reference)
- [Keyboard Shortcuts](#keyboard-shortcuts)
- [API Reference](#api-reference)
- [Component Architecture](#component-architecture)
- [Unraid Installation](#unraid-installation)
- [Adding Your Logo](#adding-your-logo)
- [Updating FabDash on Unraid](#updating-fabdash-on-unraid)
- [Local Development](#local-development)
- [Environment Variables](#environment-variables)
@@ -29,7 +31,7 @@
## Overview
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.
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 Focus View timeline, workload heatmap, agenda panel, right-click context menus, keyboard shortcuts, and a collapsible branded sidebar — all wrapped in a dark/gold UI and deployed as a single Docker container with no external dependencies.
---
@@ -42,17 +44,20 @@ FabDash is a self-hosted, full-stack project management dashboard built for fabr
| 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/core | 6.1.15 | FullCalendar core (pinned — version must match all FC packages) |
| @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) |
| @fullcalendar/interaction | 6.1.15 | Drag-and-drop, click, select events |
| react-chrono | 2.6.0 | Focus View timeline (pinned — v2.7+ requires React 19) |
| Zustand | ^4.5.5 | Global state management |
| Axios | ^1.7.9 | HTTP client |
| date-fns | ^3.6.0 | Date formatting |
| date-fns | ^3.6.0 | Date formatting and calculations |
> **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.
> **Dependency notes:**
> - All FullCalendar packages are pinned to exactly `6.1.15` (no `^`) to prevent version mismatch build errors
> - `react-chrono` is pinned to `2.6.0` — versions ≥ 2.7.0 require React 19 which breaks the build
> - `npm install --legacy-peer-deps` is used in the Dockerfile and local dev to handle peer dependency conflicts
### Backend
@@ -67,8 +72,8 @@ FabDash is a self-hosted, full-stack project management dashboard built for fabr
### 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
- Mounted as a Docker volume so data survives all container restarts and image rebuilds
- **Inline migrations** — New columns are applied automatically on startup via `_run_migrations()` in `app/__init__.py`; no `flask db upgrade` commands needed
---
@@ -76,7 +81,7 @@ FabDash is a self-hosted, full-stack project management dashboard built for fabr
```
fabdash/
├── Dockerfile
├── Dockerfile # Multi-stage: Node (React build) → Python (Flask)
├── docker-compose.yml
├── .env.example
├── .gitignore
@@ -87,53 +92,61 @@ fabdash/
│ ├── config.py
│ ├── requirements.txt
│ └── app/
│ ├── __init__.py # App factory + inline migrations
│ ├── __init__.py # App factory + inline schema migrations
│ ├── extensions.py
│ ├── models.py # Project + Deliverable models
│ ├── models.py # Project + Deliverable ORM models
│ └── routes/
│ ├── __init__.py
│ ├── projects.py
│ ├── projects.py # CRUD + drive_url support
│ └── deliverables.py
└── frontend/
├── package.json
├── vite.config.js # optimizeDeps for FullCalendar
├── package.json # react-chrono@2.6.0, @fullcalendar/* pinned to 6.1.15
├── vite.config.js # optimizeDeps for FullCalendar, /api proxy
├── tailwind.config.js
├── postcss.config.js
├── index.html
└── public/
└── logo.png # ← Drop your square logo here
└── src/
├── main.jsx
├── App.jsx
├── App.jsx # Sidebar layout, keyboard shortcuts, toast container
├── api/
│ ├── projects.js
│ └── deliverables.js
├── components/
│ ├── Calendar/
│ │ ── MainCalendar.jsx # dblclick + right-click on events
│ │ ── MainCalendar.jsx # Events, drag-drop, tooltip, select, heatmap toggle
│ │ ├── EventTooltip.jsx # Hover preview card
│ │ ├── AgendaPanel.jsx # Upcoming deliverables (next 60 days)
│ │ └── WorkloadHeatmap.jsx # 20-week density heatmap + stat cards
│ ├── Projects/
│ │ ├── ProjectList.jsx
│ │ ├── ProjectCard.jsx # dblclick + right-click, Drive link
│ │ └── ProjectModal.jsx # Drive URL input field
│ │ ├── ProjectList.jsx # Logo header, tab toggle, empty state
│ │ ├── ProjectCard.jsx # Drive link, dblclick, right-click
│ │ └── ProjectModal.jsx # Drive URL field
│ ├── Deliverables/
│ │ └── DeliverableModal.jsx
│ ├── FocusView/
│ │ ├── FocusDrawer.jsx
│ │ ├── FocusTimeline.jsx # Click any card to activate
│ │ └── DeliverableCard.jsx # dblclick + right-click, status menu
│ │ ├── FocusTimeline.jsx # px padding fix for scale-105 clip
│ │ └── DeliverableCard.jsx # Click=select, dblclick=edit, right-click=menu
│ └── UI/
│ ├── Button.jsx
│ ├── Badge.jsx
│ ├── Modal.jsx
│ ├── Modal.jsx # Animated enter transition
│ ├── Drawer.jsx
── ContextMenu.jsx # Floating right-click menu
── ContextMenu.jsx # Floating right-click menu
│ └── Toast.jsx # 30-second undo toast with countdown ring
├── store/
│ ├── useProjectStore.js
── useFocusStore.js # setActiveDeliverable action
── useFocusStore.js # setActiveDeliverable action
│ ├── useUIStore.js # sidebarOpen, sidebarTab, showHeatmap
│ └── useToastStore.js # Toast queue management
├── utils/
│ ├── dateHelpers.js
│ └── statusHelpers.js
└── styles/
└── globals.css
└── globals.css # FullCalendar dark theme, slide-up animation
```
---
@@ -142,67 +155,86 @@ fabdash/
### 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
- **Full-width calendar** — Month, Week, and Day views via FullCalendar
- **Week numbers** — ISO week numbers displayed in gold on the left edge
- **Drag-and-drop rescheduling** — Move any deliverable to a new date; backend patches immediately with a 30-second undo toast
- **Date range drag-select** — Click and drag across multiple days to open Add Deliverable modal pre-filled with the start date
- **Click empty date cell** — Opens Add Deliverable modal pre-filled with that date
- **Hover tooltip** — Shows project name, deliverable title, due date, and status badge without clicking
- **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)
### Workload Heatmap
Toggle between the calendar and heatmap with the **⬡ Heatmap** button in the top-right of the main area.
- **20-week grid** — MonSun rows, week columns, centered 10 weeks before and after today
- **Color intensity** — Cells shade from dark (no deliverables) to full gold (3+ deliverables)
- **Today ring** — Current day highlighted with a white ring
- **Hover tooltip** — Shows date + all deliverable titles and project names for that day (up to 5, with overflow count)
- **Click cell** — Opens Focus View for the first deliverable on that day
- **Stat cards** — Total / Upcoming / In Progress / Completed / Overdue counts across all projects
### Sidebar
- **Collapsible** — Click the `◀` tab or press `B` to collapse. The toggle becomes a branded square tile showing your logo
- **Projects tab** — Project cards with deliverable rows; empty state SVG illustration with keyboard hint
- **Upcoming tab** — Agenda panel showing all deliverables due in the next 60 days, grouped by date with sticky headers; Today highlighted in gold
- **Keyboard shortcut legend** — Pinned at the bottom of the sidebar
### 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
- **Multi-deliverable projects** — Unlimited deliverables per project, each with its own title, due date, and status
- **Inline creation** — Add all deliverables in a single form while creating the project
- **Color coding** — 12-swatch palette + custom hex input
- **Google Drive link** — Optional Drive folder URL stored per project; shows as a Drive button on the card and appears in context menus
- **Double-click project header** — Opens Edit Project modal
- **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
- **Auto-overdue** — Any deliverable whose due date has passed is returned as `overdue` by the API unless marked `completed`. Computed at read time — no cron job required
- **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
- **Slide-up drawer** — Opens from bottom of screen when clicking any calendar event or sidebar row
- **Horizontal timeline** — All deliverables for the project rendered in chronological order
- **Active card** — Highlighted in gold with a "Selected" badge floating above; properly padded so scale-105 transform never clips against scroll container edges
- **Click any card** — Switches the active/selected card
- **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 any card** — Context menu with quick status change (all 4 statuses inline), 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:
Custom floating `ContextMenu` component auto-adjusts to stay within the viewport. Closes on outside click or `Escape`.
| Trigger | Menu Items |
|---|---|
| Calendar event | Edit Deliverable, Open Focus View, Open Drive*, Delete |
| Calendar event | Edit Deliverable, Open Focus View, Open Drive Folder*, 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 |
| Focus View card | Edit Deliverable, Mark Upcoming / In Progress / Completed / Overdue, Delete |
*Only shown when a Drive URL is set on the project.
*Only shown when a Google Drive URL is set on the project.
### Theme & Design System
### Undo Toast
```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',
}
```
After a drag-and-drop rescheduling, a toast appears at the bottom of the screen with:
- The new date
- An **Undo** button that patches back to the original date
- A circular SVG countdown ring showing seconds remaining (30s default)
- Auto-dismisses when the timer expires
### Animations & Polish
- **Modal enter** — Backdrop fades in, dialog scales up from 95% with a translateY, using `requestAnimationFrame` for reliable transitions
- **Sidebar slide** — `transition-[width] duration-300` for smooth collapse/expand
- **Toast slide-up** — `@keyframes slide-up` animation in `globals.css`
- **Heatmap cells** — `hover:scale-125` on each cell for tactile feedback
---
@@ -211,11 +243,27 @@ colors: {
| 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) | — | — |
| Calendar empty cell | Add Deliverable (date pre-filled) | — | — |
| Calendar date range drag | Add Deliverable (start date pre-filled) | — | — |
| 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 | — | — |
| Heatmap cell (with deliverables) | Open Focus View for first deliverable | — | — |
---
## Keyboard Shortcuts
| Key | Action |
|---|---|
| `N` | Open New Project modal |
| `B` | Toggle sidebar open / collapsed |
| `←` | Calendar — previous month/week/day |
| `→` | Calendar — next month/week/day |
| `T` | Calendar — jump to today |
| `Esc` | Close any open modal or drawer |
Shortcuts are blocked when focus is inside an input, textarea, or select field.
---
@@ -240,19 +288,19 @@ colors: {
| `PATCH` | `/api/deliverables/:id` | Update title, due_date, or status |
| `DELETE` | `/api/deliverables/:id` | Delete deliverable |
**Example — Create Project:**
**Example — Create Project with Drive link:**
```json
POST /api/projects
{
"name": "CODA",
"color": "#4A90D9",
"name": "Tucson",
"color": "#E67E22",
"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" }
{ "title": "Fabricate Shelter Assembly Box", "due_date": "2026-03-10", "status": "upcoming" }
]
}
```
@@ -263,24 +311,39 @@ POST /api/projects
```
App
├── Sidebar
── ProjectList
── ProjectCard (× N) ← dblclick + right-click
│ ├── DeliverableRow (× N) ← dblclick + right-click
│ ├── DeliverableModal (local)
── ContextMenu (local)
└── Button ["+ Project"]
├── <aside> Sidebar (collapsible, w-72 ↔ w-0)
── ProjectList
── Header: [logo] FabDash + [+ Project]
│ ├── Tabs: [Projects] [Upcoming]
│ ├── ProjectCard (× N) ← dblclick header, right-click
── DeliverableRow (× N) ← click, dblclick, right-click
│ ├── DeliverableModal (local)
│ │ └── ContextMenu (local)
│ ├── AgendaPanel ← Upcoming tab
│ ├── Keyboard shortcut legend
│ └── ProjectModal
├── MainCalendar ← FullCalendar + eventDidMount
│ ├── FullCalendar events ← dblclick + right-click via DOM
├── Sidebar toggle button
│ ├── Open: ◀ arrow tab
│ └── Collapsed: [logo] square tile + ▶
├── <main> MainCalendar
│ ├── [⬡ Heatmap] toggle button
│ ├── FullCalendar ← eventDidMount: tooltip, dblclick, right-click
│ │ └── Events (drag, click, select)
│ ├── WorkloadHeatmap (toggled)
│ ├── EventTooltip (hover)
│ ├── DeliverableModal
│ └── ContextMenu
── FocusDrawer (slide-up)
├── FocusTimeline
│ └── DeliverableCard (× N) ← click=select, dblclick=edit, right-click=menu
│ └── ContextMenu (local)
└── DeliverableModal
── FocusDrawer (slide-up overlay)
├── FocusTimeline
│ └── DeliverableCard (× N) ← click=select, dblclick=edit, right-click
│ └── ContextMenu (local)
└── DeliverableModal
└── ToastContainer (fixed bottom-center)
└── ToastItem (× N) — countdown ring + Undo
```
---
@@ -308,16 +371,27 @@ cd fabdash
---
### Step 3 — Build the Docker Image
### Step 3 — Add Your Logo (Optional)
Builds the image on your Unraid server and tags it `fabdash:latest`.
First build takes 35 minutes (downloads Node + Python layers, compiles React).
Place your square logo file at:
```
frontend/public/logo.png
```
Supported formats: `.png`, `.jpg`, `.svg`, `.webp` — rename to `logo.png`. If omitted, the sidebar header shows text only and the collapsed toggle shows "FD".
---
### Step 4 — Build the Docker Image
```bash
docker build -t fabdash:latest .
```
Verify the image exists:
First build takes 35 minutes (downloads Node + Python base layers, compiles React).
Verify the image:
```bash
docker images | grep fabdash
@@ -325,7 +399,7 @@ docker images | grep fabdash
---
### Step 4 — Create the Data Directory
### Step 5 — Create the Data Directory
```bash
mkdir -p /mnt/user/appdata/fabdash/data
@@ -333,11 +407,10 @@ mkdir -p /mnt/user/appdata/fabdash/data
---
### Step 5 — Add the Container via Unraid Docker GUI
### Step 6 — Add the Container via Unraid Docker GUI
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
1. Go to the **Docker** tab **Add Container**
2. Toggle **Advanced View** in the top-right of the form
#### Basic Settings
@@ -352,7 +425,7 @@ mkdir -p /mnt/user/appdata/fabdash/data
#### Port Mapping
Click **Add another Path, Port, Variable, Label or Device****Port**:
**Add Port:**
| Field | Value |
|---|---|
@@ -361,11 +434,11 @@ Click **Add another Path, Port, Variable, Label or Device** → **Port**:
| **Host Port** | `8080` |
| **Connection Type** | `TCP` |
> Change Host Port if `8080` is already in use. Access FabDash at `http://YOUR_UNRAID_IP:8080`
> Change Host Port if `8080` is already in use. Access at `http://YOUR_UNRAID_IP:8080`
#### Volume / Path Mapping
Click **Add another Path, Port, Variable, Label or Device****Path**:
**Add Path:**
| Field | Value |
|---|---|
@@ -374,11 +447,11 @@ Click **Add another Path, Port, Variable, Label or Device** → **Path**:
| **Host Path** | `/mnt/user/appdata/fabdash/data` |
| **Access Mode** | `Read/Write` |
> Your database (`fabdash.db`) lives here and survives all rebuilds and reboots.
> Your database (`fabdash.db`) lives here and persists across all rebuilds and reboots.
#### Environment Variables
Add each as **Variable**:
**Add Variable** for each:
| Name | Key | Value |
|---|---|---|
@@ -400,23 +473,19 @@ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 48 | head -n 1
---
### Step 6 — Apply and Launch
### Step 7 — Apply and Launch
Click **Apply**. The container starts using your locally built image.
Open your browser: **`http://YOUR_UNRAID_IP:8080`**
Click **Apply**. Open your browser: **`http://YOUR_UNRAID_IP:8080`**
---
### Step 7 — Verify (Optional)
Check logs from the Unraid Docker tab → click `fabdash`**Logs**, or via SSH:
### Step 8 — Verify (Optional)
```bash
docker logs fabdash --tail 50
```
A healthy startup looks like:
A healthy startup:
```
[INFO] Starting gunicorn 23.0.0
@@ -426,9 +495,35 @@ A healthy startup looks like:
---
## Adding Your Logo
FabDash supports a custom square logo that appears in two places:
1. **Sidebar header** — Next to the "FabDash" wordmark (32×32px, `object-contain`)
2. **Collapsed sidebar toggle** — Replaces the `▶` arrow with a branded square tile (32×32px)
**To add your logo:**
```bash
# Copy your logo into the public directory
cp /path/to/your/logo.png /mnt/user/appdata/fabdash/frontend/public/logo.png
# Rebuild and restart
cd /mnt/user/appdata/fabdash
docker build -t fabdash:latest .
```
Then restart the container from the Unraid Docker GUI.
**Supported formats:** `.png`, `.jpg`, `.svg`, `.webp` — file must be named `logo.png`
If the file is missing, both image elements silently hide themselves via `onError` — no broken image icons, no errors.
---
## Updating FabDash on Unraid
### Step 1 — Pull latest code and rebuild
### Step 1 — Pull latest and rebuild
```bash
ssh root@YOUR_UNRAID_IP
@@ -439,10 +534,9 @@ docker build -t fabdash:latest .
### Step 2 — Restart via Unraid Docker GUI
Go to **Docker** tab → click the `fabdash` container icon → **Restart**
**Docker** tab → click `fabdash` container icon → **Restart**
The container reloads with the new image. Your database is untouched.
New schema columns (if any) are applied automatically on startup.
Your database is untouched. New schema columns apply automatically on startup.
### Step 3 — Verify
@@ -454,8 +548,6 @@ docker logs fabdash --tail 20
## Data Backup
Your database lives at:
```
/mnt/user/appdata/fabdash/data/fabdash.db
```
@@ -467,7 +559,7 @@ cp /mnt/user/appdata/fabdash/data/fabdash.db \
/mnt/user/backups/fabdash-$(date +%Y%m%d-%H%M).db
```
**Automated backup:** Use the **Appdata Backup/Restore** plugin from Unraid Community Applications to schedule regular backups of `/mnt/user/appdata/fabdash/`.
**Automated:** Use the **Appdata Backup/Restore** plugin from Unraid Community Applications.
---
@@ -478,7 +570,7 @@ cp /mnt/user/appdata/fabdash/data/fabdash.db \
```bash
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
source venv/bin/activate
pip install -r requirements.txt
export FLASK_ENV=development
flask run --port 5000
@@ -489,10 +581,12 @@ flask run --port 5000
```bash
cd frontend
npm install --legacy-peer-deps
npm run dev # http://localhost:5173
npm run dev # http://localhost:5173
```
Vite proxies all `/api/*` requests to Flask on port 5000 via `vite.config.js`. No CORS configuration needed in development.
Vite proxies all `/api/*` requests to Flask on port 5000 automatically via `vite.config.js`.
To use your logo in development, place it at `frontend/public/logo.png` — Vite serves `public/` at the root URL automatically.
---
@@ -501,8 +595,8 @@ Vite proxies all `/api/*` requests to Flask on port 5000 via `vite.config.js`. N
| Variable | Required | Default | Description |
|---|---|---|---|
| `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) |
| `FLASK_ENV` | No | `production` | Set to `development` for debug mode |
| `DATABASE_URL` | No | `sqlite:////app/data/fabdash.db` | SQLite path (4 slashes = absolute path) |
---
@@ -510,12 +604,12 @@ Vite proxies all `/api/*` requests to Flask on port 5000 via `vite.config.js`. N
```sql
CREATE TABLE projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
color TEXT NOT NULL DEFAULT '#C9A84C',
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
color TEXT NOT NULL DEFAULT '#C9A84C',
description TEXT,
drive_url VARCHAR(500),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE deliverables (
@@ -532,22 +626,41 @@ CREATE INDEX idx_deliverables_project ON deliverables(project_id);
CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
```
> `drive_url` is applied to existing databases automatically via the inline migration in `app/__init__.py` — no manual SQL required.
> `drive_url` is added to existing databases automatically at startup via `_run_migrations()` in `app/__init__.py`.
### Auto-Overdue Logic
The `Deliverable.effective_status()` method is called on every API read:
```python
def effective_status(self):
"""Computed at read time — never modifies the database."""
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
- Past-due + not completed → `overdue`
- `completed` is never auto-downgraded, even if the date has passed
- Stored `status` value is preserved; this is read-only logic
### Inline Migration Pattern
New columns are applied to existing databases automatically on app startup:
```python
def _run_migrations():
migrations = [
'ALTER TABLE projects ADD COLUMN drive_url VARCHAR(500)',
]
with db.engine.connect() as conn:
for stmt in migrations:
try:
conn.execute(text(stmt))
conn.commit()
except Exception:
pass # Column already exists — safe to ignore
```
To add a new column in a future version, append its `ALTER TABLE` statement to the `migrations` list.
---
@@ -563,35 +676,44 @@ def effective_status(self):
- [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
- [x] Active deliverable gold highlight in Focus View
- [x] Click any Focus View card to activate; scale-105 clip fix
- [x] Active deliverable gold highlight with "Selected" badge
- [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
- [x] 30-second undo toast with circular countdown ring after drag-and-drop
- [x] Hover tooltip on calendar events (project, title, date, status)
- [x] Collapsible sidebar with branded logo tile when collapsed
- [x] Custom logo support — `frontend/public/logo.png`
- [x] Animated modal enter transitions (backdrop + scale + translateY)
- [x] Keyboard shortcuts — N, B, ← →, T, Esc
- [x] Keyboard shortcut legend pinned to sidebar footer
- [x] Workload heatmap — 20-week density grid with stat cards
- [x] Date range drag-select on calendar
- [x] ISO week numbers on calendar
- [x] Agenda / Upcoming panel in sidebar (next 60 days)
- [x] Empty state SVG illustration with keyboard hint
- [x] Flask REST API + SQLite persistence
- [x] Cascade delete (project → deliverables)
- [x] Inline schema migrations (no manual flask db upgrade needed)
- [x] Single Docker container deployment (multi-stage build)
- [x] Inline schema migrations (auto-applied on startup)
- [x] Multi-stage Docker build (Node → Python, single container)
- [x] Unraid installation — local build + Docker GUI management
### v1.1 — Polish & UX
### v1.1 — Polish & UX *(in progress)*
- [ ] Keyboard shortcuts (`N` = new project, `Esc` = close modal/drawer, arrow keys = calendar nav)
- [ ] 30-second undo toast for drag-and-drop moves
- [ ] Animated modal and drawer enter/exit transitions
- [ ] Hover tooltip on calendar events (preview without opening Focus View)
- [ ] Responsive layout with collapsible sidebar
- [ ] Empty state illustrations
- [ ] Animated modal and drawer exit transitions
- [ ] Drag-and-drop between projects (reassign deliverable)
- [ ] Mini calendar in sidebar for quick date navigation
- [ ] Responsive mobile layout
### v1.2 — Calendar Enhancements
- [ ] Agenda sidebar showing all upcoming deliverables across projects
- [ ] Date range selection for bulk deliverable creation
- [ ] "Today" jump button
- [ ] Week numbers in calendar header
- [ ] Mini calendar thumbnail for quick date navigation
- [ ] Recurring deliverables (weekly, bi-weekly, monthly)
- [ ] Bulk status update from heatmap selection
- [ ] Print / export calendar view to PDF
- [ ] Custom calendar event display (show status color, not just project color)
### v2.0 — Auth & Multi-user
@@ -611,17 +733,17 @@ def effective_status(self):
### v2.2 — Advanced Views
- [ ] Gantt view alternate layout
- [ ] Gantt view
- [ ] Kanban board (columns by status)
- [ ] Cross-project timeline view
- [ ] Workload heatmap — deliverable density per day
- [ ] Cross-project timeline
- [ ] Heatmap drill-down — click cell to expand day detail panel
- [ ] Archived projects with searchable history
### v3.0 — Intelligence Layer
- [ ] AI-assisted scheduling suggestions based on project cadence
- [ ] AI-assisted scheduling suggestions
- [ ] Conflict detection — flag overloaded days
- [ ] Natural language deliverable input ("Add final draft due next Friday to CODA")
- [ ] Natural language deliverable input
---