Skip to content

fix: 벌금 리마인더 푸시 무한 재시도 차단 + 포스트 soft delete#82

Merged
bbbang105 merged 6 commits into
devfrom
fix/fine-reminder-no-token-post-soft-delete
May 4, 2026
Merged

fix: 벌금 리마인더 푸시 무한 재시도 차단 + 포스트 soft delete#82
bbbang105 merged 6 commits into
devfrom
fix/fine-reminder-no-token-post-soft-delete

Conversation

@bbbang105
Copy link
Copy Markdown
Owner

Summary

  • 벌금 리마인더 푸시: FCM 토큰 미등록 케이스를 실패와 분리하고, 무한 재시도 차단. `PushResult`에 `noToken`/`skipped` 카운트 추가
  • 포스트 soft delete: `posts.deletedAt` 컬럼 추가, DELETE를 soft delete로 변경 (URL 보존 → RSS 재수집 차단). 사용자 노출 쿼리 14곳에 `isNull(deletedAt)` 필터 적용
  • 수동 재등록 복원 흐름: 본인이 삭제했던 URL 재등록 시 deletedAt 해제 + 새 메타데이터로 복원. TOCTOU race 차단

배경

  • 매일 09:00 KST 벌금 리마인더가 minmanmim 유저에게 발송 시도되며 매번 'failed'로 로그가 쌓이고 있었음. 원인은 해당 유저의 FCM 토큰이 0개라 `success=0` 반환 → 'failed'로 분류 + `lastReminderAt` 미갱신으로 매일 재시도되는 구조
  • 포스트를 수동 삭제하면 row가 DB에서 사라져 RSS 수집기가 같은 URL을 다시 잡아 재등록되는 문제

주요 변경

1. 벌금 리마인더 가시성 + 무한 재시도 차단

  • `packages/web/src/lib/push.ts`: `PushResult` interface export, `noToken`/`skipped` 카운트 반환
  • `packages/web/src/app/api/internal/reminder-push/route.ts`: errorMessage가 `FCM 토큰 미등록 N명, 전송 실패 N건, 수신 거부 N명` 형식으로 분류
  • `packages/bot/src/lib/push-client.ts`: `PushResult` 타입에 `noToken` 필드 노출
  • `packages/bot/src/handlers/dm-handler.ts`: `sendFineReminder` 반환 `{ sent, noToken, errored }`. `addPendingConfirmation`은 `sent===true` 시에만 호출
  • `packages/bot/src/schedulers/fine-reminder.ts`: noToken 시 `lastReminderAt` 갱신해 무한 재시도 차단. 자동/수동 양쪽에서 `noTokenCount` 별도 집계, 결과 객체 노출

2. 포스트 soft delete

  • `packages/shared/src/db/schema.ts`: `posts.deletedAt` 컬럼 추가
  • `packages/web/src/app/api/posts/[id]/route.ts` DELETE: soft delete + 댓글/조회/리액션/점수 hard delete (복원 시 잔존 차단)
  • 사용자 노출 쿼리 14곳에 `isNull(deletedAt)` 필터 추가
  • RSS 중복 체크는 미변경: `packages/bot/src/services/post.service.ts`는 deletedAt 무관하게 모든 URL을 중복으로 잡음 → soft deleted URL이 RSS 재수집되지 않음

3. 수동 재등록 복원

  • `packages/web/src/app/api/posts/manual/route.ts`: 본인 soft deleted URL 발견 시 deletedAt=null + commentCount=0 + 새 메타데이터로 update. predicate에 `deletedAt IS NOT NULL` + `memberId` 포함시켜 TOCTOU race 차단. 타인 URL은 conflict 반환

마이그레이션

머지 후 dev 환경에서:
```bash
cd packages/shared
export $(grep DATABASE_URL ../../.env.local | head -1 | xargs)
npx drizzle-kit push --force
```

Test plan

  • DB 마이그레이션 적용 (`posts.deleted_at` 컬럼)
  • 다음 09:00 KST 벌금 리마인더 사이클 — 봇 로그에 `📱 [Push] 벌금 리마인더 — FCM 토큰 미등록` 표시 + `토큰 미등록 N건` 완료 로그 확인
  • 알림 로그 errorMessage가 `FCM 토큰 미등록 N명` 형식인지 확인
  • 포스트 삭제 → RSS 재수집되지 않는지 확인 (deletedAt 설정된 row 그대로 유지)
  • 본인 삭제 포스트 동일 URL 수동 재등록 → 복원 동작 확인 (점수 부여 1회)
  • minmanmim FCM 토큰 재등록 후 다음 사이클 정상 발송 확인

🤖 Generated with Claude Code

- 벌금 리마인더: PushResult에 noToken/skipped 카운트 추가, FCM 토큰 미등록 케이스를 실패와 분리. 토큰 미등록 시 lastReminderAt 갱신해 매일 무한 재시도 차단. addPendingConfirmation은 실제 발송 시에만 호출
- 포스트 soft delete: posts.deletedAt 컬럼 추가, DELETE를 soft delete로 변경(URL 보존 → RSS 재수집 차단). 댓글/조회/리액션/점수는 hard delete 유지(복원 시 데이터 잔존 방지). 사용자 노출 쿼리 14곳에 isNull(deletedAt) 필터 적용. RSS 중복 체크는 의도적으로 미변경
- 본인 soft deleted URL 수동 재등록 시 복원 처리. update predicate에 deletedAt IS NOT NULL + memberId 포함시켜 TOCTOU race 차단, commentCount 0으로 초기화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bbbang105 bbbang105 requested a review from choihooo as a code owner May 4, 2026 11:51
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

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

Project Deployment Actions Updated (UTC)
study-admin-web Ready Ready Preview, Comment May 4, 2026 0:27am

@bbbang105 bbbang105 added the 🚨 fix 버그 수정 / 에러 해결 label May 4, 2026
bbbang105 and others added 2 commits May 4, 2026 20:53
posts 스키마에 deletedAt이 추가되면서 Post 타입에 필수 필드가 되어 serialize/deserialize도 동기화 필요.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
firebase-admin 13.7→13.8, playwright 1.58→1.59, prettier 3.8.1→3.8.3, sentry/node 10.43→10.51, axios 1.13→1.16, discord.js 14.25→14.26 등 lockfile drift 정리.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bbbang105 bbbang105 added the ⚒️ chore 빌드 부분 혹은 패키지 매니저 수정 사항 label May 4, 2026
- push-client: 응답 raw JSON + webUrl 동시 로깅 (옛 reminder-push API 호출 식별)
- fine-reminder: sent=false && noToken=false 분류 실패 케이스 logger.warn으로 fineId/memberId/result 출력

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bbbang105 bbbang105 merged commit 22613e6 into dev May 4, 2026
7 checks passed
@bbbang105 bbbang105 deleted the fix/fine-reminder-no-token-post-soft-delete branch May 4, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚒️ chore 빌드 부분 혹은 패키지 매니저 수정 사항 🚨 fix 버그 수정 / 에러 해결

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant