Skip to content

[FEAT] 네이버 캘린더 연동 API 추가 - #43

Merged
Siul49 merged 6 commits into
devfrom
feature/42-naver-calendar-integration
Jun 11, 2026
Merged

Siul49 merged 6 commits into
devfrom
feature/42-naver-calendar-integration

Conversation

@kokkumong

Copy link
Copy Markdown
Collaborator

🚀 작업 내용 (What)

  • 네이버 OAuth 인증 시작/콜백 API를 추가했습니다.
  • 네이버 토큰 저장/갱신/프로필 조회 모듈을 추가했습니다.
  • 네이버 캘린더 기본 캘린더 응답 및 일정 생성 API를 추가했습니다.
  • 네이버 Open API에서 일정 조회 API를 제공하지 않는 점을 501 응답으로 명확히 처리했습니다.
  • 네이버 연동 타입과 단위 테스트를 추가하고, 환경 변수 예시를 갱신했습니다.

📣 핵심 변경 이유 (Why)

  • 사용자가 네이버 계정을 통해 캘린더 연동을 진행하고, MOIM에서 생성한 일정을 네이버 캘린더에 추가할 수 있도록 하기 위해 필요합니다.

📸 스크린샷 (Visuals, 선택)

  • API 라우트 중심 변경이라 별도 UI 스크린샷은 없습니다.

⚠️ 체크리스트 (Checklist)

  • 브랜치 컨벤션(feature/00-name)을 지켰나요?
  • 커밋 컨벤션(feat:, fix: 등)을 지켰나요?
  • 작업 전에 관련 이슈를 생성하고 연결했나요?
  • 내 코드가 팀의 기존 코드를 망가뜨리지 않았는지 확인했나요?

🔗 관련 이슈 (Issue)

Related #42

🧪 검증 결과

  • node node_modules/vitest/vitest.mjs run 통과: 25 files, 209 tests
  • node node_modules/eslint/bin/eslint.js src/lib/naver src/app/api/naver src/types/naver-calendar.ts src/types/calendar-event.ts 통과
  • node node_modules/next/dist/bin/next build 통과

⚠️ 남은 확인 사항

  • 로컬 OAuth 로그인과 /api/naver/calendars 인증 응답은 확인했습니다.
  • 실제 /api/naver/events/create 호출은 네이버 Gateway에서 401 / errorCode 024 인증 실패가 발생했습니다.
  • 네이버 개발자센터의 캘린더 API 권한, 테스트 계정/앱 검수 상태, 기존 앱 동의 철회 후 재동의 여부를 추가 확인해야 합니다.
  • 이 이슈가 남아 있어 PR은 draft로 생성합니다.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

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

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ 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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

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: 8a8f5ef7-2105-4ef0-bef5-dba1722cf3cf

📥 Commits

Reviewing files that changed from the base of the PR and between c53fddd and 51d38ae.

📒 Files selected for processing (9)
  • .env.example
  • src/app/api/naver/callback/route.ts
  • src/app/api/naver/events/create/route.ts
  • src/lib/naver/__tests__/auth.test.ts
  • src/lib/naver/__tests__/events.test.ts
  • src/lib/naver/auth.ts
  • src/lib/naver/errors.ts
  • src/lib/naver/events.ts
  • src/types/naver-calendar.ts

Walkthrough

Naver OAuth 2.0 기반 캘린더 연동 기능 구현. OAuth 상태 관리, 토큰 교환/갱신/저장(HttpOnly 쿠키), 사용자 프로필 조회, iCalendar 포맷 일정 생성 API 호출, zod 기반 요청 검증, 엔드-투-엔드 테스트.

Changes

Naver 캘린더 OAuth 및 일정 생성 연동

