feat: Add mobile responsive layout, open room access, and admin room management

Mobile Responsive Layout:
- Add useMediaQuery, useIsMobile, useIsTablet, useIsDesktop hooks for device detection
- Create MobileHeader component with hamburger menu and action drawer
- Create BottomToolbar for mobile navigation (Files, Members)
- Create SlidePanel component for full-screen mobile sidebars
- Update RoomDetail.tsx with mobile/desktop conditional rendering
- Update RoomList.tsx with single-column grid and touch-friendly buttons
- Add CSS custom properties for safe areas and touch targets (min 44px)
- Add mobile viewport meta tags for notched devices

Open Room Access:
- All authenticated users can view all rooms (not just their own)
- Users can join active rooms they're not members of
- Add is_member field to room responses
- Update room list API to return all rooms by default

Admin Room Management:
- Add permanent delete functionality for system admins
- Add delete confirmation dialog with room title verification
- Broadcast room deletion via WebSocket to connected users
- Add users search API for adding members

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-05 09:12:10 +08:00
parent 1e44a63a8e
commit 1d5d4d447d
48 changed files with 3505 additions and 401 deletions

View File

@@ -52,23 +52,18 @@ The system SHALL allow authenticated users to create a new incident room with me
- **THEN** the system SHALL return status 401 with "Authentication required"
### Requirement: List and Filter Incident Rooms
The system SHALL provide endpoints to list incident rooms with filtering capabilities by status, incident type, severity, date range, and user membership.
The system SHALL provide endpoints to list incident rooms with filtering capabilities by status, incident type, severity, date range, and user membership. The system SHALL automatically exclude rooms with ARCHIVED status from listing results for non-admin users, ensuring archived rooms are only visible to system administrators.
#### Scenario: List all active rooms for current user
- **WHEN** an authenticated user sends `GET /api/rooms?status=active`
- **THEN** the system SHALL return all active rooms where the user is a member
- **THEN** the system SHALL return all active rooms
- **AND** include room metadata (title, type, severity, member count, last activity)
- **AND** sort by last_activity_at descending (most recent first)
#### Scenario: Filter rooms by incident type and date range
- **WHEN** a user sends `GET /api/rooms?incident_type=quality_issue&created_after=2025-01-01&created_before=2025-01-31`
- **THEN** the system SHALL return rooms matching ALL filter criteria
- **AND** only include rooms where the user is a member
#### Scenario: Search rooms by title or description
- **WHEN** a user sends `GET /api/rooms?search=conveyor`
- **THEN** the system SHALL return rooms where title OR description contains "conveyor" (case-insensitive)
- **AND** highlight matching terms in the response
#### Scenario: Non-admin user lists rooms without status filter
- **WHEN** a non-admin user sends `GET /api/rooms` without status parameter
- **THEN** the system SHALL return rooms with status "active" or "resolved" only
- **AND** automatically exclude archived rooms from results
### Requirement: Manage Room Membership
The system SHALL allow room owners and members with appropriate permissions to add or remove members and assign roles (owner, editor, viewer). Room owners SHALL be able to transfer ownership to another member. System administrators SHALL have override capabilities for all membership operations.
@@ -218,3 +213,50 @@ The system SHALL support predefined room templates for common incident types to
- Default values for each template
- Required additional fields
### Requirement: Admin Permanent Room Deletion
The system SHALL provide system administrators with the ability to permanently delete rooms, including all associated data (members, messages, files, reports). This operation is irreversible and restricted to system administrators only.
#### Scenario: Admin permanently deletes a room
- **WHEN** a system administrator sends `DELETE /api/rooms/{room_id}/permanent`
- **THEN** the system SHALL verify the user is ymirliu@panjit.com.tw
- **AND** hard delete the room record from incident_rooms table
- **AND** cascade delete all room_members records
- **AND** cascade delete all messages and related reactions/edit_history
- **AND** cascade delete all room_files records
- **AND** delete associated files from MinIO storage
- **AND** cascade delete all generated_reports records
- **AND** delete associated report files from MinIO storage
- **AND** broadcast disconnect event to any active WebSocket connections in the room
- **AND** return status 200 with `{"message": "Room permanently deleted"}`
#### Scenario: Non-admin attempts permanent deletion
- **WHEN** a non-admin user sends `DELETE /api/rooms/{room_id}/permanent`
- **THEN** the system SHALL return status 403 with "Only system administrators can permanently delete rooms"
#### Scenario: Permanent delete non-existent room
- **WHEN** a system administrator sends `DELETE /api/rooms/{room_id}/permanent` for a non-existent room
- **THEN** the system SHALL return status 404 with "Room not found"
### Requirement: Hide Archived Rooms from Non-Admin Users
The system SHALL hide rooms with ARCHIVED status from non-admin users in all listing operations, ensuring historical/archived data is only visible to system administrators.
#### Scenario: Non-admin lists rooms with any filter
- **WHEN** a non-admin user sends `GET /api/rooms` with any status filter (including no filter)
- **THEN** the system SHALL exclude all rooms with status "archived" from the response
- **AND** only return rooms with status "active" or "resolved"
#### Scenario: Non-admin explicitly requests archived rooms
- **WHEN** a non-admin user sends `GET /api/rooms?status=archived`
- **THEN** the system SHALL return an empty list
- **AND** return total count of 0
#### Scenario: Admin can view archived rooms
- **WHEN** a system administrator sends `GET /api/rooms?status=archived`
- **THEN** the system SHALL return all archived rooms
- **AND** include full room details
#### Scenario: Admin views all rooms including archived
- **WHEN** a system administrator sends `GET /api/rooms` without status filter
- **THEN** the system SHALL return all rooms regardless of status
- **AND** include archived rooms in the response

