feat: Initial commit - Task Reporter incident response system

Complete implementation of the production line incident response system (生產線異常即時反應系統) including:

Backend (FastAPI):
- User authentication with AD integration and session management
- Chat room management (create, list, update, members, roles)
- Real-time messaging via WebSocket (typing indicators, reactions)
- File storage with MinIO (upload, download, image preview)

Frontend (React + Vite):
- Authentication flow with token management
- Room list with filtering, search, and pagination
- Real-time chat interface with WebSocket
- File upload with drag-and-drop and image preview
- Member management and room settings
- Breadcrumb navigation
- 53 unit tests (Vitest)

Specifications:
- authentication: AD auth, sessions, JWT tokens
- chat-room: rooms, members, templates
- realtime-messaging: WebSocket, messages, reactions
- file-storage: MinIO integration, file management
- frontend-core: React SPA structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-01 17:42:52 +08:00
commit c8966477b9
135 changed files with 23269 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
# Frontend Architecture Design
## Context
Task Reporter needs a frontend to enable factory personnel to use the incident response system. The application must work on internal network only, support real-time collaboration, and integrate with existing backend APIs.
**Stakeholders**: Line operators, supervisors, engineers, managers
**Constraints**: On-premise deployment, internal network only, no external CDN
## Goals / Non-Goals
### Goals
- Provide intuitive UI for incident management workflow
- Enable real-time collaboration via WebSocket
- Support file upload with image preview
- Work offline-first where possible (local state)
- Responsive design for desktop and tablet
### Non-Goals
- Mobile app (web responsive is sufficient)
- Offline mode with sync (requires backend changes)
- Multi-language i18n (Chinese-only for initial release)
- PWA capabilities (not required for internal use)
## Decisions
### 1. Framework: React 18 + Vite
**Decision**: Use React 18 with Vite for fast development and build
**Rationale**:
- Vite provides fast HMR and build times
- React 18 concurrent features for better UX
- Large ecosystem and team familiarity
- Static build can be served by FastAPI
**Alternatives considered**:
- Vue 3: Good option, but team has more React experience
- Next.js: SSR not needed for internal SPA
- Vanilla JS: Too much boilerplate for complex app
### 2. State Management: Zustand + React Query
**Decision**: Use Zustand for client state, React Query for server state
**Rationale**:
- Zustand: Minimal boilerplate, TypeScript-friendly
- React Query: Automatic caching, refetching, optimistic updates
- Clear separation between client and server state
**Alternatives considered**:
- Redux Toolkit: More boilerplate than needed
- Context only: Not suitable for complex state
- SWR: React Query has better DevTools
### 3. Styling: Tailwind CSS
**Decision**: Use Tailwind CSS for utility-first styling
**Rationale**:
- Fast development with utility classes
- Consistent design system
- Small bundle size with purging
- Good for component-based architecture
**Alternatives considered**:
- CSS Modules: More boilerplate
- Styled Components: Runtime overhead
- Ant Design: Too opinionated, Chinese license concerns
### 4. WebSocket: Native WebSocket with reconnection
**Decision**: Use native WebSocket API with custom reconnection logic
**Rationale**:
- Backend uses native WebSocket (not Socket.IO)
- Simple protocol, no heavy library needed
- Custom reconnection gives more control
**Alternatives considered**:
- Socket.IO client: Backend doesn't use Socket.IO
- SockJS: Unnecessary fallbacks for modern browsers
### 5. Directory Structure
```
frontend/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── common/ # Buttons, inputs, modals
│ │ ├── chat/ # Chat-related components
│ │ ├── room/ # Room management components
│ │ └── file/ # File upload/preview
│ ├── pages/ # Route pages
│ │ ├── Login.tsx
│ │ ├── RoomList.tsx
│ │ ├── RoomDetail.tsx
│ │ └── NotFound.tsx
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ ├── useWebSocket.ts
│ │ └── useRoom.ts
│ ├── stores/ # Zustand stores
│ │ ├── authStore.ts
│ │ └── chatStore.ts
│ ├── services/ # API client functions
│ │ ├── api.ts # Axios instance
│ │ ├── auth.ts
│ │ ├── rooms.ts
│ │ └── files.ts
│ ├── types/ # TypeScript types
│ ├── utils/ # Utility functions
│ └── App.tsx # Root component
├── public/
├── index.html
├── package.json
├── vite.config.ts
├── tailwind.config.js
└── tsconfig.json
```
## Risks / Trade-offs
### Risk: WebSocket connection stability
**Mitigation**: Implement exponential backoff reconnection, connection status indicator, message queue for offline messages
### Risk: Large file uploads blocking UI
**Mitigation**: Use chunked uploads with progress indicator, background upload queue
### Risk: Token expiry during long sessions
**Mitigation**: Auto-refresh tokens before expiry, graceful re-authentication flow
## API Integration
### Authentication
- POST `/api/auth/login` - Returns internal token
- Store token in localStorage
- Attach `Authorization: Bearer {token}` to all requests
### WebSocket Connection
- Connect to `/api/ws/{room_id}?token={token}`
- Handle message types: message, edit_message, delete_message, typing, system
### File Upload
- POST `/api/rooms/{room_id}/files` with multipart/form-data
- Display progress during upload
- Show thumbnail for images after upload
## Open Questions
- [ ] Should we bundle the frontend with FastAPI or serve separately?
- **Answer**: Bundle with FastAPI for simpler deployment (single container)
- [ ] Image thumbnail generation - frontend or backend?
- **Answer**: Backend generates thumbnails, frontend displays from MinIO URL

