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

FabDash

Fabrication Dashboard — A sleek, modern project management & scheduling application built for fabrication workflows.

Version Stack Theme Docker License


Table of Contents


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

// 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:

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

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

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:

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)

# 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

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:

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:

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 (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

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)

  • Dark/gold design system with Tailwind custom tokens
  • FullCalendar main view with Month / Week / Day modes
  • Drag-and-drop deliverable rescheduling
  • Project creation with multiple deliverables and color selection
  • Add / Edit / Delete for projects and deliverables
  • Deliverable Focus View — slide-up drawer with horizontal timeline
  • Active deliverable highlighting in Focus View
  • Status badges (Upcoming / In Progress / Completed / Overdue)
  • Flask REST API with SQLite persistence
  • Cascade delete (project → deliverables)
  • Right-click context menu on calendar events
  • 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.

Description
No description provided
Readme 564 KiB
Languages
JavaScript 59%
HTML 32.2%
Python 6.4%
CSS 1.8%
Dockerfile 0.6%