View File

@@ -36,35 +36,26 @@ The frontend SHALL provide a login interface that authenticates users against th
- Redirect to login page
### Requirement: Incident Room List
The frontend SHALL display a filterable, searchable list of incident rooms accessible to the current user.
The frontend SHALL display a filterable, searchable list of incident rooms accessible to the current user. The frontend SHALL restrict the status filter options to show only "Active" and "Resolved" for non-admin users, and SHALL display all status options including "Archived" only for system administrators.
#### Scenario: Display room list
- **WHEN** a logged-in user navigates to the room list page
#### Scenario: Filter rooms by status (Non-admin)
- **WHEN** a non-admin user views the status filter dropdown
- **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)
- Display only "Active" and "Resolved" options
- NOT display "Archived" option
- NOT display "All Status" option that would include archived rooms
#### Scenario: Filter rooms by status
- **WHEN** a user selects a status filter (Active, Resolved, Archived)
#### Scenario: Filter rooms by status (Admin)
- **WHEN** a system administrator views the status filter dropdown
- **THEN** the system SHALL:
- Update the room list to show only rooms matching the filter
- Preserve other active filters
- Display all status options: "All Status", "Active", "Resolved", "Archived"
- Allow viewing archived rooms
#### Scenario: Search rooms
- **WHEN** a user enters text in the search box
#### Scenario: Default status filter
- **WHEN** a user navigates to the room list page
- **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
- Default to "Active" status filter for all users
- Fetch only active rooms initially
### Requirement: Incident Room Detail View
The frontend SHALL display complete incident room information including metadata, members, and provide management controls for authorized users.
@@ -270,3 +261,43 @@ The frontend SHALL provide a responsive layout that works on desktop and tablet
- Log error details for debugging
- Not crash or show blank screen
### Requirement: Admin Room Deletion Interface
The frontend SHALL provide system administrators with the ability to permanently delete rooms through a dedicated UI control.
#### Scenario: Display delete button for admin
- **WHEN** a system administrator views a room detail page
- **THEN** the system SHALL:
- Display a "Delete Room Permanently" button in room settings/actions
- Style the button with warning color (red)
- Only show this button to admin users
#### Scenario: Hide delete button for non-admin
- **WHEN** a non-admin user views a room detail page
- **THEN** the system SHALL:
- NOT display permanent delete option
- Only show standard archive option (if owner)
#### Scenario: Confirm permanent deletion
- **WHEN** an admin clicks "Delete Room Permanently"
- **THEN** the system SHALL:
- Display a confirmation dialog with warning text
- Require typing room name to confirm (optional safety measure)
- Explain that deletion is irreversible
- Show what will be deleted (messages, files, reports)
#### Scenario: Execute permanent deletion
- **WHEN** an admin confirms permanent deletion
- **THEN** the system SHALL:
- Send DELETE request to `/api/rooms/{room_id}/permanent`
- Show loading state during deletion
- Navigate to room list on success
- Show success toast message
- Show error message on failure
#### Scenario: Handle active users in deleted room
- **WHEN** a room is permanently deleted while other users are viewing it
- **THEN** the system SHALL:
- Receive WebSocket disconnect event
- Display "Room has been deleted" message
- Navigate affected users to room list

View File