View File

@@ -0,0 +1,31 @@
# Change: Add React Frontend Application
## Why
The Task Reporter system currently has a complete backend API but no user interface. Users cannot interact with the incident response system without a frontend application. A React-based SPA will enable production line operators, supervisors, and engineers to create incident rooms, collaborate in real-time, upload evidence files, and manage incident resolution.
## What Changes
- **NEW**: React 18 + Vite frontend application
- **NEW**: Authentication flow (login/logout with token management)
- **NEW**: Incident room management UI (create, list, view, update)
- **NEW**: Real-time chat interface with WebSocket integration
- **NEW**: File upload/download interface with image preview
- **NEW**: Member management UI (add, remove, change roles)
- **NEW**: Responsive layout for desktop and tablet use
## Impact
- Affected specs: Creates new `frontend-core` specification
- Affected code:
- New `frontend/` directory with React application
- Backend CORS configuration update (app/main.py)
- Static file serving configuration
## Dependencies
- Backend API must be running (localhost:8000)
- MinIO must be running for file uploads (localhost:9000)
## Success Criteria
1. Users can login with AD credentials
2. Users can create and join incident rooms
3. Users can send/receive messages in real-time
4. Users can upload and view files (images, PDFs, logs)
5. Room owners can manage members and room status

View File

