React + Vite client for TaskFlow — Smart Project & Task Collaboration System.
Companion backend: TaskFlow-backend-service
- Features Overview
- Project Setup
- Environment Variables
- Demo Credentials
- Deployment
- Role Model
- Permissions (UI Gates)
- System Architecture
- Routes & Pages
- File Structure
- Future Features (Roadmap)
TaskFlow is a real-time Kanban project management platform for teams. The frontend provides:
| Area | Capabilities |
|---|---|
| Authentication | Email/password login, registration, and one-click demo login |
| Dashboard | KPI cards, task charts, project summary, activity feed, workload view, upcoming deadlines, high-priority tasks |
| Kanban board | Project-scoped board with drag-and-drop status changes, search, filters, sort, and pagination |
| Tasks | Create/edit modal with title, description, status, priority, due date, assignee, and flat comments |
| Projects | Sidebar project list, project settings (add/remove members, delete project) |
| Real-time | Live task, project, membership, and notification updates via Socket.IO |
| Notifications | In-app notification bell with unread badge and toast messages |
| Access control | UI gates for global (ADMIN / USER) and project (OWNER / MEMBER) roles |
| Layer | Technology |
|---|---|
| UI | React 18 |
| Build | Vite 6 |
| Language | TypeScript |
| Routing | React Router 6 (HashRouter) |
| State | Redux Toolkit + React-Redux |
| Charts | Recharts |
| Icons | Lucide React |
| Real-time | Socket.IO Client |
| Styling | Tailwind-style utility classes |
- Node.js 18+ and pnpm (recommended) or npm
- TaskFlow backend running locally or deployed — see backend README
# Clone and enter the repo
git clone <your-repo-url>
cd TaskFlow-frontend-service
# Install dependencies
pnpm install # or: npm install
# Configure environment (see Environment Variables below)
cp .env.example .env
# Start the dev server (port 3000)
pnpm run dev # or: npm run devOpen http://localhost:3000.
Ensure the backend API is reachable at http://localhost:5000/api/v1 (default from .env.example).
| Command | Description |
|---|---|
pnpm run dev / npm run dev |
Development server on port 3000 |
pnpm run build / npm run build |
Production build → dist/ |
pnpm run preview / npm run preview |
Preview production build on port 4173 |
Copy .env.example to .env and adjust for your environment. Vite exposes only variables prefixed with VITE_.
| Variable | Description | Default |
|---|---|---|
VITE_BASE_URL |
Backend REST API base URL | http://localhost:5001/api/v1 |
VITE_SOCKET_URL |
Socket.IO server URL (no /api/v1 path) |
http://localhost:5001 |
For production, set both variables to your deployed backend origin before running build.
Use these accounts to explore the app without registering, or click Demo Login (Admin) on the sign-in screen.
| Account | Password | Global role | |
|---|---|---|---|
| Admin | admin@taskflow.com |
Admin@123 |
ADMIN |
The demo admin has full access across all projects and system dashboard features. The backend must be running with seeded demo data for login to succeed.
The frontend is a static SPA. Build once, then host the dist/ folder on any static file host.
Set production values for:
VITE_BASE_URL— e.g.https://api.yourdomain.com/api/v1VITE_SOCKET_URL— e.g.https://api.yourdomain.com
These are baked in at build time; rebuild after changing them.
pnpm install
pnpm run build # or: npm run buildOutput is written to dist/.
| Platform | Build command | Output directory | Notes |
|---|---|---|---|
| Vercel | npm run build |
dist |
Set VITE_* env vars in project settings; vercel.json includes SPA rewrites |
The app uses HashRouter (/#/dashboard, etc.), so deep links work without server-side rewrite rules. SPA rewrites in vercel.json are included as a fallback for hosts that need them.
- Backend CORS must allow your frontend origin.
- Socket.IO must be reachable at
VITE_SOCKET_URLwith JWT auth enabled.
pnpm run previewOpens the built app at http://localhost:3000.
TaskFlow uses two layers of roles. The UI gates features based on both.
| Role | Description |
|---|---|
ADMIN |
System administrator. Bypasses project-level UI restrictions. |
USER |
Default role. Permissions depend on project membership. |
| Role | How it is determined |
|---|---|
OWNER |
project.ownerId === currentUser.id |
MEMBER |
User appears in project.members[] |
Defined and checked in helpers/projectPermissions.ts.
For demo login details, see Demo Credentials.
Source of truth: helpers/projectPermissions.ts and component usage.
| UI Action | ADMIN | OWNER | MEMBER | Helper / component |
|---|---|---|---|---|
| Create project (sidebar) | Yes | Yes | Yes | canCreateProject — Sidebar |
| Open project board | Yes | Yes | Yes | hasProjectAccess — BoardView |
| "+" create task | Yes | Yes | Yes | canCreateTask — BoardColumn |
| Edit / drag tasks | Yes | Yes | Yes | canUpdateTask — BoardView, TaskCard |
| Assign / unassign in modal | Yes | Yes | Yes | TaskFormModal (via update flow) |
| Delete task button | Yes | Yes | Creator only* | canDeleteTask — BoardView |
| Project settings gear | Yes | Yes | No | canManageProject — BoardHeader |
| Add / remove members | Yes | Yes | No | ProjectSettingsModal |
| Delete project | Yes | Yes | No | ProjectSettingsModal |
| Delete any comment | Yes | Yes | Own comments only | TaskFormModal |
| System dashboard label | Yes | No | No | isAdmin — DashboardHome |
| Admin badge in sidebar | Yes | No | No | isAdmin — Sidebar |
* Known mismatch: The UI shows the delete button to the task creator, but the backend only allows project owner or admin to delete tasks. Creators who are not owners will see the button but receive a 403 from the API.
| Helper | Logic |
|---|---|
isAdmin(user) |
user.role === ADMIN |
isProjectOwner(project, userId) |
project.ownerId === userId |
isProjectMember(project, userId) |
Owner or in project.members |
canManageProject(project, user) |
Admin or project owner |
canCreateProject(user) |
Any authenticated user with a role |
hasProjectAccess(projectId, projects) |
Project in user's fetched list |
canCreateTask(project, user) |
Admin or project member |
canUpdateTask(project, user) |
Same as canCreateTask |
flowchart TB
subgraph client [Frontend - React + Vite]
UI[Pages and Components]
Redux[Redux Store]
API[apiService + request.ts]
SockClient[Socket.IO Client]
UI --> Redux
UI --> API
UI --> SockClient
end
subgraph server [Backend - Express + Socket.IO]
Routes[root.route /api/v1]
AuthMW[auth.middleware]
Modules[Modules: auth project task dashboard activity comment notification]
Helpers[permission.helper project-access.helper]
SockServer[Socket.IO Server]
Routes --> AuthMW --> Modules
Modules --> Helpers
Modules --> SockServer
end
DB[(MongoDB)]
API -->|REST JWT| Routes
SockClient -->|JWT handshake| SockServer
Modules --> DB
| Layer | Files | Responsibility |
|---|---|---|
| Routes | App.tsx |
Auth guards, HashRouter |
| Layout | screen/DashboardLayout.tsx |
Sidebar, notifications, socket hooks |
| State | store/slices/ |
auth, data, dashboard, notifications |
| API | services/apiService.ts, helpers/request.ts |
REST calls, token refresh on 401 |
| Real-time | services/socket.ts, hooks/useProjectSocket.ts, hooks/useMembershipSync.ts |
Live task/project/notification updates |
| Permissions | helpers/projectPermissions.ts |
UI access gates |
Real-time updates use a single Socket.IO client (services/socket.ts) that authenticates with the JWT from localStorage. Hooks subscribe to events, dispatch Redux actions, and connected components re-render from the store.
flowchart LR
subgraph backend [Backend]
API[REST API]
SockSrv[Socket.IO Server]
API --> SockSrv
end
subgraph socketLayer [Socket layer]
SockClient[socket.ts]
HookProject[useProjectSocket]
HookMember[useMembershipSync]
Bell[NotificationBell listener]
Modal[TaskFormModal comment listeners]
end
subgraph redux [Redux store]
DataSlice[data slice - projects tasks]
NotifSlice[notifications slice]
DashSlice[dashboard slice]
end
subgraph ui [UI components]
Board[BoardView BoardColumn TaskCard]
Sidebar[Sidebar]
NotifUI[NotificationBell]
TaskModal[TaskFormModal]
end
SockSrv -->|emit events| SockClient
SockClient --> HookProject
SockClient --> HookMember
SockClient --> Bell
SockClient --> Modal
HookProject -->|dispatch| DataSlice
HookMember -->|dispatch| DataSlice
HookMember -->|dispatch| DashSlice
Bell -->|dispatch| NotifSlice
Bell -->|dispatch| DataSlice
DataSlice --> Board
DataSlice --> Sidebar
NotifSlice --> NotifUI
Modal -->|local useState| TaskModal
Runs once inside DashboardLayout when the user is authenticated:
sequenceDiagram
participant Layout as DashboardLayout
participant Sock as socket.ts
participant Server as Socket.IO Server
participant Redux as Redux Store
participant UI as Sidebar / BoardView
Layout->>Sock: autoConnect with JWT in auth callback
Sock->>Server: connect + authenticate
Layout->>Sock: emit joinUser(userId)
Server-->>Server: verify userId matches JWT
Layout->>Redux: fetchProjects + fetchNotifications
Redux-->>UI: projects list in Sidebar
Note over Layout: User navigates to /projects/:id
Layout->>Redux: setActiveProjectAction(projectId)
Layout->>Sock: emit joinProject(activeProjectId) via useProjectSocket
Server-->>Server: canAccessProject check
BoardView->>Redux: fetchTasks
Redux-->>UI: tasks in BoardColumn / TaskCard
| Step | Where | What happens |
|---|---|---|
| Connect | socket.ts |
io(URL) with auth: { token } from localStorage |
| Join user room | DashboardLayout |
emit("joinUser", user.id) — receives personal notifications |
| Join project room | useProjectSocket |
emit("joinProject", activeProjectId) when board is open |
| Initial data | DashboardLayout |
fetchProjects, fetchNotifications on login |
| Active project | BoardView |
setActiveProjectAction + fetchTasks on route change |
When any user in the project room performs a task action, all connected clients receive the socket event. The acting user's UI is also updated via the REST thunk fulfilled handler (same reducers).
flowchart TD
actor[User A creates or updates task] --> rest[REST thunk createTask / updateTask]
rest --> api[Backend saves + emits to project room]
api --> sockEvt["taskCreated / taskUpdate / taskAssign / taskDelete"]
sockEvt --> hook[useProjectSocket handler]
hook --> map[mapTask / mapProject via helpers/maper]
map --> dispatch[dispatch socketTaskCreated / socketTaskUpdated / socketTaskDeleted]
dispatch --> reducer[taskReducers in data slice]
reducer --> state[Update state.tasks array]
state --> ui[BoardColumn + TaskCard re-render]
rest --> thunkFulfilled[thunk fulfilled handler]
thunkFulfilled --> reducer
| Socket event | Redux action | Reducer effect | UI impact |
|---|---|---|---|
taskCreated |
socketTaskCreated |
Push task if activeProjectId matches |
New card appears in column |
taskUpdate |
socketTaskUpdated |
Replace task by id in state.tasks |
Card content/status/assignee updates |
taskAssign |
socketTaskUpdated |
Same as update | Assignee avatar changes |
taskDelete |
socketTaskDeleted |
Remove task; decrement taskTotal |
Card removed from board |
memberAssigneesCleared |
clearMemberTaskAssignees |
Set assigneeId undefined for member's tasks |
Assignee badges cleared |
Two hooks handle project-level changes:
| Hook | Events listened | Redux actions | UI impact |
|---|---|---|---|
useProjectSocket |
projectUpdated, projectMemberAdd, projectMemberRemove, projectDeleted |
socketProjectUpdated, socketProjectDelete |
Sidebar project list; board header members |
useMembershipSync |
membershipChanged |
socketProjectUpdated, revokeProjectAccess, fetchProjects, fetchDashboard |
Added project appears; removed user redirected to /dashboard |
flowchart TD
owner[Owner adds or removes member] --> api[REST addProjectMember / removeProjectMember]
api --> backendEmit[Backend emits membershipChanged + projectMemberAdd/Remove]
backendEmit --> memberHook[useMembershipSync]
memberHook --> actionAdded{action?}
actionAdded -->|ADDED| updateProj[socketProjectUpdated - push/update project]
actionAdded -->|REMOVED| revoke[revokeProjectAccess - remove project from store]
revoke --> redirect[navigate to /dashboard if on that board]
memberHook --> refresh[fetchProjects + fetchDashboard]
backendEmit --> projectHook[useProjectSocket]
projectHook --> updateMembers[socketProjectUpdated - refresh members list]
updateMembers --> ui[ProjectSettingsModal + BoardHeader avatars]
NotificationBell and useMembershipSync both listen to notification. pushSocketNotification updates the notifications slice and may trigger data refreshes.
sequenceDiagram
participant Server as Backend
participant Sock as socket.ts
participant Bell as NotificationBell
participant Redux as notifications + data slices
participant UI as Toast + badge + dropdown
Server->>Sock: emit notification to user room
Sock->>Bell: NOTIFICATION event
Bell->>Redux: pushSocketNotification
Redux->>Redux: addNotification - prepend item increment unreadCount
alt MEMBER_REMOVED
Redux->>Redux: revokeProjectAccess + fetchProjects + fetchDashboard
end
Bell->>UI: Show 4s toast with message
Redux->>UI: Unread badge + dropdown list update
Task comments are not stored in Redux. TaskFormModal listens to socket events and updates local useState when the modal is open:
| Socket event | Handler | State |
|---|---|---|
commentAdded |
Append to comments if same taskId |
useState in TaskFormModal |
commentDeleted |
Filter out deleted id | useState in TaskFormModal |
Creating a comment still goes through REST (ApiService.comments.create); the backend emits commentAdded to the project room so other open modals update live.
| Slice | Socket-driven actions | Consumed by |
|---|---|---|
data |
socketTaskCreated, socketTaskUpdated, socketTaskDeleted, socketProjectUpdated, socketProjectDelete, revokeProjectAccess, clearMemberTaskAssignees |
BoardView, Sidebar, BoardHeader |
notifications |
addNotification (via pushSocketNotification) |
NotificationBell |
dashboard |
Refetched on membership change (not direct socket reducer) | DashboardHome widgets |
| User action | Immediate UI update | Other users in room |
|---|---|---|
| Create task | createTask.fulfilled → applySocketTaskCreated |
taskCreated socket → same reducer |
| Update / drag task | updateTask.fulfilled → applyTaskUpdated |
taskUpdate socket → same reducer |
| Delete task | deleteTask.fulfilled → applyTaskDeleted |
taskDelete socket → same reducer |
| Add comment | Local state after REST response | commentAdded socket → modal local state |
sequenceDiagram
participant User
participant Frontend
participant API as Backend_API
participant DB as MongoDB
User->>Frontend: Login or Register
Frontend->>API: POST /auth/login or /register
API->>DB: Verify or create user
API-->>Frontend: JWT + refresh cookie
Frontend->>Frontend: Store token in localStorage loadUser
Frontend->>API: GET /project/list
API-->>Frontend: Visible projects
flowchart TD
start[User opens project board] --> loadTasks[fetchTasks with filters]
loadTasks --> checkCreate{canCreateTask?}
checkCreate -->|No| hidePlus[Hide plus button]
checkCreate -->|Yes| clickPlus[Click plus on column]
clickPlus --> modal[Open TaskFormModal]
modal --> submitCreate[dispatch createTask]
submitCreate --> apiCreate["POST /task/create-task/:projectId"]
apiCreate --> refreshList[Reload task list]
refreshList --> editFlow{canUpdateTask?}
editFlow -->|Yes| dragOrClick[Drag card or open edit modal]
dragOrClick --> submitUpdate[dispatch updateTask]
submitUpdate --> apiUpdate["PUT /task/update-task/:taskId"]
flowchart TD
owner[Owner opens Project Settings] --> addUI[Select user to add]
addUI --> dispatchAdd[dispatch addProjectMember]
dispatchAdd --> apiAdd["PUT /project/:id/add-member"]
apiAdd --> socketEvent[Receive projectMemberAdd via socket]
socketEvent --> memberRefresh[Member refreshes project list]
memberRefresh --> joinSocket[useProjectSocket joins project room]
removeFlow[Owner removes member] --> dispatchRemove[dispatch removeProjectMember]
dispatchRemove --> membershipSync[useMembershipSync detects REMOVED]
membershipSync --> redirect[Redirect user off revoked project board]
| Route | Guard | Component | Purpose |
|---|---|---|---|
/ |
— | Redirect | → /dashboard or /login |
/login |
Unauthenticated | AuthScreen |
Login, register, demo |
/dashboard |
Authenticated | DashboardLayout |
App shell |
/dashboard (index) |
Nested | DashboardHome |
Analytics dashboard |
/dashboard/projects/:projectId |
Nested | BoardView |
Kanban board |
TaskFlow-frontend-service/
├── App.tsx # Root router + auth gate
├── index.tsx # React entry + Redux Provider
├── types.ts # Shared TypeScript types/enums
├── vite.config.ts # Vite config (port 3000)
│
├── screen/
│ └── DashboardLayout.tsx # Authenticated shell
│
├── components/
│ ├── auth/
│ │ └── AuthScreen.tsx # Login / register / demo
│ ├── board/
│ │ ├── BoardView.tsx # Kanban orchestration
│ │ ├── BoardColumn.tsx # Status column
│ │ ├── BoardHeader.tsx # Project header
│ │ ├── TaskCard.tsx # Draggable task card
│ │ └── TeamMembersAvatarGroup.tsx
│ ├── dashboard/
│ │ ├── DashboardHome.tsx
│ │ ├── KpiCards.tsx
│ │ ├── TaskCharts.tsx
│ │ ├── ProjectSummaryList.tsx
│ │ ├── ActivityFeed.tsx
│ │ ├── WorkloadSummary.tsx
│ │ ├── UpcomingDeadlines.tsx
│ │ └── HighPriorityTasks.tsx
│ ├── layout/
│ │ ├── Sidebar.tsx
│ │ └── NotificationBell.tsx
│ ├── model/
│ │ ├── TaskFormModal.tsx
│ │ ├── ProjectSettingsModal.tsx
│ │ └── DeleteTaskConfirmModal.tsx
│ ├── search/
│ │ ├── SearchBar.tsx
│ │ ├── TaskFilters.tsx
│ │ ├── SortControls.tsx
│ │ └── Pagination.tsx
│ └── ui/
│ ├── Modal.tsx
│ └── ErrorBanner.tsx
│
├── helpers/
│ ├── projectPermissions.ts # Role/access helpers
│ ├── authSession.ts
│ ├── request.ts # Fetch wrapper + token refresh
│ ├── maper.ts # API → frontend mappers
│ └── getId.ts
│
├── hooks/
│ ├── useProjectSocket.ts
│ └── useMembershipSync.ts
│
├── services/
│ ├── apiService.ts # REST API facade
│ └── socket.ts # Socket.IO client
│
└── store/
├── store.ts
└── slices/
├── authSlice.ts
├── dataSlice.ts
├── dashboardSlice.ts
├── notificationSlice.ts
└── helper/
├── authThunks.ts
├── dataThunks.ts
├── projectReducers.ts
├── taskReducers.ts
└── socketReducers.ts
Planned improvements not yet implemented:
- Otp based login system
- Granular project roles (viewer / editor) with UI gates per role
- Email and push notifications
- Task attachments and rich-text editor
- Subtasks, labels, and dependencies
- OAuth / SSO login
- Component and integration tests
@mentionsin comments- Project templates
- Improved mobile layout and PWA support