# 데이터베이스

잔액의 기준은 `users`의 숫자 컬럼이 아니라 `credit_transactions`입니다. `credit_accounts.available`, `reserved`, `debt`는 그 원장을 접은 스냅샷이며 `vibepeer:maintain reconcile`로 맞출 수 있습니다.

비밀번호 컬럼 이름은 Laravel 관례인 `password`입니다. 값은 해시만 저장합니다.

## 사람

| 테이블 | 역할 |
| --- | --- |
| users | 이메일, 핸들, 역할(`user`,`moderator`,`admin`), 상태, 2FA 비밀, 알림 설정 |
| user_profiles | 소개, 아바타, 포트폴리오 |
| notifications | 데이터베이스 알림 |

## 앱

모델 클래스는 `MobileApp`이고 테이블 이름은 `apps`입니다.

| 테이블 | 역할 |
| --- | --- |
| apps | 소개글. `publication_status`, 플랫폼, 출시 상태, AI 사용 유형 |
| app_media | 커버와 갤러리. 공개 디스크 경로 또는 외부 영상 URL |
| app_updates | 추가 크레딧 없는 버전 소식 |
| app_store_identities | `(store, store_app_id)` 고유. 추적 파라미터를 제거한 뒤의 값 |
| app_slug_histories | 이전 슬러그. 공개 주소는 301 |
| app_ownership_verifications | 소유자 배지는 이 확인이 끝난 뒤에만 |
| app_tag, tags, categories | 분류 |
| campaigns | 같은 앱의 추가 보상 창구 |
| featured_apps, banners, announcements | 홈 운영 슬롯 |

## 피드백과 증거

| 테이블 | 역할 |
| --- | --- |
| feedback | 상태, 유형, 증거 레벨, 보상 여부, 공개 여부, 정책 버전 |
| feedback_evidence | 비공개 경로, sha256, dHash, 만료일 |
| evidence_access_logs | 운영자 열람 기록. IP는 해시 |
| feedback_replies | 제작자 답글 |
| feedback_revisions | 재제출 전 본문 |
| feedback_appeals | 작성자당 피드백 1회 |
| feedback_resolutions | 제작자의 반영/보류 기록 |
| feedback_helpful_votes, app_votes | 사용자·대상 고유 |

공개 피드백은 `status=approved`이면서 `is_public=true`입니다. 보상과 공개는 따로 둡니다.

## 크레딧

| 테이블 | 역할 |
| --- | --- |
| credit_accounts | 스냅샷 |
| credit_transactions | 원장. `idempotency_key` 고유. `admin_adjustment`만 음수 가능 |
| credit_reservations | `active_key`는 `{app_id}:publication`. 정산 후 NULL. 여러 NULL은 허용 |
| policy_versions | 설정 스냅샷. 과거 거래 금액을 다시 쓰지 않음 |
| site_settings | 현재 값. JSON `{v: ...}` |
| idempotency_records | API `Idempotency-Key`와 본문 해시 |

거래 유형은 `earn`, `reserve`, `release`, `spend`, `revoke`, `admin_adjustment`, `refund`입니다.

## 운영

`reports`, `admin_audit_logs`, `risk_events`, `moderation_actions`, `analytics_events`, `legal_documents`.

증거 파일은 `storage/app/evidence`에 두고 HTTP로 디스크를 직접 열지 않습니다. 열람은 권한 검사를 거친 컨트롤러만 합니다.