@@ -0,0 +1,132 @@
# mobile-layout Specification
## Purpose
Provide responsive layout capabilities that detect user devices and adapt the UI for optimal mobile experience. This extends the existing "Responsive Layout and Navigation" requirement in frontend-core to include mobile devices (<768px).
## MODIFIED Requirements
### Requirement: Responsive Layout and Navigation
The frontend SHALL provide a responsive layout that works on desktop, tablet, and **mobile** devices with intuitive navigation. The system SHALL detect the device type and switch layouts accordingly.
#### Scenario: Mobile layout (<768px)
- **WHEN** viewed on mobile devices (<768px width)
- **THEN** the system SHALL:
- Display a simplified header with hamburger menu
- Show sidebars as full-screen slide-in panels (not inline)
- Display a bottom toolbar with frequently used actions
- Use single-column layout for content
- Ensure all touch targets are at least 44x44 pixels
#### Scenario: Tablet layout (768px-1024px)
- **WHEN** viewed on tablet (768px-1024px)
- **THEN** the system SHALL:
- Collapse sidebars to icons or overlay panels
- Use full width for content areas
- Stack panels vertically when needed
#### Scenario: Desktop layout (>1024px)
- **WHEN** viewed on desktop (>1024px)
- **THEN** the system SHALL:
- Display full navigation and sidebars inline
- Show room list and detail side-by-side when applicable
- Display member/file panels as sidebars
## ADDED Requirements
### Requirement: Device Detection
The frontend SHALL provide hooks for detecting device type based on viewport width.
#### Scenario: Detect mobile device
- **WHEN** the viewport width is less than 768px
- **THEN** `useIsMobile()` hook SHALL return `true`
- **AND** the UI SHALL render mobile-optimized components
#### Scenario: Detect tablet device
- **WHEN** the viewport width is between 768px and 1023px
- **THEN** `useIsTablet()` hook SHALL return `true`
#### Scenario: Detect desktop device
- **WHEN** the viewport width is 1024px or greater
- **THEN** `useIsDesktop()` hook SHALL return `true`
#### Scenario: Handle viewport resize
- **WHEN** the user resizes the browser window across breakpoints
- **THEN** the hooks SHALL update their return values
- **AND** the UI SHALL transition smoothly to the appropriate layout
### Requirement: Mobile Navigation
The frontend SHALL provide mobile-optimized navigation patterns for small screens.
#### Scenario: Display mobile header
- **WHEN** on mobile layout in room detail view
- **THEN** the system SHALL:
- Show room title (truncated if necessary)
- Show connection status indicator
- Show hamburger menu button
- Hide secondary action buttons (move to menu)
#### Scenario: Open mobile action menu
- **WHEN** user taps the hamburger menu on mobile
- **THEN** the system SHALL:
- Display an action drawer/sheet from bottom or side
- Show all room actions: Generate Report, Change Status, etc.
- Allow closing by tapping outside or swipe gesture
#### Scenario: Display bottom toolbar
- **WHEN** on mobile layout in room detail view
- **THEN** the system SHALL:
- Show a fixed bottom toolbar above the message input
- Include buttons for: Files, Members
- Use icons with labels for clarity
- Ensure toolbar doesn't overlap with device safe areas
### Requirement: Mobile Sidebars
The frontend SHALL display sidebars as slide-in panels on mobile devices.
#### Scenario: Open members panel on mobile
- **WHEN** user taps the Members button on mobile
- **THEN** the system SHALL:
- Slide in a full-screen panel from the right
- Display dark overlay behind the panel
- Show member list with larger touch targets
- Include a close button at the top of the panel
#### Scenario: Close sidebar panel
- **WHEN** user taps the close button or backdrop overlay
- **THEN** the system SHALL:
- Slide the panel out to the right
- Remove the dark overlay
- Return focus to the main content
#### Scenario: Open files panel on mobile
- **WHEN** user taps the Files button on mobile
- **THEN** the system SHALL:
- Slide in a full-screen panel from the right
- Display file list with larger thumbnails
- Show upload area with larger drop zone
- Include a close button at the top
### Requirement: Touch-Friendly Interactions
The frontend SHALL ensure all interactive elements are usable on touch devices.
#### Scenario: Minimum touch target size
- **WHEN** displaying buttons, links, or interactive elements on mobile
- **THEN** the system SHALL:
- Ensure minimum touch target of 44x44 pixels
- Provide adequate spacing between touch targets
- Use padding to expand touch areas without changing visual size
#### Scenario: Mobile message input
- **WHEN** user focuses the message input on mobile
- **THEN** the system SHALL:
- Expand input area for easier typing
- Keep send button easily accessible
- Handle soft keyboard appearance gracefully
- Not obscure the input behind the keyboard
#### Scenario: Mobile form inputs
- **WHEN** displaying form inputs on mobile (login, add member, etc.)
- **THEN** the system SHALL:
- Use larger input fields (minimum height 44px)
- Show appropriate mobile keyboard type (email, text, etc.)
- Support autocomplete where appropriate