Patchwork is a generic, high-reliability Developer Project Dashboard built for small development teams and solo builders.
Built with the core design philosophy: Functionality > Reliability > UX > Visual Polish.
npx patchwork-dashboard init my-board- π Install
- β¨ Key Features
- π‘οΈ Security Architecture & Data Flow
- π§± Data Integrity & Atomicity
- π Database Schema
- β‘ Quick Start (Manual Setup)
- π§ͺ Automated Test Suite
- π± Responsive Design & Mobile Fallbacks
- π’ Deploying to Vercel
- π¬ Contact & Author
The fastest way to get Patchwork running is the npm package:
# scaffold into ./my-board (also works with npx, no global install needed)
npx patchwork-dashboard init my-board
# or install globally
npm install -g patchwork-dashboard
patchwork-dashboard init my-boardThe CLI copies the complete app, creates your .env.local, offers to run npm install, and prints the exact remaining steps (create a Supabase project β run the 2 migrations β paste your keys β npm run dev).
Prefer starting from the source instead? Use the manual setup below.
- Create, rename, edit, and delete isolated project workspaces.
- Real-time aggregate dashboard displaying total projects, active tasks, completion rate, and overdue task count.
- Multi-column drag-and-drop workflow powered by Next.js Server Actions with optimistic UI updates and instant rollback on failure.
- Accessible keyboard navigation and touch-optimized sensor configuration.
- Defaults to
BacklogβTodoβIn ProgressβReviewβDoneon project creation. - Add new custom status columns, pick custom palette colors, rename, and delete columns.
- Zero-Orphan Deletion: Deleting a status column safely moves its tasks to the fallback column automatically β atomically.
- Overdue status is computed deterministically on the server:
due_date < current_dateAND status is notDone(or the project's final column). - Highlighted across Kanban cards, metrics, and project overviews with high-visibility red badges.
- Live filtering matching title substring and
#tags. - Combine filters by: Status, Priority (
low,medium,high,urgent), Assignee, Tag, and "Overdue Only".
- Every field mutation (status change, title edit, priority bump, assignee update, due date shift) is automatically logged inside the same database transaction as the change itself.
- View task history directly inside the task detail modal or inspect the project-wide audit timeline.
- Free-text timestamped scratchpad attached to each project for storing architecture decisions, snippets, and deployment logs.
- Seamless Dark/Light mode toggle with CSS custom properties.
- Responsive mobile fallback: Status dropdown selector for 1-tap card transitions on touch screens.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser / Client UI β
β (Zero Secrets, No Service Role Key, No Direct Fetch) β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
Next.js Server Actions
('use server' RPC invocation)
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js Server Runtime β
β β’ Server Actions (app/actions/*.ts) β
β β’ Server-side validation (lib/validate.js) β
β β’ Atomic mutations via Postgres RPC (lib/db.ts) β
β β’ Automatic activity logging (same transaction) β
β β’ Service Role Supabase Client (lib/supabase.ts) β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
Internal Postgres Connection (Bypasses RLS)
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supabase (PostgreSQL) β
β β’ RLS Enabled on ALL tables (Public/Anon Denied) β
β β’ Atomic plpgsql functions (single-transaction mutations) β
β β’ Foreign Keys & Cascade Deletions β
β β’ Unique Order Constraints & High-Speed Indexes β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Direct browser-to-/api/* calls are not part of the normal application flow β the UI talks exclusively to Server Actions.
- Zero Browser Secret Exposure
SUPABASE_SERVICE_ROLE_KEYandPATCHWORK_API_SECRETare never exposed to the client or bundled into client JavaScript.- All client interactions invoke Next.js Server Actions directly (
app/actions/*).
- External Integration API Surface (
/app/api/*) β optional, for non-browser tools/scripts only- Protected by a single shared
requireApiSecrethelper (lib/auth.ts) checkingPATCHWORK_API_SECRET(Authorization: Bearer <secret>orx-patchwork-api-key: <secret>) on every route (projects, tasks, statuses, notes, activity, and their[id]variants). - Fail-closed by design: if
PATCHWORK_API_SECRETis not configured, the helper logs a server-side error and rejects every request with500 Server Configuration Errorβ the external surface is disabled entirely, never left open. A missing secret can never open the API.
- Protected by a single shared
- Database-Level Protection
- Row-Level Security (RLS) is enabled on all tables, denying anonymous/public access at the Postgres engine level.
Because every Supabase JS call is an independent HTTP request (no client-side transactions), all multi-step mutations run as single Postgres transactions via plpgsql RPC functions (supabase/migrations/20260829120000_atomic_rpc.sql):
| Operation | Atomic function | Rolled back together |
|---|---|---|
| Create project | create_project_with_statuses |
project insert + 5 default statuses seed |
| Create task | create_task_atomic |
task insert + tag upsert/link + activity log + project bump |
| Update task | update_task_atomic |
field updates + tag resync + per-field activity rows |
| Delete task | delete_task_atomic |
activity log + delete + project bump |
| Reorder statuses | reorder_statuses |
two-phase reindex (park at 10000+ offset, then 0..n-1) |
| Delete status | delete_status_atomic |
task reassignment to fallback + delete + reindex |
| Create note | create_note_atomic |
note insert + project bump |
A failure partway through any operation rolls back everything β no partial or orphaned data is ever committed. Cross-project status_id references and invalid priorities are rejected inside the transaction (defense in depth), in addition to the Server Action validation layer.
Managed exclusively via Supabase migrations (run both, in order β see setup):
-- Core Tables
projects (id uuid PK, name text, description text, created_at, updated_at)
statuses (id uuid PK, project_id FK, name text, order_index int, color text, UNIQUE(project_id, order_index))
tasks (id uuid PK, project_id FK, title text, description text, status_id FK, priority check, assignee text, due_date date)
tags (id uuid PK, name text UNIQUE)
task_tags (task_id FK, tag_id FK, PK(task_id, tag_id))
activity (id uuid PK, task_id FK, project_id FK, field text, old_value text, new_value text, description text)
notes (id uuid PK, project_id FK, content text, created_at)Full column-by-column documentation: SCHEMA.md.
git clone https://github.com/v01dst/patchwork.git
cd patchworkCopy .env.example to .env.local:
cp .env.example .env.localFill in your Supabase credentials:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
PATCHWORK_API_SECRET=your-external-api-secret
β οΈ PATCHWORK_API_SECRETis REQUIRED for the optional external/api/*surface to function at all β not just recommended. If it is omitted, every/api/*route handler rejects all requests with a500 Server Configuration Error(fail-closed). Omitting it intentionally disables the external API surface entirely β it never silently opens it. The app's own UI is unaffected: it communicates via Next.js Server Actions, not/api/*.
In the Supabase dashboard, open the SQL Editor and run both migration files in order:
supabase/migrations/20260829000000_init_patchwork.sql # tables, indexes, RLS
supabase/migrations/20260829120000_atomic_rpc.sql # atomic transaction functions (REQUIRED)
The second migration is mandatory β it creates the atomic RPC functions the app calls for every mutation.
Or, with the Supabase CLI:
supabase db pushnpm install
npm run devOpen http://localhost:3000 in your browser.
35 tests across 6 suites, runnable with zero dependencies (Node's built-in test runner):
npm test| Suite | Tests | Covers |
|---|---|---|
| Server Actions Data Flow & Validation | 3 | status moves without fetch, activity logging, typed error results |
| Activity Diff Calculation Logic | 3 | per-field audit entries, multi-field changes, no-op detection |
| API Secret Auth is FAIL-CLOSED | 6 | unset secret β 500 authorized:false (not 200), empty-string secret, wrong key β 401, correct key β 200 |
| Server-Side Overdue Computation | 5 | no due date, Done/final-status exceptions, past/future dates |
| QA Reliability Suite | 10 | atomic project+statuses seed, atomic task+tags+activity, status deletion with reassignment, reorder rollback under simulated failure, cross-project ID rejection, simulated DB failure leaving no partial data, tag normalization |
| Validation Rules & Enums | 2 | priority enums, date parsing |
# tests 35
# pass 35
# fail 0
- Desktop: Drag and drop cards freely across status columns with
@dnd-kit. - Mobile (< 640px): Cards feature a dedicated 1-touch status picker dropdown allowing seamless movement across workflow stages on touch devices without needing precise multi-column drags.
- Push your scaffolded copy to GitHub.
- Import the repository into Vercel (framework preset: Next.js).
- Add the environment variables (
NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEY, and optionallyPATCHWORK_API_SECRET) in the Vercel dashboard β never commit real values to the repository.
- Discord:
9p.1 - GitHub: @v01dst
- npm: patchwork-dashboard
- License: MIT