- member.plan(FREE/PREMIUM) 컬럼 추가 + SessionUser/MemberResponse 노출
- auth_session 백업에 plan 저장(세션 복원 시 유료 상태 유지)
- 관리자 회원 plan 변경 API (PUT /api/admin/members/{id}/plan)
- PremiumInterceptor 로 유료 전용 경로 차단(통계/예산/고정지출/태그/OCR/투자/카드알림/백업)
· 관리자는 플랜과 무관하게 허용, 무료 회원은 403 PREMIUM_REQUIRED
- WebConfigTest: 유료 경로 등록 회귀 가드 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,9 @@ ALTER TABLE member ADD UNIQUE KEY IF NOT EXISTS uk_member_google_id (google_id);
|
||||
-- 기존 구글 계정(provider=GOOGLE)의 sub 를 google_id 로 백필(멱등 — 이미 채워졌으면 아무 것도 안 함).
|
||||
UPDATE member SET google_id = provider_id WHERE provider = 'GOOGLE' AND google_id IS NULL AND provider_id IS NOT NULL;
|
||||
|
||||
-- 멤버십 플랜 (무료/유료). 기존 회원은 FREE 로 시작 (멱등).
|
||||
ALTER TABLE member ADD COLUMN IF NOT EXISTS plan VARCHAR(20) NOT NULL DEFAULT 'FREE' COMMENT 'FREE / PREMIUM' AFTER role;
|
||||
|
||||
-- ============================================================
|
||||
-- 앱 전역 설정 (단일 행, id=1). 관리자 화면에서 변경.
|
||||
-- ============================================================
|
||||
@@ -47,6 +50,7 @@ CREATE TABLE IF NOT EXISTS auth_session (
|
||||
login_id VARCHAR(50) NULL,
|
||||
name VARCHAR(100) NULL,
|
||||
role VARCHAR(20) NULL,
|
||||
plan VARCHAR(20) NULL,
|
||||
provider VARCHAR(20) NULL,
|
||||
remember_me TINYINT(1) NOT NULL DEFAULT 0,
|
||||
expires_at DATETIME NOT NULL,
|
||||
@@ -54,3 +58,5 @@ CREATE TABLE IF NOT EXISTS auth_session (
|
||||
PRIMARY KEY (token),
|
||||
KEY idx_auth_session_expires (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
-- 멤버십 플랜 백업 (기존 세션 테이블에도 멱등 추가).
|
||||
ALTER TABLE auth_session ADD COLUMN IF NOT EXISTS plan VARCHAR(20) NULL AFTER role;
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
|
||||
<insert id="insert" parameterType="com.sb.web.auth.domain.AuthSession">
|
||||
INSERT INTO auth_session
|
||||
(token, member_id, login_id, name, role, provider, remember_me, expires_at, created_at)
|
||||
(token, member_id, login_id, name, role, plan, provider, remember_me, expires_at, created_at)
|
||||
VALUES
|
||||
(#{token}, #{memberId}, #{loginId}, #{name}, #{role}, #{provider},
|
||||
(#{token}, #{memberId}, #{loginId}, #{name}, #{role}, #{plan}, #{provider},
|
||||
#{rememberMe}, #{expiresAt}, NOW())
|
||||
ON DUPLICATE KEY UPDATE
|
||||
expires_at = #{expiresAt}
|
||||
</insert>
|
||||
|
||||
<select id="findByToken" resultType="com.sb.web.auth.domain.AuthSession">
|
||||
SELECT token, member_id, login_id, name, role, provider, remember_me, expires_at, created_at
|
||||
SELECT token, member_id, login_id, name, role, plan, provider, remember_me, expires_at, created_at
|
||||
FROM auth_session
|
||||
WHERE token = #{token}
|
||||
</select>
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
<result property="providerId" column="provider_id"/>
|
||||
<result property="googleId" column="google_id"/>
|
||||
<result property="role" column="role"/>
|
||||
<result property="plan" column="plan"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createdAt" column="created_at"/>
|
||||
<result property="updatedAt" column="updated_at"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="columns">
|
||||
id, login_id, password, name, email, provider, provider_id, google_id, role, status, created_at, updated_at
|
||||
id, login_id, password, name, email, provider, provider_id, google_id, role, plan, status, created_at, updated_at
|
||||
</sql>
|
||||
|
||||
<select id="findById" parameterType="long" resultMap="memberResultMap">
|
||||
@@ -82,6 +83,10 @@
|
||||
UPDATE member SET role = #{role}, updated_at = NOW() WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="updatePlan">
|
||||
UPDATE member SET plan = #{plan}, updated_at = NOW() WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="updateStatus">
|
||||
UPDATE member SET status = #{status}, updated_at = NOW() WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
Reference in New Issue
Block a user