38 KiB
SR System — Feature Implementation Plan
Analysis date: 2026-05-26 Scope: Calendar, Notifications, User Profile, ADMIN/MANAGER Management
Executive Summary
| Feature | Existing Backend | New Backend | Frontend | Priority | Effort |
|---|---|---|---|---|---|
| Calendar | None | Calendar aggregation endpoint | CalendarPage + CalendarWidget | P2 | 5d |
| Notifications | Full (read, mark-read, unread count) | Add link_url field to Notification entity |
NotificationDropdown | P1 | 2d |
| User Profile | Partial (getMe, portfolio, dispatch-history) | ChangePassword endpoint + Extended EmployeeSummary | ProfilePage | P1 | 4d |
| ADMIN/MANAGER | Partial (employee CRUD, report listing) | Dispatch CRUD, CommonCode CRUD, Report summary aggregations | EmployeeEditModal, DispatchManager, ReportDashboard, SettingsPage | P1 (Reports), P2 (Dispatch), P2 (Settings) | 8d total |
Total estimated effort: 19 days (full-time, single dev). Parallel work possible — Admin features and Profile can be developed concurrently with Calendar and Notifications.
1. Calendar Feature
1.1 Current State Analysis
| Aspect | Status |
|---|---|
| Header Calendar icon | Route: /issues (no calendar relevance) |
| Backend calendar endpoint | Does not exist |
| Data with dates | Ticket.dueDate, Report.targetDate, Project.startDate/endDate, DispatchHistory.startDate/endDate |
| Frontend calendar page | Does not exist |
The Header component (line 65):
<button onClick={() => router.push('/issues')} ...>
<Calendar className="w-5 h-5" />
</button>
1.2 What's Missing
-
Backend: Calendar aggregation endpoint — No single endpoint to fetch events across domains. Need:
GET /api/v1/calendar?start=YYYY-MM-DD&end=YYYY-MM-DD— returns unified events- Events aggregated from: Ticket due dates, Report target dates, Dispatch start/end dates
-
Backend: Calendar event entity — No dedicated schedule/schedule_type entity. Two options:
- Option A (Recommended): Aggregation endpoint that queries existing entities (Ticket, Report, DispatchHistory) and returns a unified DTO. Zero schema change.
- Option B: New
Scheduleentity with schedule_type (MEETING, DEADLINE, MILESTONE) — more flexible but adds complexity.
-
Frontend: Calendar page (
/app/(main)/calendar/page.tsx) — Full calendar view with month/week/day modes. -
Frontend: Calendar event types — Ticket due dates, report deadlines, dispatch milestones.
1.3 Design Proposal
1.3.1 Backend: Calendar Aggregation Endpoint
New DTO: CalendarEventDto
public record CalendarEventDto(
String eventType, // TICKET_DUE, REPORT_DUE, DISPATCH_START, DISPATCH_END
Long sourceId, // ticketId / reportId / dispatchId
String title,
String description,
LocalDate eventDate,
String color, // semantic color per type
String linkUrl // navigation URL (/issues/123, /work-reports/456, etc.)
) {}
New Controller Method (in a new CalendarController or added to an existing controller):
@GetMapping("/api/v1/calendar")
@PreAuthorize("hasAnyRole('EMPLOYEE','MANAGER','ADMIN')")
ResponseEntity<ApiResponse<List<CalendarEventDto>>> getCalendar(
@RequestParam @DateTimeFormat(iso=ISO.DATE) LocalDate start,
@RequestParam @DateTimeFormat(iso=ISO.DATE) LocalDate end,
@CurrentUser Employee currentUser)
New Service: CalendarService
- Queries
TicketRepository.findByDueDateBetweenAndRequester_EmpId(start, end, empId)(for employee) or all tickets (for manager/admin) - Queries
ReportRepository.findByTargetDateBetweenAndUser_EmpId(start, end, empId)or all - Queries
DispatchHistoryRepository.findByStartDateBetween(start, end)(only active, DISPATCHED) - Merges results into
List<CalendarEventDto>
Event color mapping:
| Event Type | Color | Icon |
|---|---|---|
| TICKET_DUE | #3B82F6 (blue) |
Ticket |
| REPORT_DUE | #10B981 (green) |
FileText |
| DISPATCH_START | #F59E0B (amber) |
Play |
| DISPATCH_END | #EF4444 (red) |
Stop |
1.3.2 Frontend: Calendar Page
Route: /calendar
Design:
┌─────────────────────────────────────────────────────────────────┐
│ Calendar ◀ 2026.05 ▶ Today │
├──┬────┬────┬────┬────┬────┬────┐ │
│S │ M │ T │ W │ T │ F │ S │ │
├──┼────┼────┼────┼────┼────┼────┤ │
│ │ │ │ │ │ 1 │ 2 │ │
│ │ │ │ │ │ ● │ │ │
│ │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ │
│ │ ● │ ● │ │ ■ │ │ │ │
│ │ 11 │ 12 │ 13 │ 14 │ 15 │ 16 │ │
│ │ │ ▲ │ ● │ │ │ ■ │ │
│ │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ │
│ │ │ │ ● │ │ │ │ │
│ │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ │
│ │ │ │ ■ │ │ │ │ │
├──┴────┴────┴────┴────┴────┴────┤ │
│ Legend: ● Report Due ■ Dispatch ▲ Ticket Due │
└─────────────────────────────────────────────────────────────────┘
Components to create:
src/app/(main)/calendar/page.tsx— Main calendar pagesrc/components/calendar/CalendarGrid.tsx— Month grid view (no external library — custom CSS Grid, 7-column)src/components/calendar/CalendarEvent.tsx— Event chip with color dot + title (truncated)src/components/calendar/EventDetailPanel.tsx— Slide-over or modal showing event detailssrc/components/calendar/CalendarWidget.tsx— Mini calendar widget for dashboard (optional, P3)
Added to sidebar:
{ name: 'Calendar', href: '/calendar', icon: Calendar }
1.4 Implementation Plan — Calendar
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Create CalendarEventDto record |
backend/.../dto/CalendarEventDto.java |
0.3d |
| 2 | Create CalendarService with aggregation logic |
backend/.../service/CalendarService.java |
0.7d |
| 3 | Create CalendarController endpoint |
backend/.../controller/CalendarController.java |
0.3d |
| 4 | Add calendarService to frontend services |
src/services/calendarService.ts |
0.3d |
| 5 | Add CalendarEvent type to frontend types |
src/types/index.ts |
0.2d |
| 6 | Build CalendarGrid component |
src/components/calendar/CalendarGrid.tsx |
1.5d |
| 7 | Build CalendarEvent chip component |
src/components/calendar/CalendarEvent.tsx |
0.5d |
| 8 | Build EventDetailPanel slide-over |
src/components/calendar/EventDetailPanel.tsx |
0.5d |
| 9 | Build /calendar page |
src/app/(main)/calendar/page.tsx |
0.5d |
| 10 | Update Header Calendar icon to /calendar |
src/components/layout/Header.tsx |
0.1d |
| 11 | Add Calendar to Sidebar | src/components/layout/Sidebar.tsx |
0.1d |
| Total | 5 days |
2. Notification System
2.1 Current State Analysis
| Aspect | Status |
|---|---|
| Backend API | ✅ Full: GET /notifications, GET /notifications/unread, PUT /notifications/{id}/read |
| Frontend notificationStore | ✅ Polls unread count (30s interval), fetches list, marks as read |
| Notification entity fields | notificationId, type, title, message, isRead, createdAt |
| Bell icon behavior | Calls fetchNotifications() on click but no dropdown/modal renders |
| Missing | link_url field — no way to navigate to related entity from notification |
2.2 What's Missing
- Frontend: NotificationDropdown component — Bell click should show a dropdown listing recent notifications.
- Frontend: Click-to-navigate — Clicking a notification should navigate to the relevant page (ticket detail, report, etc.).
- Backend:
linkUrlfield — Notification entity hastypebut no link to the source entity.
2.3 Design Proposal
2.3.1 Backend: Add linkUrl to Notification Entity
Migration:
ALTER TABLE tb_notification ADD COLUMN link_url VARCHAR(500);
Entity update (Notification.java):
@Column(name = "link_url", length = 500)
private String linkUrl;
Service update — When creating notifications, set linkUrl:
| Type | linkUrl Example |
|---|---|
| TICKET_ASSIGNED | /issues/123 |
| TICKET_RESOLVED | /issues/123 |
| REPORT_APPROVED | /work-reports/456 |
| REPORT_REJECTED | /work-reports/456 |
| SLA_WARNING | /issues/789 |
| EQUIPMENT_ASSIGNED | /itam/123 |
2.3.2 Frontend: Notification Dropdown
Component: NotificationDropdown.tsx
┌─────────────────────────────────┐
│ Notifications [x] │ ← Header: "Notifications" + close button
├─────────────────────────────────┤
│ 🔵 Ticket #123 assigned to you │ ← Unread: blue left border
│ 2 minutes ago → │
├─────────────────────────────────┤
│ ✅ Report #456 approved │ ← Read: no left border
│ 1 hour ago → │
├─────────────────────────────────┤
│ ⚠️ SLA Warning: #789 Overdue │ ← Critical: red left border
│ 3 hours ago → │
├─────────────────────────────────┤
│ │
│ View All ↗ │ ← Link to full notification page
└─────────────────────────────────┘
Behavior:
- Dropdown slides down from bell icon (absolute positioned)
- Shows latest 10 notifications
- Click notification →
markAsRead(id)+ navigate tolinkUrl - Click "View All" →
/notificationspage (optional, P3) - Click outside → close dropdown
- Escape key → close dropdown
Layout:
- Max height: 400px, overflow-y: auto
- Each item: 12px padding, border-bottom, hover bg-gray-50
- Width: 360px
- Unread items:
bg-indigo-50/30, blue dot (6px) left - Categories: Icon + title (bold 13px) + time ago (gray 11px)
2.4 Implementation Plan — Notifications
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Add linkUrl column to Notification entity |
Notification.java + migration |
0.3d |
| 2 | Update NotificationListener to set linkUrl | backend/.../listener/NotificationListener.java |
0.3d |
| 3 | Add linkUrl to frontend Notification type |
src/types/index.ts |
0.1d |
| 4 | Build NotificationDropdown component |
src/components/layout/NotificationDropdown.tsx |
1.0d |
| 5 | Integrate into Header (replace bell onClick) | src/components/layout/Header.tsx |
0.2d |
| 6 | Add mark-all-as-read endpoint (optional) | Backend + service | 0.2d |
| Total | 2 days |
3. User Profile Management
3.1 Current State Analysis
| Aspect | Status |
|---|---|
GET /api/v1/employees/me |
✅ Returns EmployeeSummary (empId, name, email, roleCode, dispatchStatus) |
GET /api/v1/employees/{empId}/dispatch-histories |
✅ Returns DispatchHistory[] |
GET /api/v1/employees/{empId}/portfolio |
✅ Returns PortfolioResponse[] (with reports + resolved tickets) |
PUT /api/v1/employees/{empId} |
✅ Admin-only update endpoint |
| Change password endpoint | Missing |
| Extended profile info (phone, empStatus, joinedDate) | Missing from /me (EmployeeSummary is minimal) |
/profile page |
Does not exist |
3.2 What's Missing
- Backend:
PUT /api/v1/employees/me/password— Change password endpoint for current user. - Backend: Extended
/meresponse —EmployeeSummaryis too minimal. Need phone, empStatus, joinedDate, dispatchStatus label. - Frontend:
/profilepage — View/edit profile, change password, view dispatch history, view portfolio. - Frontend: Profile editing — Allow user to edit their own name, email, phone (or restrict to admin-only for certain fields).
3.3 Design Proposal
3.3.1 Backend: Change Password Endpoint
New DTO: ChangePasswordRequest
public record ChangePasswordRequest(
@NotBlank String currentPassword,
@NotBlank @Size(min=8) String newPassword
) {}
New Endpoint in AuthController or EmployeeController:
@PutMapping("/api/v1/employees/me/password")
@PreAuthorize("hasAnyRole('EMPLOYEE','MANAGER','ADMIN')")
ResponseEntity<ApiResponse<Void>> changePassword(
@Valid @RequestBody ChangePasswordRequest request,
@CurrentUser Employee currentUser)
Logic:
- Verify
currentPasswordmatches stored hash - Encode
newPasswordand save - Invalidate existing tokens (optional — add
token_versionfield)
3.3.2 Backend: Extended EmployeeSummary
Update EmployeeSummary to include:
public record EmployeeSummary(
Long empId,
String loginId,
String name,
String email,
String phone, // NEW
RoleCode roleCode,
EmpStatus empStatus, // NEW
DispatchStatus dispatchStatus,
LocalDate joinedDate, // NEW
LocalDate leftDate // NEW (nullable)
) {}
3.3.3 Frontend: Profile Page Design
URL: /profile
For EMPLOYEE (own profile):
┌─────────────────────────────────────────────────────┐
│ [Avatar] 김민수 │
│ 파견직원 · 재직중 · 파견중 │
│ │
│ ┌─ Personal Info ─────────────────────────────────┐ │
│ │ Login ID: minsu.kim │ │
│ │ Name: 김민수 │ │
│ │ Email: minsu@example.com │ │
│ │ Phone: 010-1234-5678 │ │
│ │ Joined: 2024-03-01 │ │
│ │ Status: ACTIVE (DISPATCHED) │ │
│ │ [Edit Info] [Change Password] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ Dispatch History ──────────────────────────────┐ │
│ │ Timeline with projects, dates, roles │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ Portfolio Summary ─────────────────────────────┐ │
│ │ Aggregated stats: projects, tickets, reports │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
For MANAGER/ADMIN viewing another employee:
- URL:
/profile/[empId] - Same layout but with employee selector/dropdown at top
- Manager can view but not edit (unless admin)
- Admin can edit fields
3.3.4 Components to Create
| Component | Description |
|---|---|
src/app/(main)/profile/page.tsx |
Own profile view |
src/app/(main)/profile/[empId]/page.tsx |
View other employee's profile (MANAGER/ADMIN) |
src/components/profile/ProfileCard.tsx |
Personal info card with edit/change-password buttons |
src/components/profile/EditProfileModal.tsx |
Modal for editing personal info (admin only or self?) |
src/components/profile/ChangePasswordModal.tsx |
Modal with current/new/confirm password fields |
src/components/profile/DispatchTimeline.tsx |
Reuse timeline from /dispatch page |
src/components/profile/PortfolioStats.tsx |
Summary stats cards (total projects, total tickets resolved, etc.) |
3.4 Implementation Plan — User Profile
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Create ChangePasswordRequest DTO |
Backend dto | 0.1d |
| 2 | Add changePassword to AuthService |
AuthService.java |
0.3d |
| 3 | Add PUT /employees/me/password endpoint |
AuthController.java or EmployeeController.java |
0.2d |
| 4 | Extend EmployeeSummary to include phone, empStatus, joinedDate |
EmployeeSummary.java + EmployeeService.toSummary() |
0.2d |
| 5 | Add getMeFull() and changePassword() to employeeService |
src/services/employeeService.ts |
0.2d |
| 6 | Build ProfileCard component |
src/components/profile/ProfileCard.tsx |
0.5d |
| 7 | Build ChangePasswordModal component |
src/components/profile/ChangePasswordModal.tsx |
0.5d |
| 8 | Build EditProfileModal component (admin-only for role/status changes; self-service for email/phone) |
src/components/profile/EditProfileModal.tsx |
0.5d |
| 9 | Build PortfolioStats component |
src/components/profile/PortfolioStats.tsx |
0.3d |
| 10 | Build /profile page |
src/app/(main)/profile/page.tsx |
0.8d |
| 11 | Build /profile/[empId] page (manager/admin view) |
src/app/(main)/profile/[empId]/page.tsx |
0.4d |
| 12 | Make user avatar/name in Header clickable → /profile |
src/components/layout/Header.tsx |
0.1d |
| Total | 4 days |
4. ADMIN/MANAGER Management Features
4.1 Current State Analysis
4.1.1 Employee CRUD
| Operation | Backend | Frontend |
|---|---|---|
| List/View | ✅ GET /employees (MANAGER/ADMIN) |
✅ /employees page with table view |
| Create | ✅ POST /employees (ADMIN) |
✅ Modal in /employees page |
| Update | ✅ PUT /employees/{id} (ADMIN) |
❌ Only MoreHorizontal button with no handler |
| Delete | ✅ DELETE /employees/{id} (ADMIN) |
❌ No delete UI |
| Search | ✅ GET /employees/search |
✅ Search bar in /employees |
Gap: Edit and delete functionality missing from frontend. The MoreHorizontal button (line 454-456 in employees/page.tsx) is a blank <button> with no click handler.
4.1.2 Dispatch Assignment
| Operation | Backend | Frontend |
|---|---|---|
| Create dispatch | ❌ No endpoint | ❌ No page |
| List dispatch by employee | ✅ GET /employees/{id}/dispatch-histories |
❌ Only shown in employee's own /dispatch page |
| List all dispatches | ❌ No endpoint | ❌ No management view |
| Link employee to project | ❌ No endpoint | ❌ |
Gap: There is NO controller/service method for creating a DispatchHistory. The DispatchHistoryService exists but only has repository calls, no create/update methods. MANAGER/ADMIN have no way to assign employees to projects.
4.1.3 Report Monitoring Dashboard
| Operation | Backend | Frontend |
|---|---|---|
| List all reports | ✅ ReportController (MANAGER/ADMIN see all) | ✅ Works via work-reports page |
| Report review/approval | ✅ PUT /reports/{id}/review |
❌ No approval UI for managers |
| Pending count | ❌ No aggregate endpoint | Dashboard fetches totalElements from page=1 query (approximate) |
| Report statistics | ❌ No stats endpoint | ❌ |
Gap: Manager needs a dedicated report monitoring page showing all submitted reports in a table with quick approve/reject actions. Dashboard count is a workaround.
4.1.4 System Settings (Common Codes)
| Operation | Backend | Frontend |
|---|---|---|
| List codes by group | ✅ GET /common-codes/{groupCode} |
❌ No page |
| Create/Update/Delete codes | ❌ No endpoints | ❌ |
Gap: Common code management is a pure ADMIN function. There are no CRUD endpoints for common codes and no settings page.
4.2 Design Proposals
4.2.1 Employee Edit/Delete
Frontend: EmployeeEditModal.tsx
- Opens on
MoreHorizontalclick - Edit: name, email, roleCode, empStatus, dispatchStatus, joinedDate
- Delete: Confirm dialog → soft delete
- After save → refresh employee list
Add to /employees page:
// Replace blank MoreHorizontal button:
<button onClick={() => setEditingEmployee(emp)}>
<MoreHorizontal className="w-4 h-4" />
</button>
4.2.2 Dispatch Management
Backend needs:
New Controller: DispatchHistoryController.java
@PostMapping("/api/v1/dispatch-histories")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<DispatchHistory>> create(CreateDispatchRequest request)
@PutMapping("/api/v1/dispatch-histories/{dispatchId}")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<DispatchHistory>> update(Long dispatchId, UpdateDispatchRequest request)
@GetMapping("/api/v1/dispatch-histories")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<Page<DispatchHistory>>> findAll(Pageable pageable, @RequestParam(required=false) Long empId, @RequestParam(required=false) Long projectId)
New DTOs:
public record CreateDispatchRequest(
@NotNull Long empId,
@NotNull Long projectId,
@NotNull LocalDate startDate,
LocalDate endDate,
@NotBlank String roleTitle,
@NotNull Integer contributionRate,
@NotBlank String individualTech,
@NotBlank String performedTasks
) {}
Frontend: Dispatch Management Page
URL: /dispatch/manage (MANAGER/ADMIN only)
┌─────────────────────────────────────────────────────┐
│ Dispatch Management [+ New Dispatch] │
├─────────┬──────────┬─────────┬─────────┬────────────┤
│ Employee│ Project │ Role │ Period │ Actions │
├─────────┼──────────┼─────────┼─────────┼────────────┤
│ 김민수 │ Samsung │ Backend │ 24.03~ │ [Edit][Del]│
│ 이영희 │ LG CNS │ Frontend│ 24.06~ │ [Edit][Del]│
│ ... │ ... │ ... │ ... │ ... │
└─────────┴──────────┴─────────┴─────────┴────────────┘
Create Dispatch modal:
- Employee selector (autocomplete search)
- Project selector (dropdown from
/projects/myor all projects) - Date range picker
- Role title, contribution rate, tech stack, tasks
4.2.3 Report Monitoring Dashboard
URL: /work-reports/review (MANAGER/ADMIN only)
┌─────────────────────────────────────────────────────┐
│ Report Review Dashboard │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Submitted │ │Pending │ │Approved │ │Rejected │ │
│ │ 12 │ │ 5 │ │ 45 │ │ 3 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ [Filter: SUBMITTED ▼] [Date: 2026-05 ▼] [Search...]│
├─────────┬─────────┬──────────┬─────────┬────────────┤
│ Employee│ Type │ Date │ Status │ Action │
├─────────┼─────────┼──────────┼─────────┼────────────┤
│ 김민수 │ DAILY │ 05-26 │ SUBMIT │[✅][❌][👁] │
│ 이영희 │ WEEKLY │ 05-20 │ SUBMIT │[✅][❌][👁] │
│ 박철수 │ MONTHLY │ 05-01 │ SUBMIT │[✅][❌][👁] │
└─────────┴─────────┴──────────┴─────────┴────────────┘
Action buttons:
- ✅ Approve →
PUT /reports/{id}/review { status: "APPROVED" } - ❌ Reject → Opens rejection modal with required feedback text
- 👁 View → Navigate to report detail
New Backend Endpoint (optional):
@GetMapping("/api/v1/reports/summary")
@PreAuthorize("hasAnyRole('MANAGER','ADMIN')")
ResponseEntity<ApiResponse<ReportSummary>> getSummary()
// Returns counts by status: { submitted, approved, rejected, draft }
4.2.4 System Settings (Common Codes)
Backend needs:
New endpoints in CommonCodeController.java:
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<CommonCode>> create(CommonCode code)
@PutMapping("/{codeId}")
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<CommonCode>> update(Long codeId, CommonCode code)
@DeleteMapping("/{codeId}")
@PreAuthorize("hasRole('ADMIN')")
ResponseEntity<ApiResponse<Void>> delete(Long codeId)
Frontend: Settings Page
URL: /settings (ADMIN only)
┌─────────────────────────────────────────────────────┐
│ System Settings │
│ ┌──────────────────────┬───────────────────────────┐ │
│ │ Common Codes │ Code Group: [Role ▼] │ │
│ │ ├ Group List │ ┌──────┬──────┬────┬────┐ │ │
│ │ │ • Role │ │ Code │ Name │Sort│ │ │ │
│ │ │ • Report Type │ ├──────┼──────┼────┼────┤ │ │
│ │ │ • Ticket Category │ │EMPLOY│파견직원│ 1 │[✏️][🗑]│ │
│ │ │ • Equipment Type │ │MANAG│본사관리│ 2 │[✏️][🗑]│ │
│ │ │ • ... │ │ADMIN│최고 │ 3 │[✏️][🗑]│ │
│ │ │ │ └──────┴──────┴────┴────┘ │ │
│ │ │ │ [+ Add Code] │ │
│ └──────────────────────┴───────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Other Settings │ │
│ │ □ Enable email notifications │ │
│ │ □ Enable Slack notifications │ │
│ │ Default SLA hours: [48 ▼] │ │
│ │ [Save] │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
4.3 Implementation Plan — ADMIN/MANAGER Features
Phase A: Report Monitoring Dashboard (P1, ~2 days)
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Add ReportSummary DTO + GET /reports/summary endpoint |
Backend | 0.3d |
| 2 | Add reportService.getSummary() to frontend services |
src/services/reportService.ts |
0.1d |
| 3 | Build report review dashboard page | src/app/(main)/work-reports/review/page.tsx |
1.0d |
| 4 | Add approve/reject inline actions | Same as above + modal | 0.4d |
| 5 | Add navigation from dashboard "Pending Reports" card to review page | src/app/(main)/page.tsx |
0.1d |
| 6 | Add sidebar link for MANAGER/ADMIN (conditional render) | src/components/layout/Sidebar.tsx |
0.1d |
Phase B: Employee Edit/Delete (P1, ~1.5 days, already mostly built on backend)
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Build EmployeeEditModal component |
src/components/employees/EmployeeEditModal.tsx |
0.5d |
| 2 | Add delete confirmation dialog | Same component | 0.2d |
| 3 | Wire MoreHorizontal button to open edit modal |
src/app/(main)/employees/page.tsx |
0.3d |
| 4 | Refresh list after edit/delete | Same page | 0.2d |
| 5 | Add employee detail view (linking to /profile/[empId]) |
Same page | 0.3d |
Phase C: Dispatch Management (P2, ~3 days)
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Create CreateDispatchRequest + UpdateDispatchRequest DTOs |
Backend | 0.2d |
| 2 | Create DispatchHistoryController with CRUD endpoints |
Backend | 0.5d |
| 3 | Add dispatchHistoryService.getAll(), .create(), .update(), .delete() to frontend |
src/services/dispatchHistoryService.ts (new) |
0.3d |
| 4 | Build dispatch management page | src/app/(main)/dispatch/manage/page.tsx |
1.0d |
| 5 | Build create/edit dispatch modal with employee search + project select | Same + modal component | 0.8d |
| 6 | Add sidebar link (MANAGER/ADMIN only) | src/components/layout/Sidebar.tsx |
0.1d |
Phase D: System Settings (P2, ~1.5 days)
| Step | Task | File(s) | Effort |
|---|---|---|---|
| 1 | Add POST/PUT/DELETE to CommonCodeController | Backend | 0.3d |
| 2 | Add create/update/delete to commonCodeService |
src/services/commonCodeService.ts (new) |
0.2d |
| 3 | Build settings page with code group list + editor | src/app/(main)/settings/page.tsx |
1.0d |
| 4 | Add sidebar link (ADMIN only) | src/components/layout/Sidebar.tsx |
0.1d |
5. Consolidated File List
5.1 Backend — Files to Create
| File | Feature | Description |
|---|---|---|
dto/CalendarEventDto.java |
Calendar | Calendar event aggregation DTO |
service/CalendarService.java |
Calendar | Aggregation logic from Ticket, Report, Dispatch |
controller/CalendarController.java |
Calendar | GET /api/v1/calendar endpoint |
dto/ChangePasswordRequest.java |
Profile | Password change request DTO |
dto/CreateDispatchRequest.java |
Dispatch | Dispatch creation request DTO |
dto/UpdateDispatchRequest.java |
Dispatch | Dispatch update request DTO |
controller/DispatchHistoryController.java |
Dispatch | Full CRUD for dispatch histories |
service/DispatchManagementService.java |
Dispatch | Management-level dispatch operations |
5.2 Backend — Files to Modify
| File | Feature | Change |
|---|---|---|
entity/Notification.java |
Notifications | Add linkUrl column |
dto/EmployeeSummary.java |
Profile | Add phone, empStatus, joinedDate, leftDate fields |
service/AuthService.java |
Profile | Add changePassword() method |
controller/AuthController.java or EmployeeController.java |
Profile | Add PUT /employees/me/password endpoint |
service/EmployeeService.java |
Profile | Update toSummary() to include new fields |
controller/ReportController.java |
Reports | Add GET /reports/summary endpoint |
controller/CommonCodeController.java |
Settings | Add POST, PUT, DELETE endpoints |
service/CommonCodeService.java |
Settings | Add create, update, delete methods |
5.3 Frontend — Files to Create
| File | Feature | Description |
|---|---|---|
src/services/calendarService.ts |
Calendar | GET /calendar?start=&end= |
src/services/dispatchHistoryService.ts |
Dispatch | Full CRUD for dispatch histories |
src/services/commonCodeService.ts |
Settings | CRUD for common codes |
src/components/calendar/CalendarGrid.tsx |
Calendar | Monthly calendar grid component |
src/components/calendar/CalendarEvent.tsx |
Calendar | Event chip component |
src/components/calendar/EventDetailPanel.tsx |
Calendar | Event detail modal |
src/components/layout/NotificationDropdown.tsx |
Notifications | Bell dropdown component |
src/components/profile/ProfileCard.tsx |
Profile | Personal info display/edit card |
src/components/profile/ChangePasswordModal.tsx |
Profile | Password change modal |
src/components/profile/EditProfileModal.tsx |
Profile | Profile edit modal |
src/components/profile/PortfolioStats.tsx |
Profile | Portfolio summary stats |
src/components/employees/EmployeeEditModal.tsx |
Admin | Employee edit + delete modal |
src/components/dispatch/DispatchFormModal.tsx |
Admin | Create/edit dispatch form |
src/app/(main)/calendar/page.tsx |
Calendar | Calendar page |
src/app/(main)/profile/page.tsx |
Profile | Own profile page |
src/app/(main)/profile/[empId]/page.tsx |
Profile | Employee profile (manager view) |
src/app/(main)/work-reports/review/page.tsx |
Reports | Report review dashboard |
src/app/(main)/dispatch/manage/page.tsx |
Dispatch | Dispatch management page |
src/app/(main)/settings/page.tsx |
Settings | System settings page |
5.4 Frontend — Files to Modify
| File | Feature | Change |
|---|---|---|
src/types/index.ts |
All | Add Notification.linkUrl, CalendarEvent, ReportSummary, CalendarEvent types |
src/services/index.ts |
All | Export new services |
src/services/employeeService.ts |
Profile | Add getMeFull(), changePassword() |
src/services/reportService.ts |
Reports | Add getSummary() |
src/components/layout/Header.tsx |
Calendar + Profile + Notifications | Calendar → /calendar, integrate NotificationDropdown, avatar → /profile |
src/components/layout/Sidebar.tsx |
All | Add Calendar, Report Review, Settings links (with RBAC) |
src/app/(main)/page.tsx |
Reports | Link "Pending Reports" card to /work-reports/review |
src/app/(main)/employees/page.tsx |
Admin | Wire MoreHorizontal to edit modal |
6. Recommended Implementation Order
Week 1: Quick Wins
Day 1-2: Notifications (Dropdown UI + linkUrl) ← P1, ~2d
Day 3-5: User Profile (ProfilePage + ChangePassword) ← P1, ~4d
Week 2: Calendar + Report Management
Day 1-3: Employee Edit/Delete (EmployeeEditModal) ← P1, ~1.5d
Day 3-5: Report Monitoring Dashboard ← P1, ~2d
Week 3: Calendar + Dispatch
Day 1-5: Calendar (Backend aggregation + Full Calendar page) ← P2, ~5d
Week 4: Admin Features
Day 1-3: Dispatch Management (CRUD endpoints + page) ← P2, ~3d
Day 4-5: System Settings (CommonCode CRUD + Settings page) ← P2, ~1.5d
Alternative — parallel by developer:
- Dev A: Calendar (5d) + Settings (1.5d) = 6.5d
- Dev B: Notifications (2d) + Profile (4d) = 6d
- Dev C: Employee Edit (1.5d) + Report Dashboard (2d) + Dispatch (3d) = 6.5d
- Total calendar time: ~1.5 weeks with 3 developers
7. Risk Assessment
| Risk | Impact | Mitigation |
|---|---|---|
| Calendar aggregation performance with large datasets | Medium | Add DB indexes on due_date, target_date; paginate results |
| Notification polling load | Low | Already 30s interval — acceptable. Could go to 60s after 30min idle |
| Password change breaks existing sessions | Medium | Option A: Invalidate all tokens on password change. Option B: Add tokenVersion to user and check on JWT validation |
| DispatchHistory creation without project exists validation | Medium | Backend must validate project exists and is not completed/hold |
| Common code changes break existing dropdowns | High | Never hard-delete common codes — add is_active toggle instead. Frontend caches codes on load |
| Concurrent employee edits by multiple admins | Low | Add @Version optimistic lock to Employee entity |
8. Quick Wins (Low Effort, High Impact)
If you only have 1 day, do these:
- Notification Dropdown (~2h) — Make the bell icon functional. Just build the dropdown UI, no backend changes needed. Notifications already have type/title/message.
- Header Calendar fix (~5min) — Change
onClick={() => router.push('/issues')}toonClick={() => router.push('/calendar')}even before building the calendar page — at least the button has a logical destination. - Header avatar → /profile (~5min) — Wrap the avatar/name in a Link to
/profile. - Employee MoreHorizontal → Edit (~2h) — Wire the existing
PUT /employees/{id}backend to a simple edit form.