feat(m12): meetings + schedule conflict detection, tests, e2e

- MeetingRepository (CRUD, soft-delete, members, findMeetingsByUserInRange
  overlap) + CalendarRepository.findByCreatorInRange + TodoRepository.
  findHighPriorityByAssignee
- MeetingService (createMeeting tx+members, meeting_invited notify,
  meeting_created activity, SSE meeting.created; updateMeeting/updateMinutes/
  deleteMeeting; checkScheduleConflicts = other meetings overlap + calendar
  events overlap + high-priority todos due +-3d, time-overlap logic,
  excludeMeetingId; conflicts are warnings)
- APIs: meetings list/create/edit + /check conflict check
- Screens: meetings page + MeetingForm(member checkboxes, conflict display)
  + ConflictWarning, ProjectNav link
- Unit tests (MeetingRepository, MeetingService incl. conflict algorithm)
  + e2e meetings
This commit is contained in:
Ken Yasue
2026-06-25 02:19:25 +02:00
parent 09e1e5e22a
commit 29e4bc6650
14 changed files with 1371 additions and 0 deletions

View File

@ -65,6 +65,23 @@ export class CalendarRepository {
return rows.map(mapEvent);
}
/** 指定ユーザーが作成したイベントのうち [from,to] と時間重複するもの(スケジュール重複判定用) */
findByCreatorInRange(
userId: number,
from: string,
to: string
): CalendarEvent[] {
const rows = this.db.query<CalendarEventRow>(
`SELECT * FROM calendar_events
WHERE created_by_id = @userId AND deleted_at IS NULL
AND end_at IS NOT NULL
AND start_at <= @to AND end_at >= @from
ORDER BY start_at ASC`,
{ userId, from, to }
);
return rows.map(mapEvent);
}
findEventById(id: number): CalendarEvent | null {
const row = this.db.get<CalendarEventRow>(
'SELECT * FROM calendar_events WHERE id = @id AND deleted_at IS NULL',