From cd55eed48519705b261156781e68db9dca38108c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Feb 2026 16:07:49 +0000 Subject: [PATCH] refactor: Remove meeting from SlotKind/WorkType type definitions (Issue #267) Remove the unused "meeting" value from type definitions across the codebase: Backend changes: - Remove MEETING from TaskCategory enum - Remove meeting from TimeSlotSchema description Frontend changes: - Remove meeting from SlotKind type and related labels/colors - Remove meeting from TimeSlot.kind type - Remove meeting from getCategoryColor functions - Update fallback from meeting to light_work in schedule.ts Test changes: - Update tests to use ADMIN/REVIEW instead of MEETING category This consolidates the work type definitions and removes the meeting option since meetings are not included in the project workflow. https://claude.ai/code/session_01Cghpa5Bg6ZNPhwzmL4xS9G --- apps/api/src/humancompiler_api/models.py | 5 +-- apps/api/tests/test_weekly_recurring_tasks.py | 40 +++++++++---------- apps/web/src/app/ai-planning/page.tsx | 1 - apps/web/src/app/weekly-tasks/page.tsx | 3 +- apps/web/src/constants/schedule.ts | 12 +++--- apps/web/src/types/ai-planning.ts | 2 +- 6 files changed, 29 insertions(+), 34 deletions(-) diff --git a/apps/api/src/humancompiler_api/models.py b/apps/api/src/humancompiler_api/models.py index b1f7cffb..77680605 100644 --- a/apps/api/src/humancompiler_api/models.py +++ b/apps/api/src/humancompiler_api/models.py @@ -48,7 +48,6 @@ class GoalStatus(str, Enum): class TaskCategory(str, Enum): """Weekly recurring task category enum""" - MEETING = "meeting" STUDY = "study" EXERCISE = "exercise" HOBBY = "hobby" @@ -1894,9 +1893,7 @@ class TimeSlotSchema(BaseModel): start: str = Field(..., pattern=r"^\d{2}:\d{2}$", description="Start time (HH:mm)") end: str = Field(..., pattern=r"^\d{2}:\d{2}$", description="End time (HH:mm)") - kind: str = Field( - ..., description="Slot kind (study, focused_work, light_work, meeting)" - ) + kind: str = Field(..., description="Slot kind (study, focused_work, light_work)") capacity_hours: float | None = Field( None, ge=0, description="Slot capacity in hours" ) diff --git a/apps/api/tests/test_weekly_recurring_tasks.py b/apps/api/tests/test_weekly_recurring_tasks.py index 61473551..3ad55df3 100644 --- a/apps/api/tests/test_weekly_recurring_tasks.py +++ b/apps/api/tests/test_weekly_recurring_tasks.py @@ -49,10 +49,10 @@ def test_user(test_session): def sample_weekly_recurring_task_data(): """Sample weekly recurring task data for testing.""" return { - "title": "週次振り返り会議", - "description": "チームの週次振り返り会議", + "title": "週次レビュー", + "description": "チームの週次レビュー", "estimate_hours": 2.0, - "category": TaskCategory.MEETING, + "category": TaskCategory.REVIEW, "is_active": True, } @@ -67,10 +67,10 @@ def test_create_weekly_recurring_task( test_session, task_data, test_user.id ) - assert task.title == "週次振り返り会議" - assert task.description == "チームの週次振り返り会議" + assert task.title == "週次レビュー" + assert task.description == "チームの週次レビュー" assert task.estimate_hours == Decimal("2.0") - assert task.category == TaskCategory.MEETING + assert task.category == TaskCategory.REVIEW assert task.is_active is True assert task.user_id == test_user.id assert task.id is not None @@ -111,12 +111,12 @@ def test_get_weekly_recurring_tasks( def test_get_weekly_recurring_tasks_with_filters(test_session: Session, test_user): """Test getting weekly recurring tasks with filters.""" # Create tasks with different categories and statuses - active_meeting_task = weekly_recurring_task_service.create_weekly_recurring_task( + active_admin_task = weekly_recurring_task_service.create_weekly_recurring_task( test_session, WeeklyRecurringTaskCreate( - title="週次会議", + title="事務作業", estimate_hours=1.5, - category=TaskCategory.MEETING, + category=TaskCategory.ADMIN, is_active=True, ), test_user.id, @@ -134,11 +134,11 @@ def test_get_weekly_recurring_tasks_with_filters(test_session: Session, test_use ) # Filter by category - meeting_tasks = weekly_recurring_task_service.get_weekly_recurring_tasks( - test_session, test_user.id, category=TaskCategory.MEETING + admin_tasks = weekly_recurring_task_service.get_weekly_recurring_tasks( + test_session, test_user.id, category=TaskCategory.ADMIN ) - assert len(meeting_tasks) >= 1 - assert all(task.category == TaskCategory.MEETING for task in meeting_tasks) + assert len(admin_tasks) >= 1 + assert all(task.category == TaskCategory.ADMIN for task in admin_tasks) # Filter by active status active_tasks = weekly_recurring_task_service.get_weekly_recurring_tasks( @@ -311,10 +311,10 @@ def test_weekly_recurring_task_filter_by_category( """Test filtering weekly recurring tasks by category.""" # Create tasks with different categories - meeting_task = { - "title": "会議", + admin_task = { + "title": "事務作業", "estimate_hours": 1.0, - "category": TaskCategory.MEETING, + "category": TaskCategory.ADMIN, "is_active": True, } @@ -327,7 +327,7 @@ def test_weekly_recurring_task_filter_by_category( # Create both tasks response = client.post( - "/api/weekly-recurring-tasks/", json=meeting_task, headers=auth_headers + "/api/weekly-recurring-tasks/", json=admin_task, headers=auth_headers ) assert response.status_code == 201 @@ -336,15 +336,15 @@ def test_weekly_recurring_task_filter_by_category( ) assert response.status_code == 201 - # Filter by meeting category + # Filter by admin category response = client.get( - "/api/weekly-recurring-tasks/?category=meeting", headers=auth_headers + "/api/weekly-recurring-tasks/?category=admin", headers=auth_headers ) assert response.status_code == 200 tasks = response.json() assert len(tasks) >= 1 - assert all(task["category"] == TaskCategory.MEETING for task in tasks) + assert all(task["category"] == TaskCategory.ADMIN for task in tasks) # Filter by study category response = client.get( diff --git a/apps/web/src/app/ai-planning/page.tsx b/apps/web/src/app/ai-planning/page.tsx index 03db56ff..99b7e7ee 100644 --- a/apps/web/src/app/ai-planning/page.tsx +++ b/apps/web/src/app/ai-planning/page.tsx @@ -391,7 +391,6 @@ export default function AIPlanningPage() { const getCategoryColor = (category: string) => { const colors: Record = { - meeting: 'bg-blue-100 text-blue-800', study: 'bg-green-100 text-green-800', exercise: 'bg-orange-100 text-orange-800', hobby: 'bg-purple-100 text-purple-800', diff --git a/apps/web/src/app/weekly-tasks/page.tsx b/apps/web/src/app/weekly-tasks/page.tsx index 8fe95b9a..67946822 100644 --- a/apps/web/src/app/weekly-tasks/page.tsx +++ b/apps/web/src/app/weekly-tasks/page.tsx @@ -80,11 +80,12 @@ export default function WeeklyTasksPage() { const getCategoryColor = (category: string) => { const colors: Record = { - meeting: "bg-blue-100 text-blue-800", study: "bg-green-100 text-green-800", exercise: "bg-orange-100 text-orange-800", hobby: "bg-purple-100 text-purple-800", admin: "bg-gray-100 text-gray-800", + maintenance: "bg-indigo-100 text-indigo-800", + review: "bg-pink-100 text-pink-800", } return colors[category] || "bg-gray-100 text-gray-800" } diff --git a/apps/web/src/constants/schedule.ts b/apps/web/src/constants/schedule.ts index b2bbde34..d20e7056 100644 --- a/apps/web/src/constants/schedule.ts +++ b/apps/web/src/constants/schedule.ts @@ -4,20 +4,18 @@ import { logger } from '@/lib/logger' -export type SlotKind = 'study' | 'focused_work' | 'light_work' | 'meeting'; +export type SlotKind = 'study' | 'focused_work' | 'light_work'; export const slotKindLabels: Record = { study: '学習', focused_work: '集中作業', light_work: '軽作業', - meeting: '会議', } as const; export const slotKindColors: Record = { study: 'bg-blue-100 text-blue-800', focused_work: 'bg-purple-100 text-purple-800', light_work: 'bg-green-100 text-green-800', - meeting: 'bg-orange-100 text-orange-800', } as const; /** @@ -29,8 +27,8 @@ export const getSlotKindLabel = (slotKind: string): string => { const typedSlotKind = slotKind as SlotKind; if (!(slotKind in slotKindLabels)) { - logger.warn('Unknown slot kind, using fallback to meeting', { slotKind }, { component: 'schedule' }); - return slotKindLabels.meeting; + logger.warn('Unknown slot kind, using fallback to light_work', { slotKind }, { component: 'schedule' }); + return slotKindLabels.light_work; } return slotKindLabels[typedSlotKind]; @@ -45,8 +43,8 @@ export const getSlotKindColor = (slotKind: string): string => { const typedSlotKind = slotKind as SlotKind; if (!(slotKind in slotKindColors)) { - logger.warn('Unknown slot kind, using fallback to meeting', { slotKind }, { component: 'schedule' }); - return slotKindColors.meeting; + logger.warn('Unknown slot kind, using fallback to light_work', { slotKind }, { component: 'schedule' }); + return slotKindColors.light_work; } return slotKindColors[typedSlotKind]; diff --git a/apps/web/src/types/ai-planning.ts b/apps/web/src/types/ai-planning.ts index 923f2af1..c0352a79 100644 --- a/apps/web/src/types/ai-planning.ts +++ b/apps/web/src/types/ai-planning.ts @@ -187,7 +187,7 @@ export interface TimeSlot { /** 終了時刻 (HH:mm形式) */ end: string; /** スロット種別(作業タイプ) */ - kind: 'study' | 'focused_work' | 'light_work' | 'meeting'; + kind: 'study' | 'focused_work' | 'light_work'; /** スロットのキャパシティ(時間単位) */ capacity_hours?: number; /** 割り当てプロジェクトID(スロット単位での割り当て) */