A real-time, browser-based service desk engineered for ticket intake, tiered L1→L2 escalation, SLA compliance tracking, role-based access governance, and a full operational audit trail.
Live Demo: https://flowdesk.riyadhalmahmud.tech
FlowDesk is a full-stack, browser-based IT service desk designed for internal support teams. It centralizes the entire request lifecycle (intake, triage, tiered escalation, SLA measurement, and resolution) in a single, unified interface, backed by a real-time operations dashboard that surfaces SLA compliance, mean-time-to-resolve, backlog trends, agent workload, and live breach risk.
FlowDesk leverages Next.js (App Router), TypeScript, and Supabase (PostgreSQL, Auth, and database-enforced Row Level Security) to deliver ITIL-aligned service management and IT governance patterns such as least privilege, segregation of duties, and auditable records.
Many small-to-mid-size IT teams run support out of email threads, chat messages, and spreadsheets. Requests slip through the cracks, no one can say whether service-level promises are actually being met, and managers have no visibility into workload, backlog, or where issues cluster most often.
Enterprise ITSM suites such as ServiceNow and Jira Service Management solve this, but at significant cost and complexity. FlowDesk offers a lightweight, self-hostable alternative: a single dashboard, running on nothing more than a Supabase project and a web browser, that logs every request, routes and escalates it through defined tiers, measures it against SLA targets, and preserves a complete audit trail of who did what and when.
- IT Service Desk Managers tracking SLA compliance, MTTR, and team workload from one console.
- L1 / L2 Support Agents triaging, assigning, escalating, and resolving tickets.
- IT Leadership requiring operational visibility and governance reporting.
- Small-to-Mid-Size Enterprises (SMEs) seeking a low-cost, accessible alternative to heavyweight ITSM suites.
- Full CRUD Operations: Create, read, update, and resolve tickets with live state synchronization.
- Governed Status Flow: New ➔ In Progress ➔ Escalated / On Hold ➔ Resolved ➔ Closed, with a Reopened path that increments a reopen counter.
- Human-Readable IDs: Every ticket is assigned a unique, sequential identifier (TCK-#####) via a database trigger.
- Five Request Types: Incident, Warranty Claim, Vendor RMA, Access Request, and Security Incident, handled by one unified queue.
- Type-Specific Fields: Selecting a type reveals the fields it requires (e.g., serial number and purchase date for warranty claims; system and access level for access requests), stored in a flexible details payload.
- Asset Linkage: Hardware-related tickets link to company assets, connecting the service desk to the asset register.
- L1 → L2 Model: A front-desk tier (L1) logs and triages; complex work escalates to specialist teams (L2).
- Team Routing: Tickets route to the correct support team (IT Support, Asset & Warranty, Identity & Access, Security) based on type and priority.
- Auditable Handoffs: Every escalation and reassignment is recorded on the ticket's timeline.
- Per-Priority Targets: Distinct first-response and resolution targets for Low, Medium, High, and Critical priorities.
- Automatic Due Dates: A database trigger stamps each ticket's SLA due time on creation from the active policy.
- Breach Detection: Open tickets past (or approaching) their due time are surfaced as breached or at-risk.
- Executive KPIs: Open backlog, SLA compliance rate, mean-time-to-resolve (MTTR), and a breached/at-risk count.
- Dynamic Charts: Recharts-powered backlog trend (created vs. resolved), ticket volume by type, and an agent workload heatmap.
- Hero Watchlist: A priority breach/at-risk queue sorted by the most urgent SLA due, for immediate triage.
- Five Clearance Profiles: Employee, L1 Agent, L2 Technician, Manager, and Administrator.
- Database-Enforced: Access is governed by PostgreSQL Row Level Security (not merely hidden in the UI) using an auth_role() helper and per-table policies.
- Least Privilege by Design: Employees see only their own tickets; staff roles unlock triage, escalation, resolution, and analytics progressively.
- Soft Delete, Not Destruction: Tickets are cancelled (a governed status), preserving the audit trail and keeping metrics intact.
- State-Aware Rules: Requesters may cancel their own ticket while it is still New; once work begins, they instead submit a cancellation request for staff review.
- Admin Backstop: Administrators retain a confirmed, logged archive/delete path for spam or test records.
- Comprehensive Event Log: Every state change (creation, assignment, escalation, priority change, resolution, closure, cancellation) is recorded in a dedicated ticket_events table.
- Chronological Timeline: Each ticket renders a complete, actor-attributed history for full traceability.
- User Management: Add users, assign roles and teams, and delete users through admin-only server actions using the Supabase service-role API.
- Governance Guards: An administrator cannot delete their own account or the last remaining administrator.
- SLA & Demo Controls: View configured SLA targets and reset the demo environment to a clean, fully populated dataset with one click.
graph TD
subgraph ClientLayer["Browser / Client Layer"]
Login["Login + Demo Role Switcher"]
MyTickets["Employee Portal (/my)"]
Queue["Agent Queue (/queue)"]
Detail["Ticket Detail (/tickets/:id)"]
Dashboard["SLA Dashboard (/dashboard)"]
Admin["Admin Console (/admin)"]
end
subgraph AppLayer["Next.js App Router (Server)"]
Middleware["middleware.ts (session guard)"]
RSC["Server Components (data fetching)"]
Actions["Server Actions (mutations + audit writes)"]
Login --> Middleware
MyTickets --> RSC
Queue --> RSC
Dashboard --> RSC
Detail --> Actions
Admin --> Actions
end
subgraph DataLayer["Supabase"]
Auth["Supabase Auth (JWT sessions)"]
subgraph PG["PostgreSQL + Row Level Security"]
t_profiles["profiles (role, team)"]
t_tickets["tickets"]
t_events["ticket_events (audit)"]
t_teams["teams"]
t_assets["assets"]
t_sla["sla_policies"]
end
Triggers["Triggers: ticket_number, sla_due_at, updated_at, profile-on-signup"]
RoleFn["auth_role() helper (drives RLS)"]
Middleware --> Auth
RSC --> PG
Actions --> PG
Actions --> Auth
PG --> Triggers
PG --> RoleFn
end
FlowDesk is built on the Next.js App Router with TypeScript. Data is read in React Server Components and mutated through Server Actions, which also write the corresponding audit events to keep business logic on the server. The UI is composed with Tailwind CSS and shadcn/ui, charts are rendered with Recharts, and the visual system uses Inter for the interface with JetBrains Mono for labels, identifiers, and metrics.
The backend is Supabase PostgreSQL, organized around six tables: profiles (users with role and team), tickets (the core record), ticket_events (the append-only audit log), teams (support and department lookup), assets (linked hardware), and sla_policies (per-priority targets). Referential integrity is preserved with foreign keys, and user deletions use ON DELETE SET NULL so historical tickets survive as records rather than being destroyed.
Authentication is handled by Supabase Auth (JWT-based sessions), with middleware.ts guarding protected routes. Authorization is enforced at the database layer: an auth_role() security-definer helper reads the caller's role, and per-table RLS policies decide what each role may select, insert, update, or delete. Clearance is mirrored in the UI (suppressing restricted actions) but never relies on it.
Database triggers assign each ticket its sequential TCK-##### identifier and compute its sla_due_at from the active priority policy on insert, and keep updated_at current on change. A profile-on-signup trigger provisions a profiles row for every new auth user.
Every state-changing action is captured in ticket_events with actor identity, event type, before/after values, and timestamp. Cancellations are modeled as a soft-delete status rather than row deletion, so the audit trail and operational metrics remain complete and trustworthy.
Follow these numbered steps to run the application locally:
- Node.js v18+
- npm
- Git
- A Supabase account
git clone https://github.com/r7riyadh/FlowDesk.git
cd FlowDesk
npm installCreate a project on Supabase, then apply the schema: either via the CLI (supabase db push) or by pasting the files in supabase/migrations/ into the SQL Editor in order:
cp .env.example .env.localFill in the values from Supabase ➔ Settings ➔ API:
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key # server-only (used by the seed script; never exposed to the client)npm run seednpm run devUse the one-click role switcher on the login screen, or sign in using:
| Role | Password | |
|---|---|---|
| Administrator | admin@flowdesk.demo |
FlowDesk!2026 |
| Manager | manager@flowdesk.demo |
FlowDesk!2026 |
| L2 Technician | l2@flowdesk.demo |
FlowDesk!2026 |
| L1 Agent | l1@flowdesk.demo |
FlowDesk!2026 |
| Employee | employee@flowdesk.demo |
FlowDesk!2026 |
- Supabase Auth: JWT-based authentication with route protection via middleware.ts.
- Row Level Security (RLS): Enabled on every table, with policies driven by an auth_role() helper so access is enforced in the database, not just the UI.
- Role-Based Access Control (RBAC): Five clearance profiles applying least privilege and segregation of duties.
- Audit Trail: Every state-changing action is logged with actor identity, event type, and timestamp.
- Record Governance: Cancellations are soft-deletes, preserving history and metric integrity; destructive admin actions require explicit confirmation.
- Credential Isolation: The service-role key is confined to server actions and the seed script; only the anon key reaches the browser. Secrets live in .env.local (gitignored).
| Security Metric | Demo Setup (Current) | Production Requirement |
|---|---|---|
| Authentication | Supabase Auth with shared demo accounts. | Add SSO / OIDC and enforce multi-factor authentication. |
| Default Accounts | Shared demo password for evaluation. | Remove demo accounts; enforce strong password and rotation policies. |
| RLS Policies | Scoped by auth.uid() and auth_role(). | Independently review/penetration-test policies; default-deny everywhere. |
| Service Role Key | Stored in server environment variables. | Move to a managed secrets store; rotate regularly. |
| Abuse Protection | Not configured. | Add rate limiting and bot protection on authentication endpoints. |
Distributed under the MIT License. See LICENSE for details.