feat: 실시간 알림(인앱+SSE, Redis pub/sub) + Redis 캐싱 (8단계)
알림(8-2): - Notification 모듈 + SSE 스트림(@Sse, @SkipTransform 으로 표준 래퍼 우회). - 12종 알림 적재(업무 지시/해제/승인요청/승인/수정요청/시작/마감변경/삭제/댓글·답글, 멤버 초대/역할변경/제거). 행위자 제외 + 중복 dedup. AppShell 종(미읽음 뱃지·드롭다운). - 실시간 fan-out: REDIS_HOST 시 ioredis pub/sub(다중 인스턴스), 미설정 시 인메모리 폴백. Redis 캐싱(8-3): - CacheModule → @keyv/redis(미설정 시 인메모리 폴백). 저장소 목록을 버전 네임스페이스로 캐시, 생성/수정/삭제·동기화·멤버 초대/제거 시 무효화(공유 버전 키라 다중 인스턴스 정합). - enableShutdownHooks 로 종료 시 Redis 연결 graceful close. 검증: 백엔드 build/lint 0·20 tests, 프론트 build/lint/type-check 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { useApi } from './useApi'
|
||||
import { DEFAULT_PAGE_SIZE } from '@/types/pagination'
|
||||
import type { ApiNotificationList, UnreadCountResult } from '@/types/notification'
|
||||
|
||||
// 알림 도메인 API Composable — 인터셉터가 success/data 를 언래핑
|
||||
// (실시간 스트림 SSE 는 store 에서 EventSource 로 직접 다룬다 — axios 비대상)
|
||||
export function useNotification() {
|
||||
const api = useApi()
|
||||
|
||||
// 내 알림 목록(페이지네이션 + 미읽음 수)
|
||||
async function list(
|
||||
page = 1,
|
||||
size = DEFAULT_PAGE_SIZE,
|
||||
): Promise<ApiNotificationList> {
|
||||
return (await api.get('/notifications', {
|
||||
params: { page, size },
|
||||
})) as unknown as ApiNotificationList
|
||||
}
|
||||
|
||||
// 단건 읽음 처리
|
||||
async function markRead(id: string): Promise<UnreadCountResult> {
|
||||
return (await api.post(
|
||||
`/notifications/${id}/read`,
|
||||
)) as unknown as UnreadCountResult
|
||||
}
|
||||
|
||||
// 전체 읽음 처리
|
||||
async function markAllRead(): Promise<UnreadCountResult> {
|
||||
return (await api.post(
|
||||
'/notifications/read-all',
|
||||
)) as unknown as UnreadCountResult
|
||||
}
|
||||
|
||||
return { list, markRead, markAllRead }
|
||||
}
|
||||
Reference in New Issue
Block a user