Layer / File(s) 요약
타입 정의 및 환경 구성
.env.example, src/types/naver-calendar.ts, src/types/calendar-event.ts
NaverTokens, NaverUserProfile, NaverEventInput, NaverEvent, NaverCreateScheduleResponse 타입 추가 및 NAVER_CLIENT_* 환경변수 정의. CalendarEventSource 유니온에 "naver" 리터럴 추가.
OAuth 인증 라이브러리
src/lib/naver/auth.ts
Naver OAuth 2.0 엔드포인트, 상수, 클라이언트 설정 정의. createOAuthState(), buildAuthUrl(), saveOAuthStateToCookie(), validateAndClearOAuthState()로 CSRF 검증 및 상태 관리 구현. exchangeCodeForTokens(), refreshAccessToken()으로 토큰 교환/갱신. getUserProfile()로 프로필 조회. saveTokensToCookie(), getValidTokens()로 HttpOnly 쿠키 기반 토큰 저장소 구현. clearTokensCookie()로 쿠키 삭제.
OAuth 흐름 라우트
src/app/api/naver/auth/route.ts, src/app/api/naver/callback/route.ts
GET /api/naver/auth: 상태 생성 및 저장 후 네이버 OAuth 동의 화면 리다이렉트. GET /api/naver/callback: 쿼리 파라미터 검증(error/code/state), state 검증 실패 시 400, 토큰 교환/프로필 조회/쿠키 저장 후 캘린더 페이지로 리다이렉트. 예외 발생 시 콘솔 로깅 후 500.
캘린더 조회 및 일정 생성 라우트
src/app/api/naver/calendars/route.ts, src/app/api/naver/events/create/route.ts, src/app/api/naver/events/query/route.ts
GET /api/naver/calendars: 토큰 검증 후 기본 캘린더 반환(401 미인증). POST /api/naver/events/create: CreateEventSchema (zod) 검증, startDateTime ≥ endDateTime 시 400, createEvent() 호출 후 201 반환. 인증 실패 메시지 포함 시 401, 권한 메시지 포함 시 403, 기타 예외 502. GET /api/naver/events/query: 501 (미구현, API 미제공).
일정 생성 유틸리티
src/lib/naver/events.ts
NAVER_CALENDAR_API_URL, DEFAULT_CALENDAR_ID, DEFAULT_TIMEZONE 상수 정의. 클라이언트 ID/시크릿 환경변수 읽기(미설정 시 예외). iCalendar 텍스트 이스케이프(;, \, 줄바꿈) 및 타임존 기반 로컬 시간 변환 헬퍼. buildNaverScheduleIcal(): VCALENDAR/VEVENT 문자열 생성, uid/DTSTART/DTEND/SUMMARY/DESCRIPTION/LOCATION/CREATED/LAST-MODIFIED/DTSTAMP 포함. createEvent(): URLSearchParams 폼으로 네이버 API 호출, Authorization(Bearer + 클라이언트 ID/시크릿) 헤더 포함, 401/403 상태코드 구분 예외, 응답 result === "success"returnValue 검증 후 반환.
OAuth 및 이벤트 테스트
src/lib/naver/__tests__/auth.test.ts, src/lib/naver/__tests__/events.test.ts
auth.ts: fetch/next/headers mock, buildAuthUrl(기본/커스텀 redirect URI), state 저장/검증/삭제, exchangeCodeForTokens(폼 body/응답 매핑/실패 예외), refreshAccessToken, getUserProfile(response.id 매핑/미설정 시 예외). events.ts: fetch mock, buildNaverScheduleIcal(iCalendar 생성/텍스트 이스케이프/타임존 변환), createEvent(엔드포인트/헤더/폼 body/calendarId 반영/인증 및 실패 예외).

예상 코드 리뷰 난이도

🎯 4 (복잡) | ⏱️ ~60분


관련 이슈

  • #42: Naver 캘린더 OAuth 및 일정 생성 기능 요청. 이 PR은 OAuth 2.0 인증 흐름, API 라우트, 타입 정의, 유틸리티 함수를 모두 구현하여 요청 사항을 완전히 충족.

추천 라벨

feature, test


시니어 리뷰 코멘트

CSRF State 관리 방식 재검토 필요
Why: validateAndClearOAuthState()에서 state 일치 후 즉시 쿠키 삭제. 네트워크 분할 환경에서 콜백 요청이 실패해도 상태 복구 불가.
How: 검증 실패 횟수를 제한하되 동일 state에 대해 재검증 기회 제공 (예: TTL 기반 soft delete).

// 현재 방식
validateAndClearOAuthState(state) // 실패 시 다시 시작해야 함
// 개선안
validateAndClearOAuthState(state, { retryCount: 3, ttl: 300000 })

토큰 갱신 자동화 시 경합 조건 미처리
Why: getValidTokens() 호출이 동시에 여러 건 들어올 때, 모두 refreshAccessToken() 호출 가능.
How: 토큰 갱신 진행 중 플래그 또는 뮤텍스 사용:

// src/lib/naver/auth.ts getValidTokens() 에 추가 필요
if (isRefreshing) await refreshingPromise;
else { refreshingPromise = refreshAccessToken(...); isRefreshing = true; }

POST /api/naver/events/create에 타임존 검증 부재
Why: NaverEventInputtimeZone 필드가 선택적. 클라이언트가 잘못된 타임존 전송 시 buildNaverScheduleIcal()에서 조용히 기본값 사용.
How: zod schema에 타임존 화이트리스트 추가:

const CreateEventSchema = z.object({
  timeZone: z.enum(['Asia/Seoul', 'UTC', /* ... */]).optional(),
  // ...
});

이벤트 API 응답 매핑 불충분
Why: createEvent()data.returnValue만 반환. 네이버 API에서 code 필드(에러 상세 코드) 무시.
How: 에러 응답에서 code 추출 후 상세 메시지 제공:

if (data.result === 'failure') {
  throw new Error(`Naver API error [${data.code}]: ${data.message}`);
}

테스트 환경변수 누수 위험
Why: beforeEach에서 process.env.NAVER_CLIENT_ID = 'test' 설정 후 정리 미흡.
How: afterEach에서 복원:

afterEach(() => {
  delete process.env.NAVER_CLIENT_ID;
  delete process.env.NAVER_CLIENT_SECRET;
  vi.clearAllMocks();
});

쿠키 보안 옵션 불완전
Why: saveTokensToCookie() 에서 secure: true이나, 개발 환경 테스트 시 HTTPS 미보장.
How: 환경별 조건부 설정:

const isProduction = process.env.NODE_ENV === 'production';
cookies().set(NAVER_TOKENS_COOKIE_NAME, JSON.stringify(tokens), {
  secure: isProduction,
  httpOnly: true,
  sameSite: 'lax',
  // ...
});
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목이 지정된 규칙에 부합하지 않음. '[FEAT]' 형식은 요구사항인 'feat:' 형식과 다름. 제목을 '[FEAT] 네이버 캘린더 연동 API 추가'에서 'feat: 네이버 캘린더 연동 API 추가'로 수정하여 규칙 준수.
Docstring Coverage ⚠️ Warning Docstring coverage is 68.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
Description check ✅ Passed PR 설명이 변경 내용과 관련 있음. 추가된 기능, 목적, 검증 결과, 남은 사항이 구체적으로 기술되어 있음.
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.

✏️ 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/42-naver-calendar-integration

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 and usage tips.

@kokkumong
kokkumong marked this pull request as ready for review June 7, 2026 04:51

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

🤖 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 @.env.example:
- Around line 12-14: The .env.example currently lists NAVER_REDIRECT_URI as if
required; update the example to mark NAVER_REDIRECT_URI as optional (or comment
it out) and add a short note that getRedirectUri() in src/lib/naver/auth.ts will
auto-generate the redirect URI from NEXT_PUBLIC_BASE_URL when NAVER_REDIRECT_URI
is not set; specifically reference NAVER_REDIRECT_URI and getRedirectUri() so
developers understand the variable is optional and avoid redundant
configuration.

In `@src/app/api/naver/callback/route.ts`:
- Around line 52-54: The current OAuth callback returns NextResponse.redirect to
the API route `/api/naver/calendars`, which causes the browser to show raw JSON;
change the redirect target from
`${baseUrl}/api/naver/calendars?connected=true&user=${encodeURIComponent(identifier)}`
to the frontend scheduling UI route (for example
`${baseUrl}/scheduling?connected=true&user=${encodeURIComponent(identifier)}` or
the app's canonical scheduling path) so the browser lands on the UI page instead
of the API; keep the query params (connected and user/identifier) and update the
redirect call that uses NextResponse.redirect and variables baseUrl and
identifier accordingly.

In `@src/app/api/naver/events/create/route.ts`:
- Line 9: Zod schema for the request currently sets calendarId as optional but
uses an error message saying "calendarId는 필수입니다.", which conflicts with the
optional behavior and the fallback to DEFAULT_CALENDAR_ID in createEvent; update
the calendarId z.string().min(...) message to reflect that the field is optional
(e.g., "calendarId는 선택 사항입니다." or "제공할 경우 빈 문자열이 될 수 없습니다.") or change
validation to only run when a value is present so that empty/missing calendarId
does not produce a "required" error; ensure references are to the calendarId
schema entry and the createEvent logic that falls back to DEFAULT_CALENDAR_ID.
- Around line 71-87: Replace fragile string-based error checks in the Naver
calendar error handling block with explicit error-type or error-code checks:
introduce or import custom error classes (e.g., NaverAuthError,
NaverPermissionError) or use a standardized error.code from the upstream handler
(events.ts), then change the conditionals in create/route.ts to test err
instanceof NaverAuthError and err instanceof NaverPermissionError (or err.code
=== 'NAVER_AUTH' / 'NAVER_PERMISSION') and return the 401/403 NextResponse
accordingly; update the producer in events.ts to throw the corresponding custom
error types or set the canonical error.code so the router’s branching is
resilient to message changes.

In `@src/lib/naver/__tests__/auth.test.ts`:
- Around line 60-83: Add tests covering null/undefined received state and
missing cookie for OAuth state validation: update the "oauth state cookie" suite
to call validateAndClearOAuthState with null (expect false) and to simulate
mockCookieStore.get returning undefined while calling validateAndClearOAuthState
with a valid string (expect false). Ensure these tests reference
validateAndClearOAuthState and the mockCookieStore.get behavior so the code path
that returns false when receivedState is falsy or when the cookie is absent is
exercised.
- Around line 160-196: Add two tests to src/lib/naver/__tests__/auth.test.ts for
getUserProfile to cover API failure and network errors: one that stubs mockFetch
to resolve with ok: false (e.g., status 401 and text returning "Unauthorized")
and asserts getUserProfile rejects, and one that stubs
mockFetch.mockRejectedValueOnce(new Error("Network error")) and asserts
getUserProfile rejects with the network error message; place them alongside the
existing getUserProfile tests so they exercise the same call path and header
check.
- Around line 36-58: Add a test to validate that buildAuthUrl correctly
URL-encodes special characters in the state parameter: call buildAuthUrl with a
state containing spaces and reserved characters (e.g., "state with spaces &
special=chars") and assert the resulting URL includes the percent-encoded state
substring ("state%20with%20spaces%20%26%20special%3Dchars"); place this new test
alongside the existing buildAuthUrl tests in auth.test.ts and reference
buildAuthUrl so the encoding behavior is explicitly verified.

In `@src/lib/naver/__tests__/events.test.ts`:
- Around line 60-170: Add two tests to cover the missing error scenarios: one
that mocks fetch returning ok: false with status: 403 and text "Forbidden" and
asserts createEvent rejects with a "권한" (permission) error, and another that
mocks a successful response (ok: true) whose JSON has result: "success" but no
returnValue and asserts createEvent rejects (throws) — update the test file's
describe("createEvent"... ) to include these cases so the createEvent function's
403 handling and the success-without-returnValue path are verified; reference
the existing createEvent calls and mockFetch.mockResolvedValueOnce usage to
mirror the other tests.
- Around line 13-58: Tests for buildNaverScheduleIcal are missing key edge
cases; add unit tests that (1) call buildNaverScheduleIcal without uid and
assert UID matches /UID:[a-f0-9-]+@moim\.app/, (2) omit optional
location/description and assert the resulting iCal string does NOT contain
"LOCATION:" or "DESCRIPTION:", (3) pass an invalid ISO date (e.g.,
"invalid-date") and assert the call throws an error mentioning date/format, and
(4) pass startDateTime >= endDateTime and assert the function throws or rejects
with a validation error; target the buildNaverScheduleIcal symbol and make
assertions using toMatch/toContain/not.toContain/toThrow as in existing tests.

In `@src/lib/naver/auth.ts`:
- Around line 187-215: In getValidTokens, add error logging for both the
JSON.parse failure and the refreshAccessToken failure: when JSON.parse(raw)
throws, catch the error and log a descriptive message including
TOKEN_COOKIE_NAME and the raw cookie value (or a safely truncated/redacted
version) plus the error stack; likewise, in the catch around
refreshAccessToken(tokens.refreshToken) log a message that includes which token
refresh failed, the (redacted/truncated) refreshToken and the caught error/stack
before returning null; implement these logs inside getValidTokens (referencing
JSON.parse, refreshAccessToken, saveTokensToCookie, and TOKEN_COOKIE_NAME) and
keep the existing behavior of returning null after logging.
- Around line 199-211: getValidTokens() currently updates only
accessToken/tokenType/expiresAt after calling
refreshAccessToken(tokens.refreshToken) and ignores a possible new refresh
token; update getValidTokens() to also set tokens.refreshToken =
refreshed.refreshToken ?? tokens.refreshToken and then call
saveTokensToCookie(tokens), and ensure refreshAccessToken() returns
refreshed.refreshToken in its response shape so the new refresh token can be
persisted for future rotations.
- Around line 105-112: Extract a shared, type-safe parser (e.g.,
parseTokenResponse) and use it from exchangeCodeForTokens and
refreshAccessToken: implement parseTokenResponse(data) to validate and parse
expires_in (use parseInt(String(data.expires_in), 10)), throw on missing/invalid
expires_in, and return { accessToken, tokenType, expiresAt } with expiresAt =
Date.now() + expiresIn*1000; then replace the inline Number(data.expires_in)
logic in exchangeCodeForTokens and refreshAccessToken to call parseTokenResponse
and merge in refreshToken where needed (keep function names
exchangeCodeForTokens and refreshAccessToken to locate replacements) to remove
duplication and ensure type-safe expiry calculation.

In `@src/lib/naver/events.ts`:
- Around line 34-53: The toNaverLocalDateTime function can produce "undefined"
segments because Intl.DateTimeFormat.formatToParts may omit fields; update
toNaverLocalDateTime to validate that byType.year, month, day, hour, minute, and
second are present and non-empty after building parts, and if any are missing
throw a clear Error (e.g. "Invalid date parts from formatToParts") instead of
returning a malformed string; locate the formatToParts call and parts→byType
mapping in toNaverLocalDateTime and add the existence checks (or
fallback/zero-pad logic if you prefer) before composing and returning the final
timestamp string.
- Around line 60-105: The VTIMEZONE block in buildNaverScheduleIcal currently
hardcodes TZOFFSETFROM/TZOFFSETTO to +0900 while TZID uses the dynamic timeZone;
to fix this, enforce that input.timeZone is the expected Asia/Seoul (or
DEFAULT_TIME_ZONE) by validating timeZone at the top of buildNaverScheduleIcal
and throw or return an error if a different zone (e.g., "America/New_York") is
provided, or alternatively remove the VTIMEZONE block entirely if you verify
Naver accepts only DTSTART;TZID=... without VTIMEZONE—update the function’s
timeZone handling and add a clear validation/error path so UID, DTSTART/DTEND
and VTIMEZONE remain consistent.

In `@src/types/naver-calendar.ts`:
- Around line 40-46: Split NaverCreateScheduleResponse into two discriminated
types (e.g., NaverCreateScheduleSuccess with result: "success" and required
returnValue: NaverEvent, and NaverCreateScheduleFailure with result: "failure"
and optional message/code) and export their union as
NaverCreateScheduleResponse; update call sites (notably the code in events.ts
that reads data.result and then accesses data.returnValue) to rely on the
narrowed union so TypeScript infers returnValue as NaverEvent after checking
result === "success".
🪄 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: 5622f3dc-c52d-4528-9a62-311a1e81be17

📥 Commits

Reviewing files that changed from the base of the PR and between e40c252 and c53fddd.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json, !**/*.json, !package-lock.json
  • package.json is excluded by !**/*.json
📒 Files selected for processing (12)
  • .env.example
  • src/app/api/naver/auth/route.ts
  • src/app/api/naver/calendars/route.ts
  • src/app/api/naver/callback/route.ts
  • src/app/api/naver/events/create/route.ts
  • src/app/api/naver/events/query/route.ts
  • src/lib/naver/__tests__/auth.test.ts
  • src/lib/naver/__tests__/events.test.ts
  • src/lib/naver/auth.ts
  • src/lib/naver/events.ts
  • src/types/calendar-event.ts
  • src/types/naver-calendar.ts

Comment thread .env.example Outdated
Comment thread src/app/api/naver/callback/route.ts
Comment thread src/app/api/naver/events/create/route.ts Outdated
Comment thread src/app/api/naver/events/create/route.ts Outdated
Comment thread src/lib/naver/__tests__/auth.test.ts
Comment thread src/lib/naver/auth.ts
Comment thread src/lib/naver/auth.ts
Comment thread src/lib/naver/events.ts
Comment thread src/lib/naver/events.ts
Comment thread src/types/naver-calendar.ts Outdated
kokkumong and others added 2 commits June 7, 2026 14:17
- OAuth 콜백을 API(JSON) 대신 /schedule/create UI 페이지로 리다이렉트
- 토큰 응답 파싱을 parseTokenResponse로 통합하고 expires_in 검증 추가
- 토큰 갱신 시 새 refresh_token 로테이션 반영 및 실패 로깅 추가
- createEvent 에러를 커스텀 에러 클래스(NaverAuthError/NaverPermissionError)로 분기
- NaverCreateScheduleResponse를 discriminated union으로 분리
- formatToParts 필수 필드 검증 및 Asia/Seoul 외 타임존 입력 차단
- calendarId zod 에러 메시지를 optional 동작에 맞게 수정
- .env.example의 NAVER_REDIRECT_URI를 선택값으로 주석 처리
- state 인코딩/null 처리, getUserProfile 실패, ical 엣지 케이스 테스트 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
moim-app Ready Ready Preview, Comment Jun 11, 2026 2:26pm

@Siul49

Siul49 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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.

2 participants