@@ -0,0 +1,268 @@
## ADDED Requirements
### Requirement: User Authentication Interface
The frontend SHALL provide a login interface that authenticates users against the backend API and maintains session state.
#### Scenario: Successful login
- **WHEN** a user enters valid AD credentials and submits the login form
- **THEN** the system SHALL:
- Send POST request to `/api/auth/login`
- Store the returned token in localStorage
- Redirect user to the room list page
- Display the user's display name in the navigation
#### Scenario: Failed login with invalid credentials
- **WHEN** a user enters invalid credentials
- **THEN** the system SHALL:
- Display error message "Invalid credentials"
- Keep user on login page
- Clear the password field
#### Scenario: Session persistence across page refresh
- **WHEN** a user refreshes the page while logged in
- **THEN** the system SHALL:
- Retrieve token from localStorage
- Validate session is still active
- Restore user session without requiring re-login
#### Scenario: Logout
- **WHEN** a logged-in user clicks the logout button
- **THEN** the system SHALL:
- Send POST request to `/api/auth/logout`
- Clear token from localStorage
- Redirect to login page
### Requirement: Incident Room List
The frontend SHALL display a filterable, searchable list of incident rooms accessible to the current user.
#### Scenario: Display room list
- **WHEN** a logged-in user navigates to the room list page
- **THEN** the system SHALL:
- Fetch rooms from `GET /api/rooms`
- Display rooms as cards with title, status, severity, and timestamp
- Show the user's role in each room
- Order by last activity (most recent first)
#### Scenario: Filter rooms by status
- **WHEN** a user selects a status filter (Active, Resolved, Archived)
- **THEN** the system SHALL:
- Update the room list to show only rooms matching the filter
- Preserve other active filters
#### Scenario: Search rooms
- **WHEN** a user enters text in the search box
- **THEN** the system SHALL:
- Filter rooms by title and description containing the search text
- Update results in real-time (debounced)
#### Scenario: Create new room
- **WHEN** a user clicks "New Room" and fills the creation form
- **THEN** the system SHALL:
- Display template selection if templates exist
- Submit room creation to `POST /api/rooms`
- Navigate to the new room on success
- Show error message on failure
### Requirement: Incident Room Detail View
The frontend SHALL display complete incident room information including metadata, members, and provide management controls for authorized users.
#### Scenario: View room details
- **WHEN** a user navigates to a room detail page
- **THEN** the system SHALL:
- Fetch room details from `GET /api/rooms/{room_id}`
- Display room title, status, severity, location, description
- Show member list with roles
- Display created timestamp and last activity
#### Scenario: Update room metadata (Owner/Editor)
- **WHEN** an owner or editor updates room fields (title, severity, description)
- **THEN** the system SHALL:
- Submit changes to `PATCH /api/rooms/{room_id}`
- Update the UI optimistically
- Revert on failure with error message
#### Scenario: Change room status (Owner only)
- **WHEN** a room owner changes status to Resolved or Archived
- **THEN** the system SHALL:
- Prompt for confirmation
- Submit status change to backend
- Update room header to reflect new status
- Broadcast status change to connected members
#### Scenario: View room with insufficient permissions
- **WHEN** a user tries to access a room they are not a member of
- **THEN** the system SHALL:
- Display "Access Denied" message
- Provide option to request access or return to room list
### Requirement: Real-time Chat Interface
The frontend SHALL provide a real-time chat interface using WebSocket connections for instant message delivery.
#### Scenario: Connect to room chat
- **WHEN** a user opens a room detail page
- **THEN** the system SHALL:
- Establish WebSocket connection to `/api/ws/{room_id}?token={token}`
- Load message history from REST API
- Display connection status indicator
- Subscribe to real-time message updates
#### Scenario: Send text message
- **WHEN** a user types a message and presses Enter or clicks Send
- **THEN** the system SHALL:
- Send message via WebSocket
- Display message immediately (optimistic update)
- Show delivery confirmation when acknowledged
- Show error indicator if delivery fails
#### Scenario: Receive message from other user
- **WHEN** another user sends a message to the room
- **THEN** the system SHALL:
- Display the new message in the chat
- Scroll to the new message if user is at bottom
- Show notification badge if user has scrolled up
#### Scenario: Display typing indicator
- **WHEN** another user is typing
- **THEN** the system SHALL:
- Show "{username} is typing..." indicator
- Hide indicator after 3 seconds of inactivity
#### Scenario: Edit own message
- **WHEN** a user edits their own message within edit window
- **THEN** the system SHALL:
- Display edit input pre-filled with original content
- Submit edit via WebSocket
- Update message with "edited" indicator
#### Scenario: Delete own message
- **WHEN** a user deletes their own message
- **THEN** the system SHALL:
- Prompt for confirmation
- Submit delete via WebSocket
- Remove or mark message as deleted in UI
#### Scenario: WebSocket reconnection
- **WHEN** WebSocket connection is lost
- **THEN** the system SHALL:
- Display "Reconnecting..." indicator
- Attempt reconnection with exponential backoff
- Restore connection and sync missed messages
- Show error after max retry attempts
### Requirement: File Upload and Management Interface
The frontend SHALL provide file upload capabilities with progress indication, preview for images, and file management controls.
#### Scenario: Upload file via button
- **WHEN** a user clicks the upload button and selects a file
- **THEN** the system SHALL:
- Validate file type and size client-side
- Display upload progress bar
- Upload to `POST /api/rooms/{room_id}/files`
- Show file in chat/file list on success
- Display error message on failure
#### Scenario: Upload file via drag and drop
- **WHEN** a user drags a file into the chat area
- **THEN** the system SHALL:
- Show drop zone indicator
- Accept the file on drop
- Proceed with upload as button upload
#### Scenario: Preview image file
- **WHEN** a user clicks on an uploaded image
- **THEN** the system SHALL:
- Open image in a modal preview
- Allow zoom and pan
- Provide download button
#### Scenario: Download file
- **WHEN** a user clicks download on a file
- **THEN** the system SHALL:
- Fetch presigned URL from `GET /api/rooms/{room_id}/files/{file_id}`
- Trigger browser download with original filename
#### Scenario: Delete file (uploader or owner)
- **WHEN** file uploader or room owner clicks delete on a file
- **THEN** the system SHALL:
- Prompt for confirmation
- Submit delete to `DELETE /api/rooms/{room_id}/files/{file_id}`
- Remove file from UI
#### Scenario: View file list
- **WHEN** a user opens the files panel in a room
- **THEN** the system SHALL:
- Fetch files from `GET /api/rooms/{room_id}/files`
- Display files with thumbnails for images
- Show filename, size, uploader, and timestamp
- Support filtering by file type
### Requirement: Member Management Interface
The frontend SHALL provide member management controls for room owners and editors with appropriate role-based access.
#### Scenario: View member list
- **WHEN** a user views a room
- **THEN** the system SHALL:
- Display all active members
- Show each member's role (Owner, Editor, Viewer)
- Indicate online status for connected members
#### Scenario: Add member (Owner/Editor)
- **WHEN** an owner or editor adds a new member
- **THEN** the system SHALL:
- Display member search/input field
- Allow role selection
- Submit to `POST /api/rooms/{room_id}/members`
- Update member list on success
#### Scenario: Change member role (Owner only)
- **WHEN** an owner changes another member's role
- **THEN** the system SHALL:
- Display role selector
- Submit to `PATCH /api/rooms/{room_id}/members/{user_id}`
- Update member display on success
#### Scenario: Remove member (Owner/Editor)
- **WHEN** an owner or editor removes a member
- **THEN** the system SHALL:
- Prompt for confirmation
- Submit to `DELETE /api/rooms/{room_id}/members/{user_id}`
- Remove member from list
#### Scenario: Transfer ownership (Owner only)
- **WHEN** a room owner transfers ownership to another member
- **THEN** the system SHALL:
- Prompt for confirmation with warning
- Submit to `POST /api/rooms/{room_id}/transfer-ownership`
- Update roles in UI (current owner becomes Editor)
### Requirement: Responsive Layout and Navigation
The frontend SHALL provide a responsive layout that works on desktop and tablet devices with intuitive navigation.
#### Scenario: Desktop layout
- **WHEN** viewed on desktop (>1024px)
- **THEN** the system SHALL:
- Display sidebar navigation
- Show room list and detail side-by-side when applicable
- Display member panel as sidebar
#### Scenario: Tablet layout
- **WHEN** viewed on tablet (768px-1024px)
- **THEN** the system SHALL:
- Collapse sidebar to icons or hamburger menu
- Use full width for content areas
- Stack panels vertically
#### Scenario: Navigation between pages
- **WHEN** a user navigates using browser back/forward
- **THEN** the system SHALL:
- Maintain correct route state
- Preserve scroll position where applicable
- Not lose unsent message drafts
#### Scenario: Error handling
- **WHEN** an API request fails
- **THEN** the system SHALL:
- Display user-friendly error message
- Provide retry option where applicable
- Log error details for debugging
- Not crash or show blank screen

