Add files via upload
This commit is contained in:
561
README.md
561
README.md
@@ -1,9 +1,11 @@
|
|||||||
# FabDash
|
# FabDash
|
||||||
### Fabrication Dashboard — A Sleek, Modern Project Management & Scheduling Application
|
|
||||||
|
**Fabrication Dashboard** — A sleek, modern project management & scheduling application built for fabrication workflows.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -16,28 +18,21 @@
|
|||||||
- [Project Structure](#project-structure)
|
- [Project Structure](#project-structure)
|
||||||
- [Data Architecture](#data-architecture)
|
- [Data Architecture](#data-architecture)
|
||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Main Calendar View](#main-calendar-view)
|
|
||||||
- [Project & Deliverable Management](#project--deliverable-management)
|
|
||||||
- [Deliverable Focus View](#deliverable-focus-view)
|
|
||||||
- [Color Coding System](#color-coding-system)
|
|
||||||
- [Theme & Design System](#theme--design-system)
|
|
||||||
- [API Reference](#api-reference)
|
- [API Reference](#api-reference)
|
||||||
- [Component Architecture](#component-architecture)
|
- [Component Architecture](#component-architecture)
|
||||||
- [Getting Started](#getting-started)
|
- [Docker Deployment](#docker-deployment)
|
||||||
- [Prerequisites](#prerequisites)
|
- [Local Development](#local-development)
|
||||||
- [Backend Setup](#backend-setup)
|
|
||||||
- [Frontend Setup](#frontend-setup)
|
|
||||||
- [Running the App](#running-the-app)
|
|
||||||
- [Environment Variables](#environment-variables)
|
- [Environment Variables](#environment-variables)
|
||||||
- [Database Schema](#database-schema)
|
- [Database Schema](#database-schema)
|
||||||
- [Roadmap](#roadmap)
|
- [Roadmap](#roadmap)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
**FabDash** is a self-hosted, full-stack project management and scheduling application built for professionals who need a clean, fast, and visually intuitive way to manage multi-deliverable projects across time. It combines a large, interactive calendar view with a powerful per-project timeline focus system — all wrapped in a dark, modern UI with gold accents.
|
**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.
|
||||||
|
|
||||||
Unlike bloated SaaS tools, FABDASH runs locally with zero subscription fees, full data ownership, and a UI designed with intention — not feature creep.
|
Deployed as a **single Docker container**, FabDash runs anywhere Docker runs with zero external dependencies.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -46,8 +41,9 @@ Unlike bloated SaaS tools, FABDASH runs locally with zero subscription fees, ful
|
|||||||
| Principle | Implementation |
|
| Principle | Implementation |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Clarity over clutter** | One focused view at a time — calendar or timeline, never both fighting for space |
|
| **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 leaving context |
|
| **Speed of interaction** | Drag, click, and edit without losing context |
|
||||||
| **Data ownership** | Local SQLite persistence, no cloud dependency |
|
| **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 |
|
| **Visual hierarchy** | Gold accents guide the eye to what matters most |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -55,14 +51,15 @@ Unlike bloated SaaS tools, FABDASH runs locally with zero subscription fees, ful
|
|||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
|
|
||||||
| Package | Version | Purpose |
|
| Package | Version | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| React | ^18.x | UI component framework |
|
| React | ^18.x | UI component framework |
|
||||||
| Vite | ^5.x | Build tool & dev server |
|
| Vite | ^5.x | Build tool and dev server |
|
||||||
| Tailwind CSS | ^3.x | Utility-first styling with custom tokens |
|
| Tailwind CSS | ^3.x | Utility-first styling with custom tokens |
|
||||||
| @fullcalendar/react | ^6.x | Main calendar view |
|
| @fullcalendar/react | ^6.x | Main calendar view |
|
||||||
| @fullcalendar/daygrid | ^6.x | Month/week/day grid views |
|
| @fullcalendar/daygrid | ^6.x | Month/week/day grid views |
|
||||||
| @fullcalendar/interaction | ^6.x | Drag-and-drop + click events |
|
| @fullcalendar/interaction | ^6.x | Drag-and-drop and click events |
|
||||||
| @fullcalendar/timegrid | ^6.x | Time-slot grid view |
|
| @fullcalendar/timegrid | ^6.x | Time-slot grid view |
|
||||||
| react-chrono | ^2.x | Deliverable Focus View timeline |
|
| react-chrono | ^2.x | Deliverable Focus View timeline |
|
||||||
| Zustand | ^4.x | Global state management |
|
| Zustand | ^4.x | Global state management |
|
||||||
@@ -71,84 +68,88 @@ Unlike bloated SaaS tools, FABDASH runs locally with zero subscription fees, ful
|
|||||||
| date-fns | ^3.x | Date formatting and manipulation |
|
| date-fns | ^3.x | Date formatting and manipulation |
|
||||||
|
|
||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
| Package | Version | Purpose |
|
| Package | Version | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Flask | ^3.x | REST API server |
|
| Flask | ^3.x | REST API server + static file serving |
|
||||||
| Flask-SQLAlchemy | ^3.x | ORM for SQLite |
|
| Flask-SQLAlchemy | ^3.x | ORM for SQLite |
|
||||||
| Flask-CORS | ^4.x | Cross-origin support for React dev server |
|
| Flask-CORS | ^4.x | Cross-origin support for React dev server |
|
||||||
| Flask-Migrate | ^4.x | Database migrations |
|
| Flask-Migrate | ^4.x | Database schema migrations |
|
||||||
|
| Gunicorn | ^21.x | Production WSGI server (inside Docker) |
|
||||||
|
|
||||||
### Database
|
### Database
|
||||||
- **SQLite** — Zero-config, file-based persistence. Located at `/backend/fabdash.db`
|
|
||||||
|
- **SQLite** — Zero-config, file-based persistence at `/app/data/fabdash.db`
|
||||||
|
- Mounted as a Docker volume so data survives container restarts
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
\`\`\`
|
```
|
||||||
fabdash/
|
fabdash/
|
||||||
│
|
├── Dockerfile
|
||||||
├── backend/ # Flask REST API
|
├── docker-compose.yml
|
||||||
│ ├── app/
|
|
||||||
│ │ ├── __init__.py # App factory
|
|
||||||
│ │ ├── models.py # SQLAlchemy models
|
|
||||||
│ │ ├── routes/
|
|
||||||
│ │ │ ├── projects.py # Project CRUD endpoints
|
|
||||||
│ │ │ └── deliverables.py # Deliverable CRUD endpoints
|
|
||||||
│ │ └── extensions.py # db, cors, migrate instances
|
|
||||||
│ ├── migrations/ # Flask-Migrate migration files
|
|
||||||
│ ├── fabdash.db # SQLite database (auto-generated)
|
|
||||||
│ ├── config.py # Environment config
|
|
||||||
│ └── run.py # App entry point
|
|
||||||
│
|
|
||||||
├── frontend/ # React + Vite application
|
|
||||||
│ ├── public/
|
|
||||||
│ ├── src/
|
|
||||||
│ │ ├── api/
|
|
||||||
│ │ │ ├── projects.js # Axios calls for projects
|
|
||||||
│ │ │ └── deliverables.js # Axios calls for deliverables
|
|
||||||
│ │ ├── components/
|
|
||||||
│ │ │ ├── Calendar/
|
|
||||||
│ │ │ │ ├── MainCalendar.jsx # FullCalendar wrapper
|
|
||||||
│ │ │ │ ├── EventChip.jsx # Color-coded event pill
|
|
||||||
│ │ │ │ └── CalendarToolbar.jsx # Custom nav toolbar
|
|
||||||
│ │ │ ├── Projects/
|
|
||||||
│ │ │ │ ├── ProjectList.jsx # Sidebar project list
|
|
||||||
│ │ │ │ ├── ProjectCard.jsx # Individual project entry
|
|
||||||
│ │ │ │ └── ProjectModal.jsx # Add/edit project modal
|
|
||||||
│ │ │ ├── Deliverables/
|
|
||||||
│ │ │ │ ├── DeliverableModal.jsx # Add/edit deliverable modal
|
|
||||||
│ │ │ │ └── DeliverableChip.jsx # Badge inside ProjectCard
|
|
||||||
│ │ │ ├── FocusView/
|
|
||||||
│ │ │ │ ├── FocusDrawer.jsx # Slide-up drawer container
|
|
||||||
│ │ │ │ ├── FocusTimeline.jsx # react-chrono wrapper
|
|
||||||
│ │ │ │ └── DeliverableCard.jsx # Individual timeline card
|
|
||||||
│ │ │ └── UI/
|
|
||||||
│ │ │ ├── Button.jsx
|
|
||||||
│ │ │ ├── Badge.jsx # Status badge (Upcoming/Overdue)
|
|
||||||
│ │ │ ├── Modal.jsx # Base modal wrapper
|
|
||||||
│ │ │ └── Drawer.jsx # Base slide-up drawer
|
|
||||||
│ │ ├── store/
|
|
||||||
│ │ │ ├── useProjectStore.js # Zustand: project state
|
|
||||||
│ │ │ └── useFocusStore.js # Zustand: focus view state
|
|
||||||
│ │ ├── hooks/
|
|
||||||
│ │ │ ├── useProjects.js # Data fetching hook
|
|
||||||
│ │ │ └── useDeliverables.js # Data fetching hook
|
|
||||||
│ │ ├── utils/
|
|
||||||
│ │ │ ├── dateHelpers.js # date-fns wrappers
|
|
||||||
│ │ │ └── statusHelpers.js # Overdue/Upcoming logic
|
|
||||||
│ │ ├── styles/
|
|
||||||
│ │ │ └── globals.css # Tailwind base + custom vars
|
|
||||||
│ │ ├── App.jsx
|
|
||||||
│ │ └── main.jsx
|
|
||||||
│ ├── tailwind.config.js
|
|
||||||
│ ├── vite.config.js
|
|
||||||
│ └── package.json
|
|
||||||
│
|
|
||||||
├── .env.example
|
├── .env.example
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
└── README.md
|
├── 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
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -156,16 +157,16 @@ fabdash/
|
|||||||
|
|
||||||
### Relationships
|
### Relationships
|
||||||
|
|
||||||
\`\`\`
|
```
|
||||||
Project (1) ──────────── (many) Deliverable
|
Project (1) ─────────────── (many) Deliverable
|
||||||
│ │
|
│ │
|
||||||
├── id (PK) ├── id (PK)
|
├── id (PK) ├── id (PK)
|
||||||
├── name ├── project_id (FK)
|
├── name ├── project_id (FK → projects.id)
|
||||||
├── color (hex) ├── title
|
├── color (hex) ├── title
|
||||||
├── description ├── due_date
|
├── description ├── due_date
|
||||||
└── created_at ├── status (enum)
|
└── created_at ├── status (enum)
|
||||||
└── created_at
|
└── 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.
|
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.
|
||||||
|
|
||||||
@@ -175,93 +176,84 @@ Each **Project** owns one or more **Deliverables**. Every deliverable inherits t
|
|||||||
|
|
||||||
### Main Calendar View
|
### Main Calendar View
|
||||||
|
|
||||||
The primary interface is a large, full-width **FullCalendar** grid. It supports three view modes switchable from the toolbar:
|
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
|
- **Month View** — Full month overview, all deliverables visible as colored event chips
|
||||||
- **Week View** — Focused 7-day view with time slots
|
- **Week View** — Focused 7-day view with time slots
|
||||||
- **Day View** — Single-day granularity for heavy scheduling days
|
- **Day View** — Single-day granularity for heavy scheduling days
|
||||||
|
|
||||||
**Interaction behaviors:**
|
**Interactions:**
|
||||||
- **Drag-and-drop** any deliverable event to a new date — the backend is updated immediately via `PATCH /deliverables/:id`
|
|
||||||
- **Click** any event to open the **Deliverable Focus View** for that project
|
- Drag-and-drop any deliverable to a new date — backend is patched immediately
|
||||||
- **Right-click** (context menu) on an event to access quick actions: Edit, Delete, Open Project
|
- Click any event to open the Deliverable Focus View
|
||||||
- **Click empty date cell** to open the Add Deliverable modal pre-filled with that date
|
- 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
|
### Project & Deliverable Management
|
||||||
|
|
||||||
**Adding a Project:**
|
**Adding a Project:**
|
||||||
1. Click the **"+ New Project"** button in the sidebar
|
|
||||||
2. Enter project name, optional description, and select a color swatch
|
|
||||||
3. Immediately add one or more deliverables inline before saving
|
|
||||||
4. Submit — project and all deliverables are persisted in a single transaction
|
|
||||||
|
|
||||||
**Adding a Deliverable to an Existing Project:**
|
1. Click **"+ New Project"** in the sidebar
|
||||||
- Open a project via the sidebar and click **"+ Add Deliverable"**
|
2. Enter project name, optional description, and choose a color swatch
|
||||||
- Or click an empty calendar cell and select an existing project from the dropdown
|
3. Add one or more deliverables inline before saving
|
||||||
|
4. Submit — project and all deliverables persist in a single transaction
|
||||||
|
|
||||||
**Editing:**
|
**Editing & Deleting:**
|
||||||
- Click any deliverable chip in the sidebar or calendar event to open its edit modal
|
|
||||||
- All fields (title, date, status) are editable inline
|
|
||||||
|
|
||||||
**Deleting:**
|
- Edit any deliverable from the sidebar, calendar event click, or Focus View
|
||||||
- Projects can be deleted from the sidebar (with a confirmation dialog warning of cascade delete)
|
- Delete a project via the sidebar (confirmation dialog warns of cascade delete)
|
||||||
- Individual deliverables can be deleted from their edit modal or via calendar right-click context menu
|
- Delete individual deliverables from their edit modal or via right-click context menu
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Deliverable Focus View
|
### Deliverable Focus View
|
||||||
|
|
||||||
Clicking any deliverable on the calendar opens a **slide-up drawer** from the bottom of the screen containing the full project timeline for that deliverable's parent project.
|
Clicking any calendar event opens a **slide-up drawer** with the full project timeline.
|
||||||
|
|
||||||
**Behavior:**
|
- All deliverables render as a horizontal timeline via `react-chrono` in `HORIZONTAL_ALL` mode
|
||||||
- All deliverables for the project are rendered as a **horizontal timeline** using `react-chrono` in `HORIZONTAL_ALL` mode
|
- The clicked deliverable is highlighted with a gold glow and elevated scale
|
||||||
- The **clicked deliverable is highlighted** with a gold glowing border (`ring-2 ring-gold`) and elevated scale
|
- Other deliverables appear as dimmed context nodes
|
||||||
- All other deliverables appear as dimmed context nodes
|
- Drawer dismisses on outside click, `Escape` key, or close button
|
||||||
- Each card displays: deliverable title, due date, and status badge
|
- Edit Deliverable and Edit Project buttons are available inline
|
||||||
- The drawer can be dismissed by clicking outside it, pressing `Escape`, or clicking the close button
|
|
||||||
- An **"Edit Deliverable"** and **"Edit Project"** button are available within the drawer without navigating away
|
|
||||||
|
|
||||||
**Active Node Visual Treatment:**
|
```
|
||||||
\`\`\`
|
[ Deliverable 1 ]────────[ Deliverable 2 ]────────[ ★ Deliverable 3 ★ ]
|
||||||
[ Deliverable 1 ]──────[ Deliverable 2 ]──────[ ★ Deliverable 3 ★ ]
|
Jan 15, 2026 Feb 28, 2026 Mar 28, 2026
|
||||||
Jan 15, 2026 Feb 28, 2026 Mar 28, 2026
|
Completed In Progress ← ACTIVE / FOCUSED
|
||||||
Completed In Progress ← ACTIVE / FOCUSED
|
```
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Color Coding System
|
### Color Coding System
|
||||||
|
|
||||||
Each project is assigned a hex color at creation. This color is used:
|
Each project is assigned a hex color used across:
|
||||||
- As the **background of event chips** on the FullCalendar grid
|
|
||||||
- As the **left border accent** on sidebar project cards
|
|
||||||
- As the **timeline node color** in the Focus View for non-active deliverables
|
|
||||||
|
|
||||||
Colors are fully user-selectable from a curated palette of 12 swatches (chosen to remain readable against the dark background) plus a custom hex input.
|
- 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
|
### Theme & Design System
|
||||||
|
|
||||||
The entire application uses a **dark, modern aesthetic** with gold as the primary accent color.
|
```js
|
||||||
|
|
||||||
**Tailwind Custom Tokens:**
|
|
||||||
\`\`\`js
|
|
||||||
// tailwind.config.js
|
// tailwind.config.js
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
gold: '#C9A84C',
|
gold: '#C9A84C',
|
||||||
'gold-light': '#E8C96A',
|
'gold-light': '#E8C96A',
|
||||||
'gold-muted': '#8A6E2F',
|
'gold-muted': '#8A6E2F',
|
||||||
surface: '#111111',
|
surface: '#111111',
|
||||||
'surface-raised': '#1A1A1A',
|
'surface-raised': '#1A1A1A',
|
||||||
'surface-elevated':'#242424',
|
'surface-elevated': '#242424',
|
||||||
'surface-border': '#2E2E2E',
|
'surface-border': '#2E2E2E',
|
||||||
'text-primary': '#F5F5F5',
|
'text-primary': '#F5F5F5',
|
||||||
'text-muted': '#888888',
|
'text-muted': '#888888',
|
||||||
},
|
},
|
||||||
boxShadow: {
|
boxShadow: {
|
||||||
gold: '0 0 12px rgba(201, 168, 76, 0.4)',
|
gold: '0 0 12px rgba(201, 168, 76, 0.4)',
|
||||||
@@ -269,10 +261,10 @@ theme: {
|
|||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['Inter', 'sans-serif'],
|
sans: ['Inter', 'sans-serif'],
|
||||||
mono: ['JetBrains Mono', 'monospace'],
|
mono: ['JetBrains Mono', 'monospace'],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -297,200 +289,297 @@ theme: {
|
|||||||
| `PATCH` | `/api/deliverables/:id` | Update title, date, or status |
|
| `PATCH` | `/api/deliverables/:id` | Update title, date, or status |
|
||||||
| `DELETE` | `/api/deliverables/:id` | Delete a single deliverable |
|
| `DELETE` | `/api/deliverables/:id` | Delete a single deliverable |
|
||||||
|
|
||||||
**Example Payload — Create Project with Deliverables:**
|
**Example — Create Project with Deliverables:**
|
||||||
\`\`\`json
|
|
||||||
|
```json
|
||||||
POST /api/projects
|
POST /api/projects
|
||||||
{
|
{
|
||||||
"name": "CODA",
|
"name": "CODA",
|
||||||
"color": "#4A90D9",
|
"color": "#4A90D9",
|
||||||
"description": "Example fabrication project",
|
"description": "Example fabrication project",
|
||||||
"deliverables": [
|
"deliverables": [
|
||||||
{ "title": "Deliverable 1 – Concept Brief", "due_date": "2026-01-15" },
|
{ "title": "Deliverable 1 – Concept Brief", "due_date": "2026-01-15" },
|
||||||
{ "title": "Deliverable 2 – Draft Review", "due_date": "2026-02-28" },
|
{ "title": "Deliverable 2 – Draft Review", "due_date": "2026-02-28" },
|
||||||
{ "title": "Deliverable 3 – Final Submission", "due_date": "2026-03-28" }
|
{ "title": "Deliverable 3 – Final Submission", "due_date": "2026-03-28" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Component Architecture
|
## Component Architecture
|
||||||
|
|
||||||
\`\`\`
|
```
|
||||||
App
|
App
|
||||||
├── Sidebar
|
├── Sidebar
|
||||||
│ ├── ProjectList
|
│ ├── ProjectList
|
||||||
│ │ └── ProjectCard (× N)
|
│ │ └── ProjectCard (× N)
|
||||||
│ │ └── DeliverableChip (× N)
|
│ │ └── DeliverableChip (× N)
|
||||||
│ └── Button ["+ New Project"]
|
│ └── Button ["+ New Project"]
|
||||||
│
|
|
||||||
├── MainCalendar
|
├── MainCalendar
|
||||||
│ ├── CalendarToolbar (Month / Week / Day + nav arrows)
|
│ ├── CalendarToolbar
|
||||||
│ └── FullCalendar
|
│ └── FullCalendar
|
||||||
│ └── EventChip (rendered per deliverable)
|
│ └── EventChip (× N)
|
||||||
│
|
├── ProjectModal
|
||||||
├── ProjectModal (Add / Edit project)
|
├── DeliverableModal
|
||||||
├── DeliverableModal (Add / Edit deliverable)
|
└── FocusDrawer
|
||||||
│
|
|
||||||
└── FocusDrawer (slide-up, conditionally rendered)
|
|
||||||
└── FocusTimeline
|
└── FocusTimeline
|
||||||
└── DeliverableCard (× N, one highlighted)
|
└── DeliverableCard (× N, one highlighted)
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Getting Started
|
## Docker Deployment
|
||||||
|
|
||||||
### Prerequisites
|
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.
|
||||||
- Node.js >= 18.x
|
|
||||||
- Python >= 3.11
|
### How It Works
|
||||||
- pip
|
|
||||||
- Git
|
```
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Backend Setup
|
## Local Development
|
||||||
|
|
||||||
\`\`\`bash
|
For active development, run frontend and backend separately so Vite HMR works:
|
||||||
|
|
||||||
|
**Terminal 1 — Flask backend:**
|
||||||
|
|
||||||
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
source venv/bin/activate # Windows: venv\Scripts\activate
|
source venv/bin/activate # Windows: venv\Scripts\activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
flask db init
|
|
||||||
flask db migrate -m "Initial schema"
|
|
||||||
flask db upgrade
|
flask db upgrade
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Frontend Setup
|
|
||||||
|
|
||||||
\`\`\`bash
|
|
||||||
cd frontend
|
|
||||||
npm install
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Running the App
|
|
||||||
|
|
||||||
**Terminal 1 — Flask backend:**
|
|
||||||
\`\`\`bash
|
|
||||||
cd backend
|
|
||||||
source venv/bin/activate
|
|
||||||
flask run --port 5000
|
flask run --port 5000
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
**Terminal 2 — React frontend:**
|
**Terminal 2 — React frontend:**
|
||||||
\`\`\`bash
|
|
||||||
cd frontend
|
|
||||||
npm run dev
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
App will be available at: **http://localhost:5173**
|
```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
|
## Environment Variables
|
||||||
|
|
||||||
\`\`\`env
|
```env
|
||||||
# backend/.env
|
# .env (used by docker-compose.yml)
|
||||||
FLASK_APP=run.py
|
SECRET_KEY=replace-with-a-strong-random-key
|
||||||
FLASK_ENV=development
|
FLASK_ENV=production
|
||||||
DATABASE_URL=sqlite:///fabdash.db
|
DATABASE_URL=sqlite:////app/data/fabdash.db
|
||||||
SECRET_KEY=your-secret-key-here
|
|
||||||
|
|
||||||
# frontend/.env
|
# frontend/.env (development only)
|
||||||
VITE_API_BASE_URL=http://localhost:5000/api
|
VITE_API_BASE_URL=http://localhost:5000/api
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Database Schema
|
## Database Schema
|
||||||
|
|
||||||
\`\`\`sql
|
```sql
|
||||||
CREATE TABLE projects (
|
CREATE TABLE projects (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
color TEXT NOT NULL DEFAULT '#C9A84C',
|
color TEXT NOT NULL DEFAULT '#C9A84C',
|
||||||
description TEXT,
|
description TEXT,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE deliverables (
|
CREATE TABLE deliverables (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
due_date DATE NOT NULL,
|
due_date DATE NOT NULL,
|
||||||
status TEXT NOT NULL DEFAULT 'upcoming'
|
status TEXT NOT NULL DEFAULT 'upcoming'
|
||||||
CHECK(status IN ('upcoming', 'in_progress', 'completed', 'overdue')),
|
CHECK(status IN ('upcoming','in_progress','completed','overdue')),
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_deliverables_project ON deliverables(project_id);
|
CREATE INDEX idx_deliverables_project ON deliverables(project_id);
|
||||||
CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
|
CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
|
||||||
\`\`\`
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
### v1.0 — Core Release *(current scope)*
|
### v1.0 — Core Release *(current scope)*
|
||||||
|
|
||||||
- [x] Dark/gold design system with Tailwind custom tokens
|
- [x] Dark/gold design system with Tailwind custom tokens
|
||||||
- [x] FullCalendar main view with Month / Week / Day modes
|
- [x] FullCalendar main view with Month / Week / Day modes
|
||||||
- [x] Drag-and-drop deliverable rescheduling
|
- [x] Drag-and-drop deliverable rescheduling
|
||||||
- [x] Project creation with multiple deliverables and color selection
|
- [x] Project creation with multiple deliverables and color selection
|
||||||
- [x] Add / Edit / Delete for both projects and deliverables
|
- [x] Add / Edit / Delete for projects and deliverables
|
||||||
- [x] Deliverable Focus View (slide-up drawer with react-chrono horizontal timeline)
|
- [x] Deliverable Focus View — slide-up drawer with horizontal timeline
|
||||||
- [x] Active deliverable highlighting in Focus View
|
- [x] Active deliverable highlighting in Focus View
|
||||||
- [x] Status badges (Upcoming / In Progress / Completed / Overdue)
|
- [x] Status badges (Upcoming / In Progress / Completed / Overdue)
|
||||||
- [x] Flask REST API with SQLite persistence
|
- [x] Flask REST API with SQLite persistence
|
||||||
- [x] Cascade delete (project → deliverables)
|
- [x] Cascade delete (project → deliverables)
|
||||||
- [x] Right-click context menu on calendar events
|
- [x] Right-click context menu on calendar events
|
||||||
|
- [x] Single Docker container deployment with persistent volume
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### v1.1 — Polish & UX
|
### v1.1 — Polish & UX
|
||||||
- [ ] Keyboard shortcuts (N = new project, Esc = close modal/drawer, ←→ = calendar navigation)
|
|
||||||
- [ ] Undo/redo for drag-and-drop moves (30-second undo toast)
|
- [ ] Keyboard shortcuts (`N` = new project, `Esc` = close modal, arrow keys = calendar nav)
|
||||||
- [ ] Animated transitions on drawer open/close and modal enter/exit
|
- [ ] Undo/redo for drag-and-drop with 30-second undo toast
|
||||||
- [ ] Deliverable sorting within Focus View (by date, by status)
|
- [ ] Animated transitions on drawer and modal open/close
|
||||||
- [ ] Empty state illustrations for no projects / no deliverables
|
- [ ] Deliverable sorting in Focus View (by date, by status)
|
||||||
- [ ] Responsive layout for smaller screens (collapsible sidebar)
|
- [ ] Empty state illustrations for no projects or no deliverables
|
||||||
|
- [ ] Responsive layout with collapsible sidebar for smaller screens
|
||||||
|
|
||||||
### v1.2 — Enhanced Calendar
|
### v1.2 — Enhanced Calendar
|
||||||
- [ ] Mini-map / agenda sidebar showing upcoming deliverables across all projects
|
|
||||||
|
- [ ] Agenda sidebar showing all upcoming deliverables across projects
|
||||||
- [ ] Week numbers in calendar header
|
- [ ] Week numbers in calendar header
|
||||||
- [ ] "Today" jump button with smooth scroll animation
|
- [ ] Hover tooltip previewing deliverable details without opening Focus View
|
||||||
- [ ] Hoverable event tooltip previewing deliverable details without opening Focus View
|
- [ ] Date range selection for bulk deliverable creation
|
||||||
- [ ] Date range selection to bulk-create deliverables
|
- [ ] "Today" jump button with smooth scroll
|
||||||
|
|
||||||
### v2.0 — Collaboration & Auth
|
### v2.0 — Collaboration & Auth
|
||||||
|
|
||||||
- [ ] User authentication (Flask-Login + JWT)
|
- [ ] User authentication (Flask-Login + JWT)
|
||||||
- [ ] Multi-user support with project ownership and sharing
|
- [ ] Multi-user support with project ownership and sharing
|
||||||
- [ ] Role-based access (Owner / Editor / Viewer per project)
|
- [ ] Role-based access per project (Owner / Editor / Viewer)
|
||||||
- [ ] Activity log per project (who changed what, when)
|
- [ ] Activity log per project (who changed what, when)
|
||||||
- [ ] Comment threads on individual deliverables
|
- [ ] Comment threads on individual deliverables
|
||||||
|
|
||||||
### v2.1 — Notifications & Integrations
|
### v2.1 — Notifications & Integrations
|
||||||
|
|
||||||
- [ ] In-app notification center for approaching due dates
|
- [ ] In-app notification center for approaching due dates
|
||||||
- [ ] Email reminders (Flask-Mail) at configurable intervals before due date
|
- [ ] Email reminders at configurable intervals before due date
|
||||||
- [ ] iCal / Google Calendar export per project
|
- [ ] iCal / Google Calendar export per project
|
||||||
- [ ] Slack webhook integration for deliverable status changes
|
- [ ] Slack webhook integration for deliverable status changes
|
||||||
- [ ] CSV import/export for bulk project setup
|
- [ ] CSV import/export for bulk project setup
|
||||||
|
|
||||||
### v2.2 — Advanced Views
|
### v2.2 — Advanced Views
|
||||||
- [ ] Gantt view (using dhtmlx-gantt or Bryntum) as an alternate layout
|
|
||||||
- [ ] Kanban board view (columns by status: Upcoming / In Progress / Completed)
|
- [ ] Gantt view as an alternate layout
|
||||||
- [ ] Cross-project timeline view showing all projects on one horizontal axis
|
- [ ] Kanban board (columns: Upcoming / In Progress / Completed)
|
||||||
- [ ] Workload heatmap showing deliverable density per day across all projects
|
- [ ] Cross-project timeline showing all projects on one horizontal axis
|
||||||
|
- [ ] Workload heatmap showing deliverable density per day
|
||||||
- [ ] Archived projects with searchable history
|
- [ ] Archived projects with searchable history
|
||||||
|
|
||||||
### v3.0 — Intelligence Layer
|
### v3.0 — Intelligence Layer
|
||||||
- [ ] AI-assisted scheduling: suggest optimal due dates based on project cadence
|
|
||||||
- [ ] Auto-detect overdue deliverables and surface them on dashboard load
|
- [ ] AI-assisted scheduling suggestions based on project cadence
|
||||||
- [ ] Smart conflict detection: flag days with too many concurrent deliverables
|
- [ ] Auto-detect and surface overdue deliverables on dashboard load
|
||||||
- [ ] Natural language input for creating deliverables ("Add final draft due next Friday to CODA")
|
- [ ] Conflict detection — flag days with too many concurrent deliverables
|
||||||
|
- [ ] Natural language input ("Add final draft due next Friday to CODA")
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user