feat: implement 8 OpenSpec proposals for security, reliability, and UX improvements

## Security Enhancements (P0)
- Add input validation with max_length and numeric range constraints
- Implement WebSocket token authentication via first message
- Add path traversal prevention in file storage service

## Permission Enhancements (P0)
- Add project member management for cross-department access
- Implement is_department_manager flag for workload visibility

## Cycle Detection (P0)
- Add DFS-based cycle detection for task dependencies
- Add formula field circular reference detection
- Display user-friendly cycle path visualization

## Concurrency & Reliability (P1)
- Implement optimistic locking with version field (409 Conflict on mismatch)
- Add trigger retry mechanism with exponential backoff (1s, 2s, 4s)
- Implement cascade restore for soft-deleted tasks

## Rate Limiting (P1)
- Add tiered rate limits: standard (60/min), sensitive (20/min), heavy (5/min)
- Apply rate limits to tasks, reports, attachments, and comments

## Frontend Improvements (P1)
- Add responsive sidebar with hamburger menu for mobile
- Improve touch-friendly UI with proper tap target sizes
- Complete i18n translations for all components

## Backend Reliability (P2)
- Configure database connection pool (size=10, overflow=20)
- Add Redis fallback mechanism with message queue
- Add blocker check before task deletion

## API Enhancements (P3)
- Add standardized response wrapper utility
- Add /health/ready and /health/live endpoints
- Implement project templates with status/field copying

## Tests Added
- test_input_validation.py - Schema and path traversal tests
- test_concurrency_reliability.py - Optimistic locking and retry tests
- test_backend_reliability.py - Connection pool and Redis tests
- test_api_enhancements.py - Health check and template tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beabigegg
2026-01-10 22:13:43 +08:00
parent 96210c7ad4
commit 3bdc6ff1c9
106 changed files with 9704 additions and 429 deletions

View File

@@ -41,22 +41,34 @@ def check_workload_access(
"""
Check if current user has access to view workload data.
Access rules:
- System admin: can access all workloads
- Department manager: can access workloads of users in their department
- Regular user: can only access their own workload
Raises HTTPException if access is denied.
"""
# System admin can access all
if current_user.is_system_admin:
return
# If querying specific user, must be self
# (Phase 1: only self access for non-admin users)
# If querying specific user
if target_user_id and target_user_id != current_user.id:
# Department manager can view subordinates' workload
if current_user.is_department_manager:
# Manager can view users in their department
# target_user_department_id must be provided for this check
if target_user_department_id and target_user_department_id == current_user.department_id:
return
# Access denied for non-manager or user not in same department
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied: Cannot view other users' workload",
)
# If querying by department, must be same department
# If querying by department
if department_id and department_id != current_user.department_id:
# Department manager can only query their own department
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied: Cannot view other departments' workload",
@@ -66,15 +78,40 @@ def check_workload_access(
def filter_accessible_users(
current_user: User,
user_ids: Optional[List[str]] = None,
db: Optional[Session] = None,
) -> Optional[List[str]]:
"""
Filter user IDs to only those accessible by current user.
Returns None if user can access all (system admin).
Access rules:
- System admin: can see all users
- Department manager: can see all users in their department
- Regular user: can only see themselves
"""
# System admin can access all
if current_user.is_system_admin:
return user_ids
# Department manager can see all users in their department
if current_user.is_department_manager and current_user.department_id and db:
# Get all users in the same department
department_users = db.query(User.id).filter(
User.department_id == current_user.department_id,
User.is_active == True
).all()
department_user_ids = {u.id for u in department_users}
if user_ids:
# Filter to only users in manager's department
accessible = [uid for uid in user_ids if uid in department_user_ids]
if not accessible:
return [current_user.id]
return accessible
else:
# No filter specified, return all department users
return list(department_user_ids)
# Regular user can only see themselves
if user_ids:
# Filter to only accessible users
@@ -111,6 +148,11 @@ async def get_heatmap(
"""
Get workload heatmap for users.
Access Rules:
- System admin: Can view all users' workload
- Department manager: Can view workload of all users in their department
- Regular user: Can only view their own workload
Returns workload summaries for users showing:
- allocated_hours: Total estimated hours from tasks due this week
- capacity_hours: User's weekly capacity
@@ -126,8 +168,8 @@ async def get_heatmap(
if department_id:
check_workload_access(current_user, department_id=department_id)
# Filter user_ids based on access
accessible_user_ids = filter_accessible_users(current_user, parsed_user_ids)
# Filter user_ids based on access (pass db for manager department lookup)
accessible_user_ids = filter_accessible_users(current_user, parsed_user_ids, db)
# Normalize week_start
if week_start is None:
@@ -181,12 +223,25 @@ async def get_user_workload(
"""
Get detailed workload for a specific user.
Access rules:
- System admin: can view any user's workload
- Department manager: can view workload of users in their department
- Regular user: can only view their own workload
Returns:
- Workload summary (same as heatmap)
- List of tasks contributing to the workload
"""
# Check access
check_workload_access(current_user, target_user_id=user_id)
# Get target user's department for manager access check
target_user = db.query(User).filter(User.id == user_id).first()
target_user_department_id = target_user.department_id if target_user else None
# Check access (pass target user's department for manager check)
check_workload_access(
current_user,
target_user_id=user_id,
target_user_department_id=target_user_department_id
)
# Calculate workload detail
detail = get_user_workload_detail(db, user_id, week_start)