View File

@@ -0,0 +1,134 @@
# Implementation Tasks
## 1. Project Setup
- [x] 1.1 Initialize Vite + React + TypeScript project in `frontend/`
- [x] 1.2 Install dependencies (react-router, zustand, @tanstack/react-query, axios)
- [x] 1.3 Configure Tailwind CSS
- [x] 1.4 Set up ESLint + Prettier
- [x] 1.5 Create directory structure (components, pages, hooks, stores, services)
- [x] 1.6 Configure Vite proxy for API calls to localhost:8000
## 2. API Client Layer
- [x] 2.1 Create Axios instance with base URL and interceptors
- [x] 2.2 Implement auth service (login, logout, token refresh)
- [x] 2.3 Implement rooms service (CRUD, members, templates)
- [x] 2.4 Implement messages service (list, create, search)
- [x] 2.5 Implement files service (upload, list, download, delete)
- [x] 2.6 Add TypeScript types matching backend schemas
## 3. State Management
- [x] 3.1 Create auth store (user, token, login state)
- [x] 3.2 Create chat store (messages, typing users, online users)
- [x] 3.3 Set up React Query provider and default options
- [x] 3.4 Create custom hooks (useAuth, useRooms, useMessages, useFiles)
## 4. Authentication Pages
- [x] 4.1 Create Login page with form validation
- [x] 4.2 Implement login flow with error handling
- [x] 4.3 Create protected route wrapper
- [x] 4.4 Add logout functionality
- [x] 4.5 Handle token storage and auto-login
## 5. Room List Page
- [x] 5.1 Create RoomList page layout
- [x] 5.2 Implement room cards with status indicators
- [x] 5.3 Add filtering by status
- [x] 5.4 Add search functionality
- [x] 5.5 Create "New Room" modal
- [x] 5.6 Add pagination with Previous/Next controls
## 6. Room Detail Page
- [x] 6.1 Create room header (title, status, severity badge)
- [x] 6.2 Implement member sidebar
- [x] 6.3 Create room settings panel (for owners) - status change buttons
- [x] 6.4 Add status change functionality (resolve, archive)
- [x] 6.5 Implement member management (add, remove, change role)
## 7. Real-time Chat
- [x] 7.1 Create WebSocket connection hook with auto-reconnect
- [x] 7.2 Implement message list component
- [x] 7.3 Create message input with submit handling
- [x] 7.4 Add typing indicator display
- [x] 7.5 Implement message edit functionality
- [x] 7.6 Implement message delete functionality
- [x] 7.7 Add reaction support with quick emoji picker
- [x] 7.8 Show online user indicators
## 8. File Management
- [x] 8.1 Create file upload button with drag-and-drop
- [x] 8.2 Implement upload progress indicator
- [x] 8.3 Create file list view
- [x] 8.4 Add image preview modal
- [x] 8.5 Implement file download functionality
- [x] 8.6 Add file delete with confirmation
## 9. Common Components
- [x] 9.1-9.7 Using Tailwind utility classes inline (no separate component library)
## 10. Routing and Layout
- [x] 10.1 Set up React Router with routes
- [x] 10.2 Create main layout with navigation
- [x] 10.3 Create 404 Not Found page
- [x] 10.4 Add breadcrumb navigation component
- [x] 10.5 Implement responsive sidebar
## 11. Testing
- [x] 11.1 Set up Vitest for unit testing
- [x] 11.2 Write tests for API services (mocked)
- [x] 11.3 Write tests for Zustand stores
- [x] 11.4 Write tests for custom hooks (useAuth, useRooms)
- [x] 11.5 Add component tests for critical paths (Login, Breadcrumb)
## 12. Build and Integration
- [x] 12.1 Configure production build settings
- [x] 12.2 Set up FastAPI to serve static files
- [x] 12.3 CORS already configured (allow all in development)
- [x] 12.4 Build script: `cd frontend && npm run build`
- [x] 12.5 Test full integration with backend
## Summary
**Completed:** All sections 1-12 (all features and tests)
**Note:** Section 9 uses inline Tailwind classes instead of separate component library
### Files Created
```
frontend/
├── src/
│ ├── types/index.ts # TypeScript types
│ ├── services/
│ │ ├── api.ts # Axios instance
│ │ ├── auth.ts # Auth service
│ │ ├── rooms.ts # Rooms service
│ │ ├── messages.ts # Messages service
│ │ ├── files.ts # Files service
│ │ └── index.ts
│ ├── stores/
│ │ ├── authStore.ts # Zustand auth store
│ │ └── chatStore.ts # Zustand chat store
│ ├── hooks/
│ │ ├── useAuth.ts # Auth hook
│ │ ├── useRooms.ts # Room queries/mutations
│ │ ├── useMessages.ts # Message queries/mutations
│ │ ├── useFiles.ts # File queries/mutations
│ │ ├── useWebSocket.ts # WebSocket hook
│ │ └── index.ts
│ ├── pages/
│ │ ├── Login.tsx # Login page
│ │ ├── RoomList.tsx # Room list page
│ │ ├── RoomDetail.tsx # Room detail with chat
│ │ ├── NotFound.tsx # 404 page
│ │ └── index.ts
│ ├── App.tsx # Root component with routes
│ ├── main.tsx # Entry point
│ └── index.css # Tailwind imports
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind configuration
├── tsconfig.json # TypeScript config
└── package.json # Dependencies
```
### Backend Integration
- `app/main.py` updated to serve frontend static files from `frontend/dist/`
- SPA routing support via catch-all route