Skip to content

feat(api): 가능 시간 관리 API 구현 - #94

Merged
meteorqz6 merged 9 commits into
developfrom
feature/92-availability-api
Jun 26, 2026
Merged

feat(api): 가능 시간 관리 API 구현#94
meteorqz6 merged 9 commits into
developfrom
feature/92-availability-api

Conversation

@ehlung

@ehlung ehlung commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

개요

가능 시간 관리와 active schedule planning period API를 구현합니다.


Closes #92

변경 사항

  • active schedule planning period 조회/저장/삭제 API 추가
  • 가능 시간 조회 및 bulk 전체 교체 저장 API 추가
  • 조직/worker 범위 접근 제한과 운영시간/휴무일/30분 단위 검증 추가
  • OpenAPI 문서 갱신
  • API 테스트와 fake Prisma 보강

변경 유형

  • feat — 새로운 기능
  • fix — 버그 수정
  • refactor — 리팩터링 (기능 변경 없음)
  • test — 테스트 코드
  • perf — 성능 개선
  • docs — 문서 수정
  • chore — 빌드·설정 변경

영향 범위

  • webapps/web
  • apiapps/api
  • dbpackages/database
  • sharedpackages/shared
  • repo — 루트 설정·CI/CD·문서

테스트 방법

  1. pnpm --filter @fragment/api test
  2. pnpm --filter @fragment/api typecheck
  3. pnpm --filter @fragment/api lint
  4. pnpm --filter @fragment/api build

체크리스트

  • CI (테스트 + 린트) 통과 확인
  • 관련 테스트 코드 작성 또는 업데이트
  • 상태 분류 규칙(서버/전역/로컬/폼 상태) 준수
  • 에러 처리 및 Fallback UI 확인 (해당 시)
  • API 명세 업데이트 (API 변경 시)
  • 공유 타입·스키마(packages/shared) 업데이트 (타입 변경 시)

리뷰 포인트

  • PUT /availability/bulk의 전체 교체 방식과 transaction 처리
  • 조직 운영시간/휴무일/익일 종료 검증 경계
  • shared 30분 단위 datetime 검증 보강

Summary by CodeRabbit

  • New Features
    • 조직의 활성 스케줄 계획 기간을 조회, 생성/수정, 삭제할 수 있게 되었습니다.
    • 근무자별 가용 시간을 조회하고, 지정한 기간의 가용 시간을 일괄 교체할 수 있게 되었습니다.
  • Bug Fixes
    • 시간 입력 검증이 더 엄격해져 정각/30분 기준 위반(초/밀리초 포함 등) 입력은 올바르게 차단됩니다.
    • 쿼리 검증 결과가 반영될 때, 검증되지 않은 값은 남지 않도록 처리됩니다.
  • Documentation
    • 활성 스케줄 계획 기간 및 가용 시간 API 스펙이 OpenAPI 문서에 추가되었습니다.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 24eed81c-f265-4c55-8677-8342b04d71ce

📥 Commits

Reviewing files that changed from the base of the PR and between 3ea4728 and 25d38f0.

📒 Files selected for processing (5)
  • apps/api/src/middlewares/validate.ts
  • apps/api/src/modules/availability/availability.service.spec.ts
  • apps/api/src/modules/availability/availability.service.ts
  • apps/api/test/availability.routes.test.ts
  • packages/shared/src/schemas/common.ts

Walkthrough

조직의 활성 플래닝 기간 조회·업서트·삭제와 근무자 가용 시간 조회·일괄 교체 API가 추가되었습니다. 관련 검증, 테스트 기반, OpenAPI 문서도 함께 갱신되었습니다.

Changes

조직 일정 API

