Files
fabdash/README.md
2026-03-05 11:59:14 -06:00

587 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FabDash
**Fabrication Dashboard** — A sleek, modern project management & scheduling application built for fabrication workflows.
![Version](https://img.shields.io/badge/version-1.0.0--alpha-gold)
![Stack](https://img.shields.io/badge/stack-React%20%2B%20Flask%20%2B%20SQLite-informational)
![Theme](https://img.shields.io/badge/theme-Dark%20%2F%20Gold-yellow)
![Docker](https://img.shields.io/badge/deployment-Single%20Docker%20Container-blue)
![License](https://img.shields.io/badge/license-MIT-green)
---
## Table of Contents
- [Overview](#overview)
- [Core Philosophy](#core-philosophy)
- [Tech Stack](#tech-stack)
- [Project Structure](#project-structure)
- [Data Architecture](#data-architecture)
- [Features](#features)
- [API Reference](#api-reference)
- [Component Architecture](#component-architecture)
- [Docker Deployment](#docker-deployment)
- [Local Development](#local-development)
- [Environment Variables](#environment-variables)
- [Database Schema](#database-schema)
- [Roadmap](#roadmap)
---
## Overview
**FabDash** is a self-hosted, full-stack project management and scheduling application built for fabrication teams who need a clean, fast, and visually intuitive way to manage multi-deliverable projects across time. It combines a large interactive calendar with a per-project timeline focus system — all wrapped in a dark, modern UI with gold accents.
Deployed as a **single Docker container**, FabDash runs anywhere Docker runs with zero external dependencies.
---
## Core Philosophy
| Principle | Implementation |
|---|---|
| **Clarity over clutter** | One focused view at a time — calendar or timeline, never both fighting for space |
| **Speed of interaction** | Drag, click, and edit without losing context |
| **Data ownership** | Local SQLite persistence, no cloud dependency |
| **Easy deployment** | Single Docker container — one command to run anywhere |
| **Visual hierarchy** | Gold accents guide the eye to what matters most |
---
## Tech Stack
### Frontend
| Package | Version | Purpose |
|---|---|---|
| React | ^18.x | UI component framework |
| Vite | ^5.x | Build tool and dev server |
| Tailwind CSS | ^3.x | Utility-first styling with custom tokens |
| @fullcalendar/react | ^6.x | Main calendar view |
| @fullcalendar/daygrid | ^6.x | Month/week/day grid views |
| @fullcalendar/interaction | ^6.x | Drag-and-drop and click events |
| @fullcalendar/timegrid | ^6.x | Time-slot grid view |
| react-chrono | ^2.x | Deliverable Focus View timeline |
| Zustand | ^4.x | Global state management |
| Axios | ^1.x | HTTP client for Flask API |
| React Router | ^6.x | Client-side routing |
| date-fns | ^3.x | Date formatting and manipulation |
### Backend
| Package | Version | Purpose |
|---|---|---|
| Flask | ^3.x | REST API server + static file serving |
| Flask-SQLAlchemy | ^3.x | ORM for SQLite |
| Flask-CORS | ^4.x | Cross-origin support for React dev server |
| Flask-Migrate | ^4.x | Database schema migrations |
| Gunicorn | ^21.x | Production WSGI server (inside Docker) |
### Database
- **SQLite** — Zero-config, file-based persistence at `/app/data/fabdash.db`
- Mounted as a Docker volume so data survives container restarts
---
## Project Structure
```
fabdash/
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── .gitignore
├── README.md
├── backend/
│ ├── run.py
│ ├── config.py
│ ├── requirements.txt
│ └── app/
│ ├── __init__.py
│ ├── extensions.py
│ ├── models.py
│ └── routes/
│ ├── projects.py
│ └── deliverables.py
└── frontend/
├── package.json
├── vite.config.js
├── tailwind.config.js
├── index.html
└── src/
├── main.jsx
├── App.jsx
├── api/
│ ├── projects.js
│ └── deliverables.js
├── components/
│ ├── Calendar/
│ │ ├── MainCalendar.jsx
│ │ ├── EventChip.jsx
│ │ └── CalendarToolbar.jsx
│ ├── Projects/
│ │ ├── ProjectList.jsx
│ │ ├── ProjectCard.jsx
│ │ └── ProjectModal.jsx
│ ├── Deliverables/
│ │ ├── DeliverableModal.jsx
│ │ └── DeliverableChip.jsx
│ ├── FocusView/
│ │ ├── FocusDrawer.jsx
│ │ ├── FocusTimeline.jsx
│ │ └── DeliverableCard.jsx
│ └── UI/
│ ├── Button.jsx
│ ├── Badge.jsx
│ ├── Modal.jsx
│ └── Drawer.jsx
├── store/
│ ├── useProjectStore.js
│ └── useFocusStore.js
├── hooks/
│ ├── useProjects.js
│ └── useDeliverables.js
├── utils/
│ ├── dateHelpers.js
│ └── statusHelpers.js
└── styles/
└── globals.css
```
---
## Data Architecture
### Relationships
```
Project (1) ─────────────── (many) Deliverable
│ │
├── id (PK) ├── id (PK)
├── name ├── project_id (FK → projects.id)
├── color (hex) ├── title
├── description ├── due_date
└── created_at ├── status (enum)
└── created_at
```
Each **Project** owns one or more **Deliverables**. Every deliverable inherits the parent project's color when rendered on the calendar. Deleting a project cascades to remove all its deliverables.
---
## Features
### Main Calendar View
The primary interface is a large, full-width FullCalendar grid with three switchable view modes:
- **Month View** — Full month overview, all deliverables visible as colored event chips
- **Week View** — Focused 7-day view with time slots
- **Day View** — Single-day granularity for heavy scheduling days
**Interactions:**
- Drag-and-drop any deliverable to a new date — backend is patched immediately
- Click any event to open the Deliverable Focus View
- Right-click an event for quick actions: Edit, Delete, Open Project
- Click an empty date cell to open the Add Deliverable modal pre-filled with that date
---
### Project & Deliverable Management
**Adding a Project:**
1. Click **"+ New Project"** in the sidebar
2. Enter project name, optional description, and choose a color swatch
3. Add one or more deliverables inline before saving
4. Submit — project and all deliverables persist in a single transaction
**Editing & Deleting:**
- Edit any deliverable from the sidebar, calendar event click, or Focus View
- Delete a project via the sidebar (confirmation dialog warns of cascade delete)
- Delete individual deliverables from their edit modal or via right-click context menu
---
### Deliverable Focus View
Clicking any calendar event opens a **slide-up drawer** with the full project timeline.
- All deliverables render as a horizontal timeline via `react-chrono` in `HORIZONTAL_ALL` mode
- The clicked deliverable is highlighted with a gold glow and elevated scale
- Other deliverables appear as dimmed context nodes
- Drawer dismisses on outside click, `Escape` key, or close button
- Edit Deliverable and Edit Project buttons are available inline
```
[ Deliverable 1 ]────────[ Deliverable 2 ]────────[ ★ Deliverable 3 ★ ]
Jan 15, 2026 Feb 28, 2026 Mar 28, 2026
Completed In Progress ← ACTIVE / FOCUSED
```
---
### Color Coding System
Each project is assigned a hex color used across:
- Background of event chips on the calendar grid
- Left border accent on sidebar project cards
- Timeline node color in the Focus View for non-active deliverables
Colors are selectable from a curated 12-swatch palette (all readable on dark backgrounds) plus a custom hex input.
---
### Theme & Design System
```js
// tailwind.config.js
theme: {
extend: {
colors: {
gold: '#C9A84C',
'gold-light': '#E8C96A',
'gold-muted': '#8A6E2F',
surface: '#111111',
'surface-raised': '#1A1A1A',
'surface-elevated': '#242424',
'surface-border': '#2E2E2E',
'text-primary': '#F5F5F5',
'text-muted': '#888888',
},
boxShadow: {
gold: '0 0 12px rgba(201, 168, 76, 0.4)',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
},
}
```
---
## API Reference
### Projects
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/projects` | Fetch all projects with nested deliverables |
| `POST` | `/api/projects` | Create a new project |
| `GET` | `/api/projects/:id` | Fetch a single project |
| `PATCH` | `/api/projects/:id` | Update project name, color, or description |
| `DELETE` | `/api/projects/:id` | Delete project and cascade deliverables |
### Deliverables
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/deliverables?project_id=:id` | Fetch deliverables for a project |
| `POST` | `/api/deliverables` | Create a new deliverable |
| `PATCH` | `/api/deliverables/:id` | Update title, date, or status |
| `DELETE` | `/api/deliverables/:id` | Delete a single deliverable |
**Example — Create Project with Deliverables:**
```json
POST /api/projects
{
"name": "CODA",
"color": "#4A90D9",
"description": "Example fabrication project",
"deliverables": [
{ "title": "Deliverable 1 Concept Brief", "due_date": "2026-01-15" },
{ "title": "Deliverable 2 Draft Review", "due_date": "2026-02-28" },
{ "title": "Deliverable 3 Final Submission", "due_date": "2026-03-28" }
]
}
```
---
## Component Architecture
```
App
├── Sidebar
│ ├── ProjectList
│ │ └── ProjectCard (× N)
│ │ └── DeliverableChip (× N)
│ └── Button ["+ New Project"]
├── MainCalendar
│ ├── CalendarToolbar
│ └── FullCalendar
│ └── EventChip (× N)
├── ProjectModal
├── DeliverableModal
└── FocusDrawer
└── FocusTimeline
└── DeliverableCard (× N, one highlighted)
```
---
## Docker Deployment
FabDash ships as a **single Docker container**. The build process compiles the React frontend with Vite, copies the static output into Flask's `static/` folder, and serves everything through Gunicorn. No separate web server or container needed.
### How It Works
```
Docker Build
├── Stage 1 (node:18-alpine)
│ └── npm run build → frontend/dist/
└── Stage 2 (python:3.12-slim)
├── Copy dist/ → backend/app/static/
├── pip install -r requirements.txt
├── Flask serves API at /api/*
├── Flask serves React at /* (catch-all → index.html)
└── Gunicorn runs on port 8080
```
### Dockerfile
```dockerfile
# ── Stage 1: Build React frontend ──────────────────────────────────────
FROM node:18-alpine AS frontend-build
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# ── Stage 2: Flask + Gunicorn production image ─────────────────────────
FROM python:3.12-slim
WORKDIR /app
# Install Python dependencies
COPY backend/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy Flask app
COPY backend/ ./
# Copy compiled React build into Flask static folder
COPY --from=frontend-build /app/frontend/dist ./app/static
# Persistent volume mount point for SQLite database
RUN mkdir -p /app/data
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "run:app"]
```
### docker-compose.yml
```yaml
version: "3.9"
services:
fabdash:
build: .
container_name: fabdash
ports:
- "8080:8080"
volumes:
- fabdash-data:/app/data # Persists SQLite database across restarts
environment:
- FLASK_ENV=production
- DATABASE_URL=sqlite:////app/data/fabdash.db
- SECRET_KEY=${SECRET_KEY}
restart: unless-stopped
volumes:
fabdash-data:
```
### Flask Catch-All Route (SPA Support)
Add this to `backend/app/__init__.py` so React Router handles all non-API routes:
```python
import os
from flask import send_from_directory
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve_react(path):
static_folder = os.path.join(app.root_path, "static")
if path and os.path.exists(os.path.join(static_folder, path)):
return send_from_directory(static_folder, path)
return send_from_directory(static_folder, "index.html")
```
### Deploy (One Command)
```bash
# Clone and run
git clone https://github.com/yourname/fabdash.git
cd fabdash
cp .env.example .env # Add your SECRET_KEY
docker compose up -d --build
# FabDash is live at http://localhost:8080
```
### Useful Docker Commands
```bash
docker compose logs -f fabdash # Stream logs
docker compose down # Stop container
docker compose up -d --build # Rebuild and restart
docker exec -it fabdash flask db upgrade # Run migrations
```
---
## Local Development
For active development, run frontend and backend separately so Vite HMR works:
**Terminal 1 — Flask backend:**
```bash
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
flask db upgrade
flask run --port 5000
```
**Terminal 2 — React frontend:**
```bash
cd frontend
npm install
npm run dev # Vite dev server at http://localhost:5173
```
Set `VITE_API_BASE_URL=http://localhost:5000/api` in `frontend/.env` during development.
In production (Docker), the frontend calls `/api/*` relative to the same origin — no CORS needed.
---
## Environment Variables
```env
# .env (used by docker-compose.yml)
SECRET_KEY=replace-with-a-strong-random-key
FLASK_ENV=production
DATABASE_URL=sqlite:////app/data/fabdash.db
# frontend/.env (development only)
VITE_API_BASE_URL=http://localhost:5000/api
```
---
## Database Schema
```sql
CREATE TABLE projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
color TEXT NOT NULL DEFAULT '#C9A84C',
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE deliverables (
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')),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_deliverables_project ON deliverables(project_id);
CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
```
---
## Roadmap
### v1.0 — Core Release *(current scope)*
- [x] Dark/gold design system with Tailwind custom tokens
- [x] FullCalendar main view with Month / Week / Day modes
- [x] Drag-and-drop deliverable rescheduling
- [x] Project creation with multiple deliverables and color selection
- [x] Add / Edit / Delete for projects and deliverables
- [x] Deliverable Focus View — slide-up drawer with horizontal timeline
- [x] Active deliverable highlighting in Focus View
- [x] Status badges (Upcoming / In Progress / Completed / Overdue)
- [x] Flask REST API with SQLite persistence
- [x] Cascade delete (project → deliverables)
- [x] Right-click context menu on calendar events
- [x] Single Docker container deployment with persistent volume
---
### v1.1 — Polish & UX
- [ ] Keyboard shortcuts (`N` = new project, `Esc` = close modal, arrow keys = calendar nav)
- [ ] Undo/redo for drag-and-drop with 30-second undo toast
- [ ] Animated transitions on drawer and modal open/close
- [ ] Deliverable sorting in Focus View (by date, by status)
- [ ] Empty state illustrations for no projects or no deliverables
- [ ] Responsive layout with collapsible sidebar for smaller screens
### v1.2 — Enhanced Calendar
- [ ] Agenda sidebar showing all upcoming deliverables across projects
- [ ] Week numbers in calendar header
- [ ] Hover tooltip previewing deliverable details without opening Focus View
- [ ] Date range selection for bulk deliverable creation
- [ ] "Today" jump button with smooth scroll
### v2.0 — Collaboration & Auth
- [ ] User authentication (Flask-Login + JWT)
- [ ] Multi-user support with project ownership and sharing
- [ ] Role-based access per project (Owner / Editor / Viewer)
- [ ] Activity log per project (who changed what, when)
- [ ] Comment threads on individual deliverables
### v2.1 — Notifications & Integrations
- [ ] In-app notification center for approaching due dates
- [ ] Email reminders at configurable intervals before due date
- [ ] iCal / Google Calendar export per project
- [ ] Slack webhook integration for deliverable status changes
- [ ] CSV import/export for bulk project setup
### v2.2 — Advanced Views
- [ ] Gantt view as an alternate layout
- [ ] Kanban board (columns: Upcoming / In Progress / Completed)
- [ ] Cross-project timeline showing all projects on one horizontal axis
- [ ] Workload heatmap showing deliverable density per day
- [ ] Archived projects with searchable history
### v3.0 — Intelligence Layer
- [ ] AI-assisted scheduling suggestions based on project cadence
- [ ] Auto-detect and surface overdue deliverables on dashboard load
- [ ] Conflict detection — flag days with too many concurrent deliverables
- [ ] Natural language input ("Add final draft due next Friday to CODA")
---
*Built with intention. No subscriptions. No bloat. Just your fabrication workflow.*