Add files via upload
This commit is contained in:
604
README.md
604
README.md
@@ -1,26 +1,23 @@
|
||||
# FabDash
|
||||
|
||||
**Fabrication Dashboard** — A sleek, modern project management & scheduling application built for fabrication workflows.
|
||||
**Fabrication Dashboard** — A sleek, modern project management & scheduling application.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
- [Unraid Installation](#unraid-installation)
|
||||
- [Local Development](#local-development)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Database Schema](#database-schema)
|
||||
@@ -30,57 +27,22 @@
|
||||
|
||||
## 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 |
|
||||
FabDash is a self-hosted project management dashboard built for fabrication teams. It features a large interactive calendar, multi-deliverable project tracking, drag-and-drop scheduling, and a per-project timeline Focus View. All wrapped in a dark/gold UI and deployed as a single Docker container.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
| Layer | Technology |
|
||||
|---|---|
|
||||
| Frontend | React 18, Vite, Tailwind CSS |
|
||||
| Calendar | FullCalendar v6 (daygrid, timegrid, interaction) |
|
||||
| Focus View | Custom horizontal timeline with react-chrono |
|
||||
| State | Zustand |
|
||||
| HTTP | Axios |
|
||||
| Backend | Flask 3, Flask-SQLAlchemy, Flask-Migrate, Flask-CORS |
|
||||
| Database | SQLite (persisted via Docker volume) |
|
||||
| Server | Gunicorn (production) |
|
||||
|
||||
---
|
||||
|
||||
@@ -103,6 +65,7 @@ fabdash/
|
||||
│ ├── extensions.py
|
||||
│ ├── models.py
|
||||
│ └── routes/
|
||||
│ ├── __init__.py
|
||||
│ ├── projects.py
|
||||
│ └── deliverables.py
|
||||
│
|
||||
@@ -110,6 +73,7 @@ fabdash/
|
||||
├── package.json
|
||||
├── vite.config.js
|
||||
├── tailwind.config.js
|
||||
├── postcss.config.js
|
||||
├── index.html
|
||||
└── src/
|
||||
├── main.jsx
|
||||
@@ -119,16 +83,13 @@ fabdash/
|
||||
│ └── deliverables.js
|
||||
├── components/
|
||||
│ ├── Calendar/
|
||||
│ │ ├── MainCalendar.jsx
|
||||
│ │ ├── EventChip.jsx
|
||||
│ │ └── CalendarToolbar.jsx
|
||||
│ │ └── MainCalendar.jsx
|
||||
│ ├── Projects/
|
||||
│ │ ├── ProjectList.jsx
|
||||
│ │ ├── ProjectCard.jsx
|
||||
│ │ └── ProjectModal.jsx
|
||||
│ ├── Deliverables/
|
||||
│ │ ├── DeliverableModal.jsx
|
||||
│ │ └── DeliverableChip.jsx
|
||||
│ │ └── DeliverableModal.jsx
|
||||
│ ├── FocusView/
|
||||
│ │ ├── FocusDrawer.jsx
|
||||
│ │ ├── FocusTimeline.jsx
|
||||
@@ -141,9 +102,6 @@ fabdash/
|
||||
├── store/
|
||||
│ ├── useProjectStore.js
|
||||
│ └── useFocusStore.js
|
||||
├── hooks/
|
||||
│ ├── useProjects.js
|
||||
│ └── useDeliverables.js
|
||||
├── utils/
|
||||
│ ├── dateHelpers.js
|
||||
│ └── statusHelpers.js
|
||||
@@ -153,118 +111,16 @@ fabdash/
|
||||
|
||||
---
|
||||
|
||||
## 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'],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
- **Large calendar view** — Month, Week, and Day modes via FullCalendar
|
||||
- **Drag-and-drop** — Move deliverables to new dates; backend updates instantly
|
||||
- **Multi-deliverable projects** — Add unlimited deliverables per project, each with its own due date and status
|
||||
- **Color-coded projects** — 12-swatch palette + custom hex; colors appear on calendar events and sidebar cards
|
||||
- **Deliverable Focus View** — Click any calendar event to open a slide-up drawer showing the full project timeline, with the selected deliverable highlighted in gold
|
||||
- **Status tracking** — Upcoming / In Progress / Completed / Overdue badges per deliverable
|
||||
- **Dark/gold theme** — Dark surfaces with gold as the primary accent throughout
|
||||
- **Full persistence** — SQLite database via Flask-SQLAlchemy, mounted as a Docker volume
|
||||
|
||||
---
|
||||
|
||||
@@ -274,216 +130,231 @@ theme: {
|
||||
|
||||
| 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 |
|
||||
| `GET` | `/api/projects` | List all projects with nested deliverables |
|
||||
| `POST` | `/api/projects` | Create project (with optional deliverables inline) |
|
||||
| `GET` | `/api/projects/:id` | Get single project |
|
||||
| `PATCH` | `/api/projects/:id` | Update name, color, or description |
|
||||
| `DELETE` | `/api/projects/:id` | Delete project + 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)
|
||||
```
|
||||
| `GET` | `/api/deliverables?project_id=:id` | List deliverables for a project |
|
||||
| `POST` | `/api/deliverables` | Create deliverable |
|
||||
| `PATCH` | `/api/deliverables/:id` | Update title, due_date, or status |
|
||||
| `DELETE` | `/api/deliverables/:id` | Delete deliverable |
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
FabDash uses a **multi-stage Docker build**:
|
||||
|
||||
### How It Works
|
||||
1. Stage 1 compiles the React/Vite frontend into static files
|
||||
2. Stage 2 copies those files into Flask's `static/` folder
|
||||
3. Gunicorn serves the Flask API at `/api/*` and the React SPA at `/*`
|
||||
|
||||
```
|
||||
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)
|
||||
No Nginx, no separate containers, no reverse proxy required.
|
||||
|
||||
```bash
|
||||
# Clone and run
|
||||
git clone https://github.com/yourname/fabdash.git
|
||||
cd fabdash
|
||||
cp .env.example .env # Add your SECRET_KEY
|
||||
cp .env.example .env
|
||||
# Edit .env and set a strong SECRET_KEY
|
||||
docker compose up -d --build
|
||||
|
||||
# FabDash is live at http://localhost:8080
|
||||
# App available at http://your-host:8080
|
||||
```
|
||||
|
||||
### Useful Docker Commands
|
||||
---
|
||||
|
||||
## Unraid Installation
|
||||
|
||||
FabDash is designed to run cleanly on Unraid via a Docker Compose build from source.
|
||||
Two methods are provided below — **Terminal (recommended)** and **Unraid Docker GUI**.
|
||||
|
||||
---
|
||||
|
||||
### Method 1 — Terminal via SSH (Recommended)
|
||||
|
||||
This method builds the image directly on your Unraid server and uses `docker compose` to manage the container.
|
||||
|
||||
#### Step 1 — Enable SSH on Unraid
|
||||
|
||||
Go to **Settings → Management Access → SSH** and ensure SSH is enabled.
|
||||
|
||||
#### Step 2 — SSH into your Unraid server
|
||||
|
||||
```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
|
||||
ssh root@YOUR_UNRAID_IP
|
||||
```
|
||||
|
||||
#### Step 3 — Clone the repository
|
||||
|
||||
```bash
|
||||
cd /mnt/user/appdata
|
||||
git clone https://github.com/yourname/fabdash.git
|
||||
cd fabdash
|
||||
```
|
||||
|
||||
#### Step 4 — Create your environment file
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
Set a strong `SECRET_KEY`:
|
||||
|
||||
```env
|
||||
SECRET_KEY=your-strong-random-secret-key-here
|
||||
FLASK_ENV=production
|
||||
DATABASE_URL=sqlite:////app/data/fabdash.db
|
||||
```
|
||||
|
||||
Press `Ctrl+X`, then `Y` to save.
|
||||
|
||||
#### Step 5 — Build and start the container
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The build will take 2–4 minutes the first time (downloading Node and Python layers, compiling the React app).
|
||||
|
||||
#### Step 6 — Access FabDash
|
||||
|
||||
Open your browser and navigate to:
|
||||
|
||||
```
|
||||
http://YOUR_UNRAID_IP:8080
|
||||
```
|
||||
|
||||
#### Useful Commands
|
||||
|
||||
```bash
|
||||
# View live logs
|
||||
docker compose logs -f fabdash
|
||||
|
||||
# Stop the container
|
||||
docker compose down
|
||||
|
||||
# Rebuild after a git pull (update)
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
|
||||
# Open a shell inside the container
|
||||
docker exec -it fabdash bash
|
||||
|
||||
# Run database migrations (after schema changes)
|
||||
docker exec -it fabdash flask db upgrade
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Method 2 — Unraid Docker GUI (Manual Container)
|
||||
|
||||
Use this method if you have already built and pushed the FabDash image to a registry (Docker Hub or GHCR). If you are running from source, use Method 1.
|
||||
|
||||
#### Step 1 — Push image to a registry (on your dev machine)
|
||||
|
||||
```bash
|
||||
docker build -t yourdockerhubuser/fabdash:latest .
|
||||
docker push yourdockerhubuser/fabdash:latest
|
||||
```
|
||||
|
||||
#### Step 2 — Add container via Unraid Docker tab
|
||||
|
||||
1. In Unraid, go to the **Docker** tab
|
||||
2. Click **Add Container**
|
||||
3. Switch to **Advanced View** (toggle top-right)
|
||||
|
||||
Fill in the fields:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Name** | `fabdash` |
|
||||
| **Repository** | `yourdockerhubuser/fabdash:latest` |
|
||||
| **Network Type** | Bridge |
|
||||
| **Port** | Host: `8080` → Container: `8080` (TCP) |
|
||||
| **Path** | Host: `/mnt/user/appdata/fabdash/data` → Container: `/app/data` |
|
||||
|
||||
#### Step 3 — Add Environment Variables
|
||||
|
||||
Click **Add another Path, Port, Variable...** and add:
|
||||
|
||||
| Key | Value |
|
||||
|---|---|
|
||||
| `SECRET_KEY` | `your-strong-random-key` |
|
||||
| `FLASK_ENV` | `production` |
|
||||
| `DATABASE_URL` | `sqlite:////app/data/fabdash.db` |
|
||||
|
||||
#### Step 4 — Apply
|
||||
|
||||
Click **Apply**. Unraid will pull the image and start the container. Access at:
|
||||
|
||||
```
|
||||
http://YOUR_UNRAID_IP:8080
|
||||
```
|
||||
|
||||
#### Updating the Container (GUI method)
|
||||
|
||||
1. SSH into Unraid
|
||||
2. Run: `docker pull yourdockerhubuser/fabdash:latest`
|
||||
3. In the Docker tab, click the FabDash container icon → **Update**
|
||||
|
||||
---
|
||||
|
||||
### Data Persistence on Unraid
|
||||
|
||||
Your SQLite database is stored at:
|
||||
|
||||
```
|
||||
/mnt/user/appdata/fabdash/data/fabdash.db
|
||||
```
|
||||
|
||||
This path survives container restarts, image rebuilds, and Unraid reboots. Back it up with Unraid's **Appdata Backup** plugin or manually:
|
||||
|
||||
```bash
|
||||
cp /mnt/user/appdata/fabdash/data/fabdash.db /mnt/user/backups/fabdash-$(date +%Y%m%d).db
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Local Development
|
||||
|
||||
For active development, run frontend and backend separately so Vite HMR works:
|
||||
Run backend and frontend separately to get Vite hot-module reloading:
|
||||
|
||||
**Terminal 1 — Flask backend:**
|
||||
**Terminal 1 — Flask:**
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
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
|
||||
flask db upgrade
|
||||
export FLASK_ENV=development
|
||||
flask run --port 5000
|
||||
```
|
||||
|
||||
**Terminal 2 — React frontend:**
|
||||
**Terminal 2 — React:**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev # Vite dev server at http://localhost:5173
|
||||
npm run dev # 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.
|
||||
Vite proxies `/api/*` calls to Flask on port 5000 automatically via `vite.config.js`.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `SECRET_KEY` | *(required)* | Flask session secret — use a long random string |
|
||||
| `FLASK_ENV` | `production` | Set to `development` for debug mode |
|
||||
| `DATABASE_URL` | `sqlite:////app/data/fabdash.db` | Full SQLite path (4 slashes = absolute path) |
|
||||
|
||||
---
|
||||
|
||||
@@ -516,69 +387,66 @@ CREATE INDEX idx_deliverables_due_date ON deliverables(due_date);
|
||||
|
||||
## Roadmap
|
||||
|
||||
### v1.0 — Core Release *(current scope)*
|
||||
### v1.0 — Core Release *(current)*
|
||||
|
||||
- [x] Dark/gold design system with Tailwind custom tokens
|
||||
- [x] FullCalendar main view with Month / Week / Day modes
|
||||
- [x] Dark/gold Tailwind design system
|
||||
- [x] FullCalendar with Month / Week / Day views
|
||||
- [x] Drag-and-drop deliverable rescheduling
|
||||
- [x] Project creation with multiple deliverables and color selection
|
||||
- [x] Multi-deliverable project creation with inline rows
|
||||
- [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] Deliverable Focus View (slide-up drawer + horizontal timeline)
|
||||
- [x] Active deliverable gold highlight in Focus View
|
||||
- [x] Status badges (Upcoming / In Progress / Completed / Overdue)
|
||||
- [x] Flask REST API with SQLite persistence
|
||||
- [x] Flask REST API + SQLite persistence
|
||||
- [x] Cascade delete (project → deliverables)
|
||||
- [x] Right-click context menu on calendar events
|
||||
- [x] Single Docker container deployment with persistent volume
|
||||
|
||||
---
|
||||
- [x] Single Docker container deployment
|
||||
- [x] Unraid installation guide (Terminal + GUI)
|
||||
|
||||
### 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
|
||||
- [ ] Keyboard shortcuts (`N` = new project, `Esc` = close, arrow keys = calendar nav)
|
||||
- [ ] 30-second undo toast for drag-and-drop moves
|
||||
- [ ] Animated modal/drawer enter and exit transitions
|
||||
- [ ] Hover tooltip on calendar events (preview without opening Focus View)
|
||||
- [ ] Responsive layout with collapsible sidebar
|
||||
- [ ] Empty state illustrations
|
||||
|
||||
### v1.2 — Enhanced Calendar
|
||||
### v1.2 — Calendar Enhancements
|
||||
|
||||
- [ ] Agenda sidebar showing all upcoming deliverables across projects
|
||||
- [ ] Week numbers in calendar header
|
||||
- [ ] Hover tooltip previewing deliverable details without opening Focus View
|
||||
- [ ] Click empty date → pre-filled Add Deliverable modal with project selector
|
||||
- [ ] Date range selection for bulk deliverable creation
|
||||
- [ ] "Today" jump button with smooth scroll
|
||||
- [ ] "Today" jump button
|
||||
- [ ] Week numbers in calendar header
|
||||
|
||||
### v2.0 — Collaboration & Auth
|
||||
### v2.0 — Auth & Multi-user
|
||||
|
||||
- [ ] User authentication (Flask-Login + JWT)
|
||||
- [ ] Multi-user support with project ownership and sharing
|
||||
- [ ] User login (Flask-Login + JWT)
|
||||
- [ ] Multi-user support with project ownership
|
||||
- [ ] Role-based access per project (Owner / Editor / Viewer)
|
||||
- [ ] Activity log per project (who changed what, when)
|
||||
- [ ] Comment threads on individual deliverables
|
||||
- [ ] Activity log per project
|
||||
- [ ] Comment threads on deliverables
|
||||
|
||||
### v2.1 — Notifications & Integrations
|
||||
|
||||
- [ ] In-app notification center for approaching due dates
|
||||
- [ ] Email reminders at configurable intervals before due date
|
||||
- [ ] Email reminders at configurable intervals (Flask-Mail)
|
||||
- [ ] iCal / Google Calendar export per project
|
||||
- [ ] Slack webhook integration for deliverable status changes
|
||||
- [ ] CSV import/export for bulk project setup
|
||||
- [ ] Slack webhook for deliverable status changes
|
||||
- [ ] CSV import/export for bulk 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
|
||||
- [ ] Gantt view alternate layout
|
||||
- [ ] Kanban board (columns by status)
|
||||
- [ ] Cross-project timeline view
|
||||
- [ ] 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
|
||||
- [ ] AI scheduling suggestions based on project cadence
|
||||
- [ ] Conflict detection — flag overloaded days
|
||||
- [ ] Natural language input ("Add final draft due next Friday to CODA")
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user