Layer / File(s) Summary
공통 검증
apps/api/src/middlewares/validate.ts, packages/shared/src/schemas/common.ts
validate의 query 반영이 병합 방식으로 바뀌고, 30분 경계 판정이 UTC 초·분수까지 검사하도록 바뀌었다.
테스트 기반 확장
apps/api/tsconfig*.json, apps/api/test/helpers/fake-prisma.ts
tsconfig가 test/build 범위를 확장하고, fake Prisma에 planning period/availability 레코드 타입·복제·초기화와 worker.findFirst가 추가되었다.
활성 플래닝 기간 API
apps/api/src/modules/organization/planning-period.*, apps/api/src/routes/organization.routes.ts, apps/api/test/organization.routes.test.ts
조직 활성 플래닝 기간의 조회·업서트·삭제 서비스, 라우트, 테스트가 추가되었다.
가용 시간 API
apps/api/src/modules/availability/*, apps/api/src/routes/availability.routes.ts, apps/api/src/routes/index.ts, apps/api/test/availability.routes.test.ts
근무자 가용 시간의 조회·일괄 교체 서비스, 라우트, 테스트가 추가되었다.
OpenAPI 계약
docs/openapi.yaml
active schedule planning period와 availability의 경로, 파라미터, 스키마가 추가되었다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 가능 시간 관리 API 구현이라는 핵심 변경을 정확히 요약하고 있어 적절합니다.
Description check ✅ Passed 개요, 변경 사항, 변경 유형, 영향 범위, 테스트 방법, 체크리스트, 리뷰 포인트가 포함되어 템플릿을 대부분 충족합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/92-availability-api

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ehlung ehlung self-assigned this Jun 25, 2026
@ehlung

ehlung commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
apps/api/src/modules/availability/availability.service.ts (1)

22-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prisma 조회 결과 타입을 수동으로 복제하지 마세요.

OrganizationForAvailabilityfindUnique({ include: { businessHours: true } })의 결과 모양을 손으로 다시 적고 있어서, 선택 필드나 relation 타입이 바뀌면 이 서비스 타입이 바로 드리프트합니다. generated payload type으로 붙여 두는 편이 안전합니다.

♻️ 제안
-type OrganizationForAvailability = {
-  id: bigint;
-  businessHours: OrganizationBusinessHour[];
-};
+type OrganizationForAvailability = Prisma.OrganizationGetPayload<{
+  include: { businessHours: true };
+}>;

As per coding guidelines, apps/api/src/**/*.ts: Use Prisma-generated result types for query results and do not redefine those types manually.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/modules/availability/availability.service.ts` around lines 22 -
25, The OrganizationForAvailability type is manually duplicating a Prisma query
result shape and can drift from the actual include payload. Replace the
hand-written type in availability.service.ts with the Prisma-generated payload
type for the findUnique call that includes businessHours, and update any
references in the availability service to use that generated type instead of
redefining id/businessHours manually. Keep the type tied to the relevant Prisma
model/result so changes to selected fields or relations stay in sync
automatically.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/middlewares/validate.ts`:
- Around line 30-32: In validate.ts, the query handling in the validation
middleware currently merges validated data into req.query, which leaves removed
or unvalidated keys behind and breaks the Zod contract. Update the query branch
in the validate middleware so it effectively replaces the existing query
contents while preserving object identity, for example by clearing req.query
before assigning result.data.query back into it. Use the validate request flow
around result.data.query and req.query as the place to make this change, and
keep the same approach consistent with body and params handling if needed.

In `@apps/api/src/modules/availability/availability.service.spec.ts`:
- Around line 308-447: Add a regression test in the availability service spec to
cover the missing startsAt >= endsAt validation. Use replaceAvailability with
createPrismaMock to pass an item whose startsAt is equal to or after endsAt, and
assert it rejects with the same invalid time-range error shape. Keep the new
case alongside the existing validation tests in the availability.service.spec.ts
suite so the behavior is locked in.

In `@apps/api/src/modules/availability/availability.service.ts`:
- Around line 127-135: The availability validation in availability.service.ts
only checks that the range fits within business hours, so reverse or zero-length
intervals can still pass. Update the validation around startsAt, endsAt, openAt,
and closeAt to also reject any item where startsAt is greater than or equal to
endsAt before reaching createMany, and keep using createInvalidTimeRangeError
for the failure case.

In `@apps/api/src/modules/organization/planning-period.service.ts`:
- Around line 29-30: The organization-context guard in
planning-period.service.ts is returning the wrong contract for organization
subresources. Update the check around the organization lookup to follow the same
organization-route behavior used by apps/api/src/routes/organization.routes.ts,
returning NOT_FOUND-style handling instead of HttpError(403,
ERROR_CODES.ORGANIZATION_REQUIRED, ...). Keep the logic aligned with the
existing organization guard and add/adjust a regression test for this route to
verify the expected organization-specific error contract.

In `@apps/api/test/availability.routes.test.ts`:
- Around line 84-250: The availability routes tests are missing
cross-organization access coverage for worker scoping, so add cases that call
get /api/availability and put /api/availability/bulk with a workerId belonging
to a different organization than the authenticated user. Use the existing
createFakePrisma, createApp, and authHeader setup in availability.routes.test.ts
to verify both endpoints reject cross-org worker access with the expected error
response, while keeping the current same-org tests intact.

In `@apps/api/test/organization.routes.test.ts`:
- Around line 209-318: The organization active planning period route tests are
missing a regression case for users without an organization, so add a new test
in organization.routes.test.ts using createApp and the
active-schedule-planning-period endpoint to verify the existing
/api/organization contract still returns 404 NOT_FOUND for a no-organization
authenticated user. Reuse the same route-level patterns already present around
the active planning period tests, and assert the response status/body for the
Organization subresource behavior rather than only the
null/success/validation/delete cases.

