Files
PROJECT-CONTORL/backend/app/models/notification.py
beabigegg 9b220523ff feat: complete issue fixes and implement remaining features
## Critical Issues (CRIT-001~003) - All Fixed
- JWT secret key validation with pydantic field_validator
- Login audit logging for success/failure attempts
- Frontend API path prefix removal

## High Priority Issues (HIGH-001~008) - All Fixed
- Project soft delete using is_active flag
- Redis session token bytes handling
- Rate limiting with slowapi (5 req/min for login)
- Attachment API permission checks
- Kanban view with drag-and-drop
- Workload heatmap UI (WorkloadPage, WorkloadHeatmap)
- TaskDetailModal integrating Comments/Attachments
- UserSelect component for task assignment

## Medium Priority Issues (MED-001~012) - All Fixed
- MED-001~005: DB commits, N+1 queries, datetime, error format, blocker flag
- MED-006: Project health dashboard (HealthService, ProjectHealthPage)
- MED-007: Capacity update API (PUT /api/users/{id}/capacity)
- MED-008: Schedule triggers (cron parsing, deadline reminders)
- MED-009: Watermark feature (image/PDF watermarking)
- MED-010~012: useEffect deps, DOM operations, PDF export

## New Files
- backend/app/api/health/ - Project health API
- backend/app/services/health_service.py
- backend/app/services/trigger_scheduler.py
- backend/app/services/watermark_service.py
- backend/app/core/rate_limiter.py
- frontend/src/pages/ProjectHealthPage.tsx
- frontend/src/components/ProjectHealthCard.tsx
- frontend/src/components/KanbanBoard.tsx
- frontend/src/components/WorkloadHeatmap.tsx

## Tests
- 113 new tests passing (health: 32, users: 14, triggers: 35, watermark: 32)

## OpenSpec Archives
- add-project-health-dashboard
- add-capacity-update-api
- add-schedule-triggers
- add-watermark-feature
- add-rate-limiting
- enhance-frontend-ux
- add-resource-management-ui

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 21:49:52 +08:00

41 lines
1.5 KiB
Python

import uuid
from sqlalchemy import Column, String, Text, Boolean, DateTime, ForeignKey, Enum
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from app.core.database import Base
import enum
class NotificationType(str, enum.Enum):
MENTION = "mention"
ASSIGNMENT = "assignment"
BLOCKER = "blocker"
STATUS_CHANGE = "status_change"
COMMENT = "comment"
BLOCKER_RESOLVED = "blocker_resolved"
DEADLINE_REMINDER = "deadline_reminder"
SCHEDULED_TRIGGER = "scheduled_trigger"
class Notification(Base):
__tablename__ = "pjctrl_notifications"
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
user_id = Column(String(36), ForeignKey("pjctrl_users.id", ondelete="CASCADE"), nullable=False)
type = Column(
Enum("mention", "assignment", "blocker", "status_change", "comment", "blocker_resolved",
"deadline_reminder", "scheduled_trigger",
name="notification_type_enum"),
nullable=False
)
reference_type = Column(String(50), nullable=False)
reference_id = Column(String(36), nullable=False)
title = Column(String(200), nullable=False)
message = Column(Text, nullable=True)
is_read = Column(Boolean, default=False, nullable=False)
created_at = Column(DateTime, server_default=func.now(), nullable=False)
read_at = Column(DateTime, nullable=True)
# Relationships
user = relationship("User", back_populates="notifications")