Skip to content

feat(api): 근무자 API 구현 - #83

Merged
meteorqz6 merged 17 commits into
developfrom
feature/77-workers-api
Jun 25, 2026
Merged

feat(api): 근무자 API 구현#83
meteorqz6 merged 17 commits into
developfrom
feature/77-workers-api

Conversation

@meteorqz6

@meteorqz6 meteorqz6 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

개요

근무자 관리 API를 추가합니다.

Closes #77


변경 사항

  • /workers 목록/생성/수정/삭제 API를 추가했습니다.
  • 근무자 사번을 조직별 lastWorkerSequence 기반의 W-0001 형식으로 자동 생성합니다.
  • 인증/조직 필수 처리, 조직 범위 제한, 타 조직 worker 접근 시 404 WORKER_NOT_FOUND 처리를 적용했습니다.
  • 삭제 시 근무자는 hard delete 하고 과거 스케줄 배정의 worker_id는 null 처리되도록 검증했습니다.
  • shared schema, API 문서, OpenAPI 명세, seed 사번 포맷을 갱신했습니다.
  • CodeRabbit 리뷰 반영으로 fake Prisma ID sequence, seed 멱등성, OpenAPI employeeCode pattern을 보강했습니다.

변경 유형

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

영향 범위

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

테스트 방법

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

체크리스트

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

리뷰 포인트

  • W-0001 사번 생성 방식과 조직별 sequence 갱신 흐름
  • 타 조직 worker 접근을 404 WORKER_NOT_FOUND로 처리하는 범위 제한
  • seed legacy 사번(W001 계열) 정규화 방식

Summary by CodeRabbit

  • New Features
    • 근무자(Workers) 목록 조회, 생성, 수정, 삭제 API가 추가되었습니다.
    • 근무자 사번은 서버에서 자동 생성되며 조직 단위로 관리됩니다.
  • Bug Fixes
    • 조직 정보가 없는 요청은 거부되며, 잘못된 근무자 ID/존재하지 않는 근무자는 적절한 오류로 처리됩니다.
    • 근무자 삭제 시 연결된 스케줄 할당은 유지(해당 근무자만 해제)됩니다.
  • Documentation
    • 근무자 관련 API 문서(엔드포인트, 스키마, 에러 응답)가 추가 및 보강되었습니다.
  • Tests
    • 근무자 라우트 동작을 검증하는 통합 테스트가 추가되었습니다.

@meteorqz6 meteorqz6 self-assigned this Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@meteorqz6, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 39 minutes and 3 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 53dc8411-e1a7-4d54-ae6f-7d11d948c6e9

📥 Commits

Reviewing files that changed from the base of the PR and between 91c5131 and 4f389dd.

📒 Files selected for processing (3)
  • apps/api/src/modules/workers/workers.service.spec.ts
  • apps/api/test/helpers/fake-prisma.ts
  • apps/api/test/workers.routes.test.ts

Walkthrough

워커 CRUD API가 /workers로 추가됐고, 조직 범위 검증과 W-000x 사번 생성, 수정/삭제 처리, 관련 OpenAPI/문서, 테스트 더블, 라우트 통합 테스트, 시드 정리가 함께 갱신됐다.

Changes

워커 API 표면과 지원 코드

