A production-ready, full stack Kanban task management system with JWT authentication, role-based access control, drag and drop, and real-time dashboard statistics.
Frontend: http://localhost:5173
Backend: http://localhost:8080
Default Admin:
Email: admin@kanban.com
Password: password123
| Technology | Purpose |
|---|---|
| Java 17 | Language |
| Spring Boot 3.3.5 | Framework |
| Spring Security | Authentication + Authorization |
| JWT (jjwt 0.12.5) | Token based auth |
| Spring Data JPA | Database ORM |
| Hibernate | SQL generation |
| PostgreSQL | Database |
| Maven | Build tool |
| Technology | Purpose |
|---|---|
| React 18 | UI framework |
| TypeScript | Type safety |
| Vite | Build tool |
| React Router DOM | Multi page routing |
| axios | HTTP client + interceptors |
| @hello-pangea/dnd | Drag and drop |
| lucide-react | Icons |
| Context API | Global state (Auth) |
- JWT token based login and register
- Token stored in localStorage
- Auto token refresh on every request
- Protected routes — redirect to login if not authenticated
- Role based routes — redirect if not authorized
- Register new users (default role: USER)
- Admin assigns ADMIN or USER role
- Admin activates or deactivates users
- Task assignment to registered users only
- Three columns: To Do, In Progress, Done
- Drag and drop tasks between columns
- Status saved to PostgreSQL on drop
- Create tasks with title, description, priority, assignee
- Delete tasks
- Priority badges: HIGH, MEDIUM, LOW
- Live task counts by status
- Live priority breakdown with progress bars
- Recent 5 tasks activity feed
- All data from real API
TaskFlow/
│
├── taskflow-api/ ← Spring Boot Backend
│ └── src/main/java/com/example/kanban/
│ ├── auth/
│ │ ├── AuthController.java
│ │ ├── AuthService.java
│ │ ├── JwtFilter.java
│ │ ├── JwtUtil.java
│ │ └── dto/
│ │ ├── LoginRequest.java
│ │ ├── LoginResponse.java
│ │ └── RegisterRequest.java
│ ├── config/
│ │ ├── CorsConfig.java
│ │ ├── DataInitializer.java
│ │ └── SecurityConfig.java
│ ├── controller/
│ │ ├── TaskController.java
│ │ └── UserController.java
│ ├── dto/
│ │ ├── StatsDTO.java
│ │ ├── TaskDTO.java
│ │ └── UserDTO.java
│ ├── entity/
│ │ ├── Role.java
│ │ ├── Task.java
│ │ └── User.java
│ ├── repository/
│ │ ├── TaskRepository.java
│ │ └── UserRepository.java
│ └── service/
│ ├── TaskService.java
│ └── UserService.java
│
└── taskflow-ui/ ← React Frontend
└── src/
├── components/
│ ├── board/
│ │ ├── AddTaskModal.tsx
│ │ ├── Board.tsx
│ │ ├── Column.tsx
│ │ └── TaskCard.tsx
│ └── layout/
│ ├── Header.tsx
│ ├── Layout.tsx
│ └── Sidebar.tsx
├── context/
│ └── AuthContext.tsx
├── pages/
│ ├── AdminPage.tsx
│ ├── BoardPage.tsx
│ ├── DashboardPage.tsx
│ ├── LoginPage.tsx
│ ├── NotFoundPage.tsx
│ └── RegisterPage.tsx
├── routes/
│ ├── AdminRoute.tsx
│ ├── index.tsx
│ └── ProtectedRoute.tsx
├── services/
│ └── api.ts
└── types/
├── auth.ts
└── kanban.ts
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/login | Login → returns JWT token |
| POST | /api/auth/register | Register new user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/tasks | Get all tasks |
| POST | /api/tasks | Create task |
| PUT | /api/tasks/{id} | Update task |
| PATCH | /api/tasks/{id}/move | Move to column |
| DELETE | /api/tasks/{id} | Delete task |
| GET | /api/tasks/stats | Dashboard stats |
| GET | /api/tasks/recent | Last 5 tasks |
| GET | /api/tasks/search?keyword= | Search tasks |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/users | Get all users |
| GET | /api/users/active | Get active users |
| PATCH | /api/users/{id}/role | Assign role |
| PATCH | /api/users/{id}/toggle-active | Toggle active |
-- app_users table
CREATE TABLE app_users (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
role VARCHAR(255) NOT NULL CHECK (role IN ('ADMIN','USER')),
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP
);
-- tasks table
CREATE TABLE tasks (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
priority VARCHAR(255) NOT NULL,
status VARCHAR(255) NOT NULL,
assigned_to BIGINT REFERENCES app_users(id),
created_at TIMESTAMP
);Java 17+
Node.js 22+
PostgreSQL 14+
Maven (or use ./mvnw)
git clone https://github.com/yourusername/taskflow-api
git clone https://github.com/yourusername/taskflow-uipsql -U postgres -h localhost
CREATE DATABASE taskflowdb;
CREATE USER taskuser WITH PASSWORD 'taskpass';
GRANT ALL PRIVILEGES ON DATABASE taskflowdb TO taskuser;
\qOpen taskflow-api/src/main/resources/application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/taskflowdb
username: taskuser
password: taskpass
jpa:
hibernate:
ddl-auto: update
show-sql: true
server:
port: 8080
jwt:
secret: mySecretKey12345678901234567890123456789012
expiration: 86400000cd taskflow-api
./mvnw spring-boot:run
# Windows:
.\mvnw.cmd spring-boot:runYou should see:
✅ Admin user created
Started KanbanApplication in 3.x seconds
Tomcat started on port 8080
cd taskflow-ui
npm install
npm run devOpen: http://localhost:5173
User enters credentials
↓
POST /api/auth/login
↓
Spring Boot validates password (BCrypt)
↓
Generates JWT token with email
↓
React stores token in localStorage
↓
axios interceptor adds token to every request
↓
Spring JwtFilter validates token on every request
↓
Role checked for admin endpoints
User drags task to new column
↓
React updates UI immediately (optimistic)
↓
PATCH /api/tasks/{id}/move
↓
Spring Boot updates status in PostgreSQL
↓
Data persists on page refresh
Public routes:
/login → anyone
/register → anyone
Protected routes (must be logged in):
/dashboard → any user
/board → any user
Admin only routes:
/admin → ADMIN role only
→ USER redirected to /dashboard
API protection:
GET /api/users → ADMIN only → 403 for USER
/api/tasks/** → any valid token
/api/auth/** → no token needed
@Entity — maps Java class to DB table
@Repository — JPA data access layer
@Service — business logic layer
@RestController — REST API endpoints
@PreAuthorize — method level security
JwtFilter — validates token on every request
BCryptPasswordEncoder — hashes passwords
CORS config — allows React to call API
useState — holds component state
useEffect — fetches data on mount
useContext — global auth state
axios interceptor — auto adds JWT token
React Router — multi page navigation
ProtectedRoute — redirects if not logged in
AdminRoute — redirects if not admin
DragDropContext — drag and drop wrapper
Login Page → JWT auth form
<img width="571" height="633" alt="image" src="https://github.com/user-attachments/assets/ceac4b91-8efb-4204-95d9-deb12c26bb5b" />
Dashboard → Live stats + recent tasks
<img width="1625" height="798" alt="image" src="https://github.com/user-attachments/assets/fea1880e-88f9-4840-9b3a-23ec149e664c" />
Kanban Board → Drag and drop columns
<img width="1300" height="612" alt="image" src="https://github.com/user-attachments/assets/23eb3c94-8348-4872-99de-1808ed46696f" />
Admin Panel → User management table
Register Page → New user signup
| Error | Cause | Fix |
|---|---|---|
| 403 Forbidden | Missing token or wrong role | Check Authorization header |
| CORS blocked | OPTIONS not allowed | Add OPTIONS to CorsConfig |
| Empty response 200 | Missing filterChain.doFilter() | Add to JwtFilter |
| Bean creation error | Duplicate @Bean | Remove duplicate from CorsConfig |
| Table not found | Old schema | DROP TABLE and restart |
| Cannot read undefined | Data not loaded | Add loading state check |
| Too many re-renders | Missing useEffect [] | Add empty dependency array |
Backend:
→ Spring Boot REST API design
→ JWT authentication end to end
→ Spring Security role based access
→ JPA entity relationships (ManyToOne)
→ BCrypt password hashing
→ CORS configuration
→ Debugging bean creation errors
Frontend:
→ React TypeScript component architecture
→ useState and useEffect patterns
→ Context API for global state
→ axios interceptors for auth
→ Protected and role based routing
→ Drag and drop with API persistence
→ Optimistic UI updates
Gobinath Full Stack Developer — Java Spring Boot + React TypeScript
MIT License — free to use and modify