Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
a3c9a37
#250 [Fix] 투표 비율 계산 기준을 preVoteOption에서 postVoteOption으로 수정 (#252)
HYH0804 May 27, 2026
a38c141
#254 [Refactor] 관점 등록/수정 시 GPT 검수 코드 제거 (#256)
HYH0804 Jun 3, 2026
cee2c5d
#255 [Refactor] VoteStatsResponse OptionStat에 title 필드 추가 (#257)
HYH0804 Jun 3, 2026
53533b8
#258 [Feat] 출석체크 API 추가
si-zero Jun 3, 2026
77db7a1
#260 [Feat] 스웨거 어드민/유저 분리
si-zero Jun 4, 2026
a9d4293
[Feat] 알림기능 (#263)
HYH0804 Jun 11, 2026
b5a681b
#262 [Fix] APNs 자격증명 S3 다운로드 시 임시파일 충돌 오류 수정
HYH0804 Jun 11, 2026
d281fa3
#264 [Fix] AdMob SSV 포인트 미적립 버그 수정
si-zero Jun 11, 2026
968d6a3
#262 merge (#266)
HYH0804 Jun 14, 2026
d041631
[Chore] adMob 크롤링 파일 설정: adMob 크롤링 파일 설정 #269
si-zero Jun 16, 2026
ec25882
#270 [Feat] 설정 파일 추가
si-zero Jun 16, 2026
4c45999
[Chore] JWT필터 설정 #271
si-zero Jun 16, 2026
e0c9c1c
#275 [Fix] AdMob SSV 콜백 파라미터 optional 처리 및 서명 검증 활성화
si-zero Jun 18, 2026
ab2cb78
#277 [Fix] AdMob SSV 콜백 URL 검증 요청 처리 실패
si-zero Jun 18, 2026
04d947c
#279 [Fix] AdMob SSV 엔드포인트 검증 실패 시 항상 200 반환
si-zero Jun 18, 2026
d9ea3b5
#283 [Fix] /me/content-activities voteSide null 반환 버그
si-zero Jun 19, 2026
ec27b01
#285 [Feat] content-activities 응답에 option_title 필드 추가
si-zero Jun 20, 2026
6663e7a
#287 [Fix] AdMob SSV 서명 검증 오류로 인한 포인트 미지급 버그
si-zero Jun 24, 2026
39aca84
#289 [Fix] 오늘의 배틀 개수 변경
si-zero Jul 5, 2026
11e2da1
#293 [Fix] 사전투표 철학자 아이콘 미노출
si-zero Jul 5, 2026
aa449f0
#297 [Fix] 댓글 작성 시각이 9시간 전으로 표시되는 버그
si-zero Jul 6, 2026
3259a1a
#301 [Fix] robots.txt 파일 부재로 AdMob app-ads.txt 크롤링 차단
si-zero Jul 6, 2026
e91819b
#305 [Fix] S3 오디오 조각 재다운로드 시 FileAlreadyExistsException으로 TTS 파이프라인 실패
si-zero Jul 6, 2026
d64d5ca
#309 [Fix] JwtFilter 자체 화이트리스트에 /robots.txt 누락으로 401 발생
si-zero Jul 6, 2026
ff16d85
#316 [Fix] 포인트 정책표 대비 코드 불일치 4건 수정
si-zero Jul 7, 2026
f50c749
Merge branch 'main' into dev
si-zero Jul 7, 2026
d9e28a1
#321 [Feat] 알림 미읽음 여부 확인 API 추가
si-zero Jul 7, 2026
4279341
#313 [Hotfix] Railway 배포 환경 FFmpeg 자동 설치 적용 (#320)
jucheonsu Jul 7, 2026
f77048c
#327 [Fix] 알림 전체 읽음 처리 후 모두 읽음 신호가 전달되지 않던 문제 수정
si-zero Jul 13, 2026
99886f9
#331 [Docs] 출석체크 API 명세서를 실제 코드에 맞춰 갱신
si-zero Jul 13, 2026
087b8c0
#333 [Fix] app-ads.txt가 text/html로 응답되어 AdMob 크롤러가 무시하는 문제 수정
si-zero Jul 13, 2026
d33ff1f
#337 [Feat] 인앱 알림 테스트용 API 추가
si-zero Jul 14, 2026
17f35a4
#341 [Fix] 미문서화/중복 포인트 지급 로직 정리
si-zero Jul 15, 2026
acbe078
관리자 페이지를 새 admin-web(Next.js) 앱으로 리다이렉트 (#346)
Jul 15, 2026
de75bdf
#349 [Feat] admin.web.url env 주입 + 기본값 picke.up.railway.app (#350)
Jul 15, 2026
9493351
#352 [Fix] JwtFilter 화이트리스트 /api/v1/auth 전체 매칭으로 logout 인증 우회, 500 에러 발생
si-zero Jul 16, 2026
00bfcb3
#356 [Feat] 이용약관/개인정보처리방침 페이지 백엔드 서빙
si-zero Jul 20, 2026
99c936d
#361 [Feat] 관리자용 테스트 계정 로컬 로그인 기능 추가
si-zero Jul 24, 2026
f0a837d
#360 [Refactor] 1인 1관점 제한을 해제하고 1인 다수 관점 등록 허용
si-zero Jul 24, 2026
9fb601f
#366 [Feat] 내 콘텐츠 활동 내역(댓글 탭)에 내가 작성한 관점 포함
si-zero Jul 24, 2026
6a1abde
#370 [Fix] 사전투표만 한 기록도 내 배틀 기록에 노출되는 버그
si-zero Jul 24, 2026
80f5b9c
[Feat] 관점 200자 제한 해제 (#375)
si-zero Aug 2, 2026
f9bc278
#378 [Feat] 관리자 예약 푸시알림(제목/소제목/발송시간) 설정 및 자동발송
si-zero Aug 8, 2026
99f4765
#382 [Fix] 내 콘텐츠 활동 댓글 정보 매핑 오류 수정 (#383)
jucheonsu Aug 9, 2026
79cb355
#387 [Refactor] 철학자 태그 제한 및 가치관 육각형 계산 보정 (#388)
jucheonsu Aug 13, 2026
bdbe3b3
#391 [Remove] 미사용 파일 정리 (비활성 CI 워크플로우 + 레거시 admin 프론트)
si-zero Aug 13, 2026
a82c575
#392 [CI/CD] Java CI 파이프라인 브랜치명 오류 및 지속적 빌드 실패 수정
si-zero Aug 13, 2026
70ccc90
#395 [Feat] 관리자용 푸시 알림 발송 테스트 API 추가
si-zero Aug 16, 2026
2e72bf7
#396 [Fix] Android FCM 푸시에 title/body가 실리지 않아 알림이 안 뜨던 문제 수정
si-zero Aug 16, 2026
1fc8488
#401 [Fix] FCM 만료된 디바이스 토큰이 정리되지 않아 반복 발송 실패 로그가 쌓이는 문제 수정
si-zero Aug 17, 2026
a4d3b31
#405 [Feat] 어드민 예약 알림 On/Off 전환 API 추가 및 관리자 알림 API 문서화
si-zero Aug 26, 2026
0b9a374
#407 [Feat] 어드민 유저 검색 API 추가
si-zero Aug 26, 2026
869de77
#409 [Feat] 어드민 공지사항 수정/삭제 API 추가
si-zero Aug 26, 2026
087fea5
#411 [Feat] 어드민 공지 발송 결과 조회 API 추가
si-zero Aug 26, 2026
4bdbdf3
#413 [Feat] 어드민 공지 발송 대상자 수 미리보기 API 추가
si-zero Aug 26, 2026
76e8097
#414 [Feat] 어드민 공지 작성 옵션(카테고리) 조회 API 추가
si-zero Aug 26, 2026
26116e8
#415 [Feat] 어드민 예약 알림 테스트 발송 API 추가
si-zero Aug 26, 2026
4234c29
#423 [Docs] 누락된 마이그레이션 SQL 파일 보완 (#409, #411)
si-zero Aug 30, 2026
7aaa1f4
#421 [Feat] 유저 일별 활동 트래킹(DAU/MAU 기반) 인프라 구축
si-zero Aug 30, 2026
d3b9343
#425 [Feat] 어드민 대시보드 오늘 요약 API 추가
si-zero Sep 1, 2026
2129d35
#427 [Feat] 어드민 대시보드 DAU/MAU 추이 API 추가
si-zero Sep 1, 2026
d8fe672
#429 [Feat] 어드민 대시보드 신규 가입자 추이 API 추가
si-zero Sep 1, 2026
6eea0d4
#431 [Feat] 어드민 대시보드 배틀 참여율 API 추가
si-zero Sep 1, 2026
1e134bc
#433 [Feat] 어드민 대시보드 출석 체크율 API 추가
si-zero Sep 1, 2026
cba91cb
#436 [Feat] 어드민 대시보드 크레딧 지급 현황 API 추가
si-zero Sep 2, 2026
23496d1
#444 [Refactor] AWS S3를 Railway Bucket으로 마이그레이션 (개발 서버)
si-zero Sep 7, 2026
7b0b68f
🐛 Fix: BattleVoteServiceImplTest 시간대 불일치로 15시(UTC) 이후 CI 실패 (#442)
Roy-wonji Sep 7, 2026
c99065e
✨ Feat: ad.picke.store 제휴 광고(쿠팡 파트너스·애드픽) 연동 (#443)
Roy-wonji Sep 8, 2026
d22f21a
#441 [Fix] 쿠팡 파트너스 ID 환경변수 누락 시 앱 부팅 실패 해소 (#448)
Roy-wonji Sep 8, 2026
9745f2e
#441 [Fix] 광고 스웨거 기본 서버를 문서를 연 주소로 바꿈 (#449)
Roy-wonji Sep 8, 2026
e5a0422
#441 [Fix] 필수 쿼리 파라미터 누락 시 500 대신 400 응답 (#450)
Roy-wonji Sep 8, 2026
c3bd52b
#441 [Feat] 광고 스웨거 탭에 운영 광고 도메인 추가 (#451)
Roy-wonji Sep 8, 2026
3baba67
Merge branch 'main' into merge/#452
si-zero Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ out/
.env
postgres_data/
src/main/resources/application-local.yml
.claude
.claude

### macOS ###
.DS_Store
**/.DS_Store
72 changes: 72 additions & 0 deletions docs/db/20260901_create_ad_tables.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
-- 제휴 광고(쿠팡 파트너스 / 애드픽) 소재·클릭·노출 테이블
-- 관련 설계: docs/superpowers/specs/2026-09-01-ad-picke-store-design.md
--
-- 이 파일은 참고용이다. 운영은 spring.jpa.hibernate.ddl-auto=update 라 배포 시 자동 생성된다.
-- 스키마를 손으로 관리하는 환경이나 사후 검증이 필요할 때 쓴다.
--
-- CHECK 제약은 엔티티의 @Check 로도 선언되어 있어 테이블 최초 생성 시 함께 만들어진다.
-- 다만 ddl-auto=update 는 이미 있는 제약을 갱신하지 않는다.
-- enum 에 값을 추가하면 아래 ALTER 를 별도로 실행해야 한다.
-- ALTER TABLE ad_creatives DROP CONSTRAINT ck_ad_creatives_slot;
-- ALTER TABLE ad_creatives ADD CONSTRAINT ck_ad_creatives_slot CHECK (slot IN (...));
-- 빠뜨리면 새 지면의 INSERT 가 조용히 막힌다. AdCheckConstraintTest 가 제약과 enum 의 불일치를 먼저 잡는다.

CREATE TABLE IF NOT EXISTS ad_creatives (
id BIGSERIAL PRIMARY KEY,
code VARCHAR(16) NOT NULL UNIQUE,
network VARCHAR(20) NOT NULL,
slot VARCHAR(40) NOT NULL,
title VARCHAR(100) NOT NULL,
subtitle VARCHAR(200),
image_url VARCHAR(500) NOT NULL,
cta_text VARCHAR(30) NOT NULL,
landing_url VARCHAR(1000) NOT NULL,
status VARCHAR(20) NOT NULL,
source VARCHAR(20) NOT NULL DEFAULT 'MANUAL',
external_id VARCHAR(64),
target_os VARCHAR(20) NOT NULL DEFAULT 'ALL',
weight INTEGER NOT NULL DEFAULT 1,
starts_at TIMESTAMP,
ends_at TIMESTAMP,
created_at TIMESTAMP,
updated_at TIMESTAMP,
CONSTRAINT ck_ad_creatives_network CHECK (network IN ('COUPANG', 'ADPICK')),
CONSTRAINT ck_ad_creatives_slot CHECK (slot IN ('HOME_FEED', 'BATTLE_RESULT_BOTTOM', 'CHAT_ROOM_INLINE', 'ATTENDANCE_COMPLETE', 'PROFILE_BOTTOM')),
CONSTRAINT ck_ad_creatives_status CHECK (status IN ('DRAFT', 'ACTIVE', 'PAUSED')),
CONSTRAINT ck_ad_creatives_source CHECK (source IN ('MANUAL', 'ADPICK_API')),
CONSTRAINT ck_ad_creatives_target_os CHECK (target_os IN ('ALL', 'ANDROID', 'IOS')),
-- 애드픽 캠페인을 다시 찾는 키. 수동 등록 소재는 external_id 가 NULL 이라 중복되지 않는다.
CONSTRAINT uk_ad_creatives_external UNIQUE (source, external_id)
);

-- 지면 조회는 (slot, status)로만 들어온다.
CREATE INDEX IF NOT EXISTS idx_ad_creatives_slot_status ON ad_creatives (slot, status);

CREATE TABLE IF NOT EXISTS ad_click_logs (
id BIGSERIAL PRIMARY KEY,
creative_id BIGINT NOT NULL,
slot VARCHAR(40) NOT NULL,
ip_hash VARCHAR(64),
user_agent VARCHAR(500),
created_at TIMESTAMP,
updated_at TIMESTAMP,
CONSTRAINT ck_ad_click_logs_slot CHECK (slot IN ('HOME_FEED', 'BATTLE_RESULT_BOTTOM', 'CHAT_ROOM_INLINE', 'ATTENDANCE_COMPLETE', 'PROFILE_BOTTOM'))
);

CREATE INDEX IF NOT EXISTS idx_ad_click_logs_creative ON ad_click_logs (creative_id);
CREATE INDEX IF NOT EXISTS idx_ad_click_logs_created_at ON ad_click_logs (created_at);

-- 노출은 raw 로그로 쌓지 않는다. 배너가 스크롤에 걸릴 때마다 행이 생기면 금방 수천만 건이 된다.
CREATE TABLE IF NOT EXISTS ad_impression_daily (
id BIGSERIAL PRIMARY KEY,
creative_id BIGINT NOT NULL,
slot VARCHAR(40) NOT NULL,
stat_date DATE NOT NULL,
impressions BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMP,
updated_at TIMESTAMP,
CONSTRAINT uk_ad_impression_daily UNIQUE (creative_id, slot, stat_date),
CONSTRAINT ck_ad_impression_daily_slot CHECK (slot IN ('HOME_FEED', 'BATTLE_RESULT_BOTTOM', 'CHAT_ROOM_INLINE', 'ATTENDANCE_COMPLETE', 'PROFILE_BOTTOM'))
);

CREATE INDEX IF NOT EXISTS idx_ad_impression_daily_date ON ad_impression_daily (stat_date);
82 changes: 82 additions & 0 deletions docs/erd/ad.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
@startuml ad
hide circle
hide methods
skinparam linetype ortho

entity "ad_creatives" as ad_creatives {
* id : BIGINT <<PK>>
--
code : VARCHAR(16) <<UK>>
network : VARCHAR(20)
slot : VARCHAR(40)
title : VARCHAR(100)
subtitle : VARCHAR(200) <<nullable>>
image_url : VARCHAR(500)
cta_text : VARCHAR(30)
landing_url : VARCHAR(1000)
status : VARCHAR(20)
source : VARCHAR(20)
external_id : VARCHAR(64) <<nullable>>
target_os : VARCHAR(20)
weight : INTEGER
starts_at : TIMESTAMP <<nullable>>
ends_at : TIMESTAMP <<nullable>>
created_at : TIMESTAMP
updated_at : TIMESTAMP
}

entity "ad_click_logs" as ad_click_logs {
* id : BIGINT <<PK>>
--
creative_id : BIGINT
slot : VARCHAR(40)
ip_hash : VARCHAR(64) <<nullable>>
user_agent : VARCHAR(500) <<nullable>>
created_at : TIMESTAMP
updated_at : TIMESTAMP
}

entity "ad_impression_daily" as ad_impression_daily {
* id : BIGINT <<PK>>
--
creative_id : BIGINT
slot : VARCHAR(40)
stat_date : DATE
impressions : BIGINT
created_at : TIMESTAMP
updated_at : TIMESTAMP
}

ad_creatives ||--o{ ad_click_logs : clicked
ad_creatives ||--o{ ad_impression_daily : impressed

note bottom of ad_creatives
제휴 광고 소재. 각 매체 콘솔에서 발급한
완성형 제휴 링크를 어드민이 등록한다.
network : COUPANG | ADPICK
status : DRAFT | ACTIVE | PAUSED
source : MANUAL | ADPICK_API
target_os : ALL | ANDROID | IOS

ADPICK_API 소재는 캠페인 API 가 주기적으로
덮어쓴다. external_id 는 애드픽 apOffer 다.
end note

note bottom of ad_click_logs
클릭 원장. 제휴사 리포트와 대조하는 용도다.
/c/{code}는 외부 브라우저에서 열려
Authorization 헤더가 없으므로 사용자를 특정하지 않는다.
end note

note bottom of ad_impression_daily
일별 노출 집계. (creative_id, slot, stat_date) 유니크.
노출을 raw 로그로 쌓으면 배너가 스크롤에 걸릴 때마다
행이 생겨 금방 수천만 건이 된다.
end note

note top of ad_creatives
creative_id는 논리적 참조다.
소재를 지워도 집계 이력은 남기려고 FK를 걸지 않았다.
end note

@enduml
Loading
Loading