Layer / File(s) Summary
공개 계약과 라우팅 연결
packages/shared/src/schemas/workers.ts, apps/api/src/routes/workers.routes.ts, apps/api/src/routes/index.ts, docs/openapi.yaml, docs/API.md
workerId 파라미터 스키마와 /workers 라우터, 검증 미들웨어, OpenAPI 계약, API 문서, 라우트 마운트가 추가됐다.
핸들러 브리지
apps/api/src/modules/workers/workers.handlers.ts
조직 ID와 workerId를 추출해 서비스로 전달하고, 목록/생성/수정/삭제 응답 상태를 각각 200/201/200/204로 반환한다.
근로자 CRUD 서비스
apps/api/src/modules/workers/workers.service.ts
조직 스코프 조회, employeeCode 정렬, lastWorkerSequence 기반 코드 생성, 선택적 수정, 삭제 시 404 처리가 Prisma 트랜잭션으로 구현됐다.
테스트 더블과 라우트 검증
apps/api/test/helpers/fake-prisma.ts, apps/api/test/workers.routes.test.ts
Fake Prisma가 워커와 스케줄 할당 상태를 다루도록 확장되고, /api/workers 통합 테스트가 인증, 조직 범위, 정렬, 생성, 수정, 삭제 동작을 검증한다.
시드 워커 코드 정리
packages/database/prisma/seed.ts
레거시 사번을 새 W-000x 형식으로 정리한 뒤 시드 upsert가 새 형식을 사용하도록 변경됐다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning fake Prisma의 minimumStaffingRule CRUD 정리는 workers 이슈와 직접 관련 없는 추가 변경입니다. workers 관련 fake Prisma 수정만 유지하고, minimumStaffingRule 정리는 별도 PR로 분리하세요.
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 (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 근무자 API 구현이라는 핵심 변경을 간결하게 요약합니다.
Description check ✅ Passed 개요, 변경 사항, 테스트, 체크리스트, 리뷰 포인트가 포함되어 템플릿을 대부분 충족합니다.
Linked Issues check ✅ Passed 인증/조직 범위, CRUD 엔드포인트, 스키마, 테스트, 문서, 시드까지 이슈 #77의 요구를 반영했습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/77-workers-api

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.

@meteorqz6 meteorqz6 mentioned this pull request Jun 25, 2026
35 tasks

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/database/prisma/seed.ts (1)

104-125: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

기존 시드 DB에서 워커가 중복 생성됩니다.

Line 111의 upsert 키가 organizationId_employeeCode인데, 이번에 employeeCode 포맷을 바꾸면서 예전에 W001/W002/W003로 시드된 행을 더 이상 매칭하지 못합니다. 그 상태로 시드를 다시 돌리면 기존 워커는 남고 W-0001~0003가 새로 추가되어 멱등성이 깨집니다. legacy 코드를 먼저 정규화하거나 정리한 뒤 새 포맷으로 upsert해야 합니다. As per path instructions, "upsert 사용으로 멱등성 보장 여부 확인"이 필요합니다.

수정 예시
-  await Promise.all(
-    [
-      { employeeCode: "W-0001", name: "김민지", weeklyContractHours: 20 },
-      { employeeCode: "W-0002", name: "박준호", weeklyContractHours: 24 },
-      { employeeCode: "W-0003", name: "이서연", weeklyContractHours: 16 },
-    ].map((worker) =>
-      prisma.worker.upsert({
-        where: {
-          organizationId_employeeCode: {
-            organizationId: organization.id,
-            employeeCode: worker.employeeCode,
-          },
-        },
-        update: {
-          name: worker.name,
-          weeklyContractHours: worker.weeklyContractHours,
-        },
-        create: {
-          organizationId: organization.id,
-          employeeCode: worker.employeeCode,
-          name: worker.name,
-          weeklyContractHours: worker.weeklyContractHours,
-        },
-      }),
-    ),
-  );
+  await Promise.all(
+    [
+      {
+        legacyEmployeeCode: "W001",
+        employeeCode: "W-0001",
+        name: "김민지",
+        weeklyContractHours: 20,
+      },
+      {
+        legacyEmployeeCode: "W002",
+        employeeCode: "W-0002",
+        name: "박준호",
+        weeklyContractHours: 24,
+      },
+      {
+        legacyEmployeeCode: "W003",
+        employeeCode: "W-0003",
+        name: "이서연",
+        weeklyContractHours: 16,
+      },
+    ].map(async (worker) => {
+      await prisma.worker.updateMany({
+        where: {
+          organizationId: organization.id,
+          employeeCode: worker.legacyEmployeeCode,
+        },
+        data: {
+          employeeCode: worker.employeeCode,
+        },
+      });
+
+      return prisma.worker.upsert({
+        where: {
+          organizationId_employeeCode: {
+            organizationId: organization.id,
+            employeeCode: worker.employeeCode,
+          },
+        },
+        update: {
+          name: worker.name,
+          weeklyContractHours: worker.weeklyContractHours,
+        },
+        create: {
+          organizationId: organization.id,
+          employeeCode: worker.employeeCode,
+          name: worker.name,
+          weeklyContractHours: worker.weeklyContractHours,
+        },
+      });
+    }),
+  );
🤖 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 `@packages/database/prisma/seed.ts` around lines 104 - 125, The worker seeding
logic in the Promise.all map uses prisma.worker.upsert with
organizationId_employeeCode, but the new employeeCode format no longer matches
legacy seeded rows, so rerunning the seed creates duplicates. Update the seed
flow in the worker upsert block to handle existing W001/W002/W003 records first
by normalizing or migrating legacy employeeCode values before inserting
W-0001/W-0002/W-0003, and keep the upsert keyed on organizationId_employeeCode
so the operation remains idempotent.

Source: Path instructions

🤖 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/test/helpers/fake-prisma.ts`:
- Around line 75-82: The fixed starting values in the fake Prisma state cause ID
sequencing to move backward when seeded data already contains larger IDs. Update
the fake state initialization in fake-prisma so nextOrganizationId, nextUserId,
nextRefreshTokenId, and nextBusinessHourId are computed from the existing seeded
records the same way nextWorkerId is, using the relevant collections to pick max
existing ID plus one. This keeps the test double aligned with Prisma’s
auto-increment behavior and avoids collisions when tests inject initial state.

In `@apps/api/test/organization.routes.test.ts`:
- Around line 129-208: Add a test case in organization.routes.test.ts for an
authenticated user whose Prisma fixture has no organization, and verify that
GET/PATCH /api/organization is rejected with the ORGANIZATION_REQUIRED error.
Reuse the existing createFakePrisma, createApp, authHeader, and organization
route request pattern so the new case clearly covers the “organization required”
access control rule and prevents regressions for users without an organization.

In `@docs/openapi.yaml`:
- Around line 624-626: The Worker.employeeCode schema is too loose because it is
only declared as a string with an example, so update the OpenAPI definition for
employeeCode in docs/openapi.yaml to enforce the W-0001-style contract by adding
an appropriate pattern (and keep the example aligned). Make the change in the
existing employeeCode property definition so Swagger/UI and generated clients
treat only the intended 사번 format as valid.

---

Outside diff comments:
In `@packages/database/prisma/seed.ts`:
- Around line 104-125: The worker seeding logic in the Promise.all map uses
prisma.worker.upsert with organizationId_employeeCode, but the new employeeCode
format no longer matches legacy seeded rows, so rerunning the seed creates
duplicates. Update the seed flow in the worker upsert block to handle existing
W001/W002/W003 records first by normalizing or migrating legacy employeeCode
values before inserting W-0001/W-0002/W-0003, and keep the upsert keyed on
organizationId_employeeCode so the operation remains idempotent.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 79ebe804-ae93-4f18-804a-6ab8c12e8f14

📥 Commits

Reviewing files that changed from the base of the PR and between 80565cc and 8a5974c.

📒 Files selected for processing (13)
  • apps/api/src/modules/workers/workers.handlers.ts
  • apps/api/src/modules/workers/workers.service.ts
  • apps/api/src/routes/index.ts
  • apps/api/src/routes/workers.routes.ts
  • apps/api/test/auth.routes.test.ts
  • apps/api/test/helpers/fake-prisma.ts
  • apps/api/test/helpers/organization-fixtures.ts
  • apps/api/test/organization.routes.test.ts
  • apps/api/test/workers.routes.test.ts
  • docs/API.md
  • docs/openapi.yaml
  • packages/database/prisma/seed.ts
  • packages/shared/src/schemas/workers.ts

Comment thread apps/api/test/helpers/fake-prisma.ts Outdated
Comment thread apps/api/test/organization.routes.test.ts
Comment thread docs/openapi.yaml
@meteorqz6

meteorqz6 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

리뷰 코멘트 처리 상태입니다.

  • seed 멱등성: 반영했습니다. legacy 사번(W001~W003)을 먼저 W-0001 계열로 정규화하고, 이미 새 포맷 row가 있는 경우 legacy row를 정리한 뒤 upsert하도록 수정했습니다. 반영 커밋: 64ab331
  • fake Prisma ID sequence: 반영했습니다. fixture의 기존 id를 기준으로 next id를 계산하도록 수정했습니다. 반영 커밋: 64ab331
  • OpenAPI employeeCode pattern: 반영했습니다. ^W-\d{4}$ pattern을 추가했습니다. 반영 커밋: 64ab331
  • organization route의 ORGANIZATION_REQUIRED 테스트 요청: 미반영했습니다. 현재 organization API는 조직 미존재 시 기존 계약상 404 NOT_FOUND를 반환하고, 이번 PR 범위는 workers 운영 API의 조직 필수 처리입니다.
  • PR description warning: PR 본문을 템플릿 형식으로 갱신했습니다.
  • Docstring coverage / CodeRabbit ESLint install warning: 프로젝트 TypeScript 코드 스타일 및 외부 도구 설정 이슈로 판단해 코드 변경 대상에서는 제외했습니다.

검증:

  • pnpm --filter @fragment/api typecheck
  • pnpm --filter @fragment/api test
  • pnpm --filter @fragment/api lint
  • pnpm --filter @fragment/api build

@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: 1

🤖 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/test/helpers/fake-prisma.ts`:
- Around line 233-247: The `fake-prisma.ts` sorting in the `rules.sort` callback
is using `localeCompare` for `dayOfWeek`, which sorts alphabetically instead of
Prisma Enum declaration order. Update the `dayOfWeek` branch in the
`Array.isArray(orderBy)` handling to compare against the enum’s intended order
(matching Prisma/PostgreSQL, e.g. via a fixed ordinal map), so
`staffing-rules.service.ts` tests see the same weekday ordering as production.
Keep the `startTime` ordering logic unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2d95e191-3817-4013-8ac1-98d15ec55019

📥 Commits

Reviewing files that changed from the base of the PR and between 0311d15 and 91c5131.

📒 Files selected for processing (3)
  • apps/api/src/routes/index.ts
  • apps/api/test/helpers/fake-prisma.ts
  • docs/API.md

Comment thread apps/api/test/helpers/fake-prisma.ts
@meteorqz6
meteorqz6 merged commit 0afc5d7 into develop Jun 25, 2026
2 checks passed
@meteorqz6
meteorqz6 deleted the feature/77-workers-api branch June 25, 2026 13:08
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