In `@packages/shared/src/schemas/common.ts`:
- Around line 33-39: In isDateTimeOnThirtyMinuteBoundary, the boundary check is
using new Date(...) plus getUTCMinutes(), which can reject valid :00/:30 inputs
when the datetime includes an offset. Update the logic to inspect the original
dateTime string’s hour/minute/second values instead of converting to UTC, and
keep the existing zero-seconds/milliseconds requirement when validating the
boundary.

---

Nitpick comments:
In `@apps/api/src/modules/availability/availability.service.ts`:
- Around line 22-25: The OrganizationForAvailability type is manually
duplicating a Prisma query result shape and can drift from the actual include
payload. Replace the hand-written type in availability.service.ts with the
Prisma-generated payload type for the findUnique call that includes
businessHours, and update any references in the availability service to use that
generated type instead of redefining id/businessHours manually. Keep the type
tied to the relevant Prisma model/result so changes to selected fields or
relations stay in sync automatically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3a6eaa96-bb12-4aff-99ce-affeea0da9d6

📥 Commits

Reviewing files that changed from the base of the PR and between 37f063c and 3ea4728.

📒 Files selected for processing (17)
  • apps/api/src/middlewares/validate.ts
  • apps/api/src/modules/availability/availability.handlers.ts
  • apps/api/src/modules/availability/availability.service.spec.ts
  • apps/api/src/modules/availability/availability.service.ts
  • apps/api/src/modules/organization/planning-period.handlers.ts
  • apps/api/src/modules/organization/planning-period.service.spec.ts
  • apps/api/src/modules/organization/planning-period.service.ts
  • apps/api/src/routes/availability.routes.ts
  • apps/api/src/routes/index.ts
  • apps/api/src/routes/organization.routes.ts
  • apps/api/test/availability.routes.test.ts
  • apps/api/test/helpers/fake-prisma.ts
  • apps/api/test/organization.routes.test.ts
  • apps/api/tsconfig.build.json
  • apps/api/tsconfig.json
  • docs/openapi.yaml
  • packages/shared/src/schemas/common.ts

Comment thread apps/api/src/middlewares/validate.ts
Comment thread apps/api/src/modules/availability/availability.service.spec.ts
Comment thread apps/api/src/modules/availability/availability.service.ts
Comment thread apps/api/src/modules/organization/planning-period.service.ts
Comment thread apps/api/test/availability.routes.test.ts
Comment thread apps/api/test/organization.routes.test.ts
Comment thread packages/shared/src/schemas/common.ts Outdated
@ehlung

ehlung commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

CodeRabbit 리뷰 반영/미반영 정리입니다.

반영했습니다:

  • validate.ts query 처리: 검증 후 기존 query key를 비우고 검증된 query만 남기도록 수정했습니다.
  • availability.service.ts 시간 범위 검증: startsAt >= endsAtINVALID_TIME_RANGE로 차단하도록 service 방어 로직을 추가했습니다.
  • availability.service.spec.ts: 빈/역전 시간 범위 회귀 테스트를 추가했습니다.
  • packages/shared 30분 단위 검증: offset datetime을 UTC 변환값이 아니라 원본 문자열의 분/초/fraction 기준으로 검증하도록 수정했습니다.
  • OrganizationForAvailability 타입: 수동 타입 대신 Prisma generated payload type을 사용하도록 변경했습니다.

반영하지 않았습니다:

  • planning period 조직 없음 응답을 404로 바꾸는 제안: 기존 workers/staffing-rules 등 조직 하위 기능 정책이 403 ORGANIZATION_REQUIRED라서 유지했습니다.
  • availability route cross-org worker 테스트 추가: 동일 보안 규칙은 service spec에서 listAvailability, replaceAvailability 양쪽으로 이미 검증하고 있어 route 중복 테스트는 추가하지 않았습니다.
  • organization route no-organization 테스트 추가: service spec에서 조직 없음 케이스를 검증하고 있어 route 중복 테스트는 추가하지 않았습니다.
  • docstring coverage 경고와 CodeRabbit ESLint install 실패는 프로젝트 코드 수정 대상이 아니어서 반영하지 않았습니다.

반영 커밋: 25d38f0 fix(api): 가능 시간 검증 보강

@ehlung
ehlung requested a review from meteorqz6 June 26, 2026 05:27
@meteorqz6
meteorqz6 merged commit a483555 into develop Jun 26, 2026
2 checks passed
@meteorqz6
meteorqz6 deleted the feature/92-availability-api branch June 26, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(api): 가능 시간 관리 API 구현

2 participants