Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2f809f1
refactor(main): remove unused main page components (#60, #68)
thxforall Apr 4, 2026
2ed63ce
feat(ui): add error.tsx and improve global-error styling (#65)
thxforall Apr 4, 2026
88688ca
feat(admin): add dedicated admin login page (#64)
thxforall Apr 4, 2026
da9d015
fix(ui): reduce rendering flickering and layout shifts (#63)
thxforall Apr 4, 2026
5bd76ee
docs: update agent reference docs for phase-1 changes (#66)
thxforall Apr 4, 2026
daa7f0c
fix(admin): resolve login redirect loop by moving to route group (#64)
thxforall Apr 4, 2026
8b29220
fix(admin): resolve login redirect loop — render children instead of …
thxforall Apr 4, 2026
b2a05a3
style(ui): rebrand 404 page with DECODED identity (#65)
thxforall Apr 4, 2026
71f0054
fix(modal): prevent left image flash on explore panel close (#63)
thxforall Apr 4, 2026
17e088a
docs: add Orval/Zod generated API section to agent docs (#66)
thxforall Apr 4, 2026
41b196d
feat(api): expose artist_id/group_id in PostListItem response (#62)
thxforall Apr 4, 2026
6e0d808
feat(api): expose brand_id in Solution response DTOs (#62)
thxforall Apr 4, 2026
5d95f00
chore: update openapi.json with FK fields (artist_id, group_id, brand…
thxforall Apr 4, 2026
72ea60d
feat(api): add artist_id/group_id filter params to list_posts (#79)
thxforall Apr 4, 2026
a49a1f6
chore: update openapi.json with artist_id/group_id filter params (#79)
thxforall Apr 4, 2026
f16156a
feat(explore): show artist profile images on explore cards (#79)
thxforall Apr 4, 2026
677c67e
fix(explore): always show artist info on cards, remove hasMagazine bu…
thxforall Apr 4, 2026
6ed2b5f
feat(detail): show artist/group profile in modal and editorial (#79)
thxforall Apr 4, 2026
736f696
feat(detail): add brand profile images, fix profile image proxy, clea…
thxforall Apr 4, 2026
b756e53
fix(detail): fallback to group_name when artist_name not in profile m…
thxforall Apr 4, 2026
38463d1
fix(warehouse): increase fetch limits and remove debug logs (#79)
thxforall Apr 4, 2026
20a61dd
fix(warehouse): remove hardcoded limit(50) in buildArtistProfileMap (…
thxforall Apr 4, 2026
a7a3bf1
fix(detail): extract brand from solution metadata instead of null (#79)
thxforall Apr 4, 2026
2908acc
fix(warehouse): increase brands fetch limit 100→500, remove hardcoded…
thxforall Apr 4, 2026
c3550ba
feat(detail): add brand logos to MagazineItemsSection (#79)
thxforall Apr 4, 2026
327081e
docs: add editorial UI sizing unification design spec
thxforall Apr 4, 2026
1b323e8
style(detail): unify artist profile, item image, and brand sizing
thxforall Apr 4, 2026
6ebca77
style(detail): increase compact item image to md:w-52
thxforall Apr 4, 2026
60b649c
chore(types): regenerate supabase types (2026-04-04)
thxforall Apr 4, 2026
d5b36e5
fix: type safety fixes and field alignment with regenerated schema
thxforall Apr 4, 2026
4324cce
docs: update planning artifacts and clean old specs
thxforall Apr 4, 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
4 changes: 2 additions & 2 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
- [x] **v8.0 Monorepo Consolidation & Bun Migration** — m10-Phases 01-04 (shipped 2026-03-23)
- [x] **v9.0 Type-Safe API Generation** — Phases 39-43 (shipped 2026-03-24)
- [x] **v10.0 Profile Page Completion** — Phases 44-50 (shipped 2026-03-26)
- [ ] **v11.0 Explore & Editorial Data Integration** — Phases 51-55
- [x] **v11.0 Explore & Editorial Data Integration** — Phases 51-55 (shipped 2026-04-02)

## Phases

Expand Down Expand Up @@ -130,7 +130,7 @@ See archived roadmap: `.planning/milestones/v9.0-ROADMAP.md`
- [x] **Phase 52: Editorial Filter Fix** - hasMagazine 필터 실제 동작 + OpenAPI has_magazine 파라미터 추가 (completed 2026-04-01)
- [x] **Phase 53: Detail Data Migration** - usePostDetailForImage REST 마이그레이션 + Maximize 버튼 soft navigation (completed 2026-04-02)
- [x] **Phase 54: Card Enrichment** - Explore spot_count 배지 + Editorial 매거진 타이틀 오버레이 (completed 2026-04-02)
- [ ] **Phase 55: End-to-End Verification** - 탐색 → 드로어 → 풀 페이지 전체 플로우 검증
- [x] **Phase 55: End-to-End Verification** - 탐색 → 드로어 → 풀 페이지 전체 플로우 검증 (completed 2026-04-02)

## Phase Details

Expand Down
13 changes: 7 additions & 6 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
gsd_state_version: 1.0
milestone: v10.0
milestone_name: Profile Page Completion
status: active
milestone: v11.0
milestone_name: Explore & Editorial Data Integration
status: shipped
last_updated: "2026-04-02"
progress:
total_phases: 20
completed_phases: 17
total_phases: 5
completed_phases: 5
---

# Project State
Expand All @@ -30,7 +30,8 @@ See: .planning/PROJECT.md
| v7.0 Sticker Canvas | Paused | - |
| v8.0 Monorepo & Bun | Shipped | 2026-03-23 |
| v9.0 API Generation | Shipped | 2026-03-23 |
| **v10.0 Profile Completion** | **Active** | - |
| v10.0 Profile Completion | Shipped | 2026-03-26 |
| **v11.0 Explore & Editorial** | **Shipped** | 2026-04-02 |

## Pending Todos

Expand Down
18 changes: 18 additions & 0 deletions docs/agent/api-v1-routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

`packages/web/app/api/v1/` 기준. 메서드·경로 추가 시 이 파일과 실제 라우트 핸들러를 함께 갱신합니다.

## Search

| Route | Methods | Description |
| ------------------ | ------- | ------------------------------------------------------------------------ |
| `/api/v1/search` | GET | Unified search — proxies to backend Meilisearch; Supabase ilike fallback |

Params: `q`, `context`, `media_type`, `sort`, `page`, `limit`.

## Posts & content

| Route | Methods | Description |
Expand All @@ -17,6 +25,7 @@
| `/api/v1/posts/[postId]/likes` | POST | Like/unlike a post |
| `/api/v1/posts/[postId]/saved` | POST | Save/unsave a post |
| `/api/v1/post-magazines/[id]` | GET | Post magazine data |
| `/api/v1/post-magazines/generate` | POST | Trigger editorial generation for a post (admin only, proxy → Rust) |

## Solutions & spots

Expand Down Expand Up @@ -77,5 +86,14 @@
| `/api/v1/admin/reports/[reportId]` | PATCH | Update report status (proxy → Rust) |
| `/api/v1/admin/server-logs` | GET | Server logs |
| `/api/v1/admin/server-logs/stream` | GET | Server logs (SSE stream) |
| `/api/v1/admin/editorial-candidates` | GET | Posts eligible for editorial (spot ≥ 4, solution ≥ 1/spot; proxy → Rust) |
| `/api/v1/admin/picks` | GET/POST | List / create decoded picks (Supabase `decoded_picks` table) |
| `/api/v1/admin/picks/[pickId]` | PATCH/DELETE | Update / delete a decoded pick |

## Utility

| Route | Methods | Description |
| ------------------------ | ------- | ------------------------------------------------ |
| `/api/v1/image-proxy` | GET | Proxy external image URLs (avoids CORS/hotlink) |

Rust REST API와의 관계는 [`.planning/codebase/INTEGRATIONS.md`](../../.planning/codebase/INTEGRATIONS.md) 및 `packages/api-server` 문서를 참고합니다.
37 changes: 36 additions & 1 deletion docs/agent/warehouse-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
> ETL 파이프라인 데이터를 저장하는 Supabase `warehouse` 스키마.
> Instagram 수집 → 엔티티 관리 → Seed 퍼블리싱 파이프라인 전체를 커버한다.

> **참고**: `public.posts` 및 `public.solutions` 테이블(앱 스키마)에는 warehouse 엔티티를 참조하는 FK 컬럼이 추가되었습니다. 자세한 내용은 아래 [App 스키마 FK 컬럼](#app-스키마-fk-컬럼-warehouse-참조) 섹션을 참고합니다.

**Project ID:** `fvxchskblyhuswzlcmql`
**Schema:** `warehouse` (API Exposed)
**Types 파일:** `packages/web/lib/supabase/warehouse-types.ts` (2026-03-26 생성)
**Types 파일:** `packages/web/lib/supabase/warehouse-types.ts` (2026-03-26 생성, warehouse 스키마 전용)
**Public Types 파일:** `packages/web/lib/supabase/types.ts` (2026-04-04 재생성, `supabase gen types` 기반)
**Client 파일:** `packages/web/lib/supabase/warehouse.ts`

---
Expand Down Expand Up @@ -335,6 +338,38 @@ Seed post의 아카이브된 이미지 에셋.

---

## App 스키마 FK 컬럼 (warehouse 참조)

PR #69 / SeaORM migration `m20260402_000001_add_warehouse_fk_posts_solutions`에서 추가됨.
`public` 스키마(앱 데이터)의 테이블에 warehouse 엔티티 FK를 연결한다.

### `public.posts` 추가 컬럼

| Column | Type | Constraint | Note |
|--------|------|------------|------|
| `artist_id` | uuid | nullable, FK → `warehouse.artists.id` ON DELETE SET NULL | `artist_name`에서 이름 매칭으로 백필됨 |
| `group_id` | uuid | nullable, FK → `warehouse.groups.id` ON DELETE SET NULL | `group_name`에서 이름 매칭으로 백필됨 |

인덱스: `idx_posts_artist_id`, `idx_posts_group_id`

### `public.solutions` 추가 컬럼

| Column | Type | Constraint | Note |
|--------|------|------------|------|
| `brand_id` | uuid | nullable, FK → `warehouse.brands.id` ON DELETE SET NULL | `metadata.brand` 또는 `title` prefix 매칭으로 백필됨 |
| `price_amount` | numeric(12,2) | nullable | 상품 가격 (2026-04-04 추가) |
| `price_currency` | varchar(10) | nullable, DEFAULT 'KRW' | 통화 코드 (2026-04-04 추가) |

인덱스: `idx_solutions_brand_id`

### 백필 전략

- `posts.artist_id`: `artist_name` → `warehouse.artists.name_ko / name_en` (unaccent + lower 정규화, 고유 매칭만)
- `posts.group_id`: `group_name` → `warehouse.groups.name_ko / name_en` (동일 방식)
- `solutions.brand_id`: `metadata->>'brand'` 값 우선, 없으면 `title` prefix로 `warehouse.brands` 매칭

---

## Type Aliases

`warehouse-types.ts`에서 export하는 편의 타입:
Expand Down
101 changes: 99 additions & 2 deletions docs/agent/web-hooks-and-stores.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ Paths below are under `packages/web/` unless absolute from repo root.
| Area | Location | Description |
| ------------------ | ----------------------------------- | ------------------------------------------------------------ |
| **Auth** | `lib/stores/authStore.ts` | OAuth (Kakao, Google, Apple) + session |
| **Search State** | `lib/stores/searchStore.ts` | Search query, filters, results |
| **Search State** | `lib/stores/searchStore.ts` | Search query, debouncedQuery, filters (category/mediaType/context/sort), page; re-exported from `@decoded/shared` |
| **Filter** | `lib/stores/filterStore.ts` | Category filter key (all/fashion/beauty/…); re-exported from `@decoded/shared` |
| **Behavior** | `lib/stores/behaviorStore.ts` | Behavioral tracking state |
| **VTON** | `lib/stores/vtonStore.ts` | Virtual try-on state |
| **Collection** | `lib/stores/collectionStore.ts` | Collection/studio state |
| **Magazine** | `lib/stores/magazineStore.ts` | Magazine/editorial state |
| **Active Spot** | `lib/stores/activeSpotStore.ts` | Currently selected spot on image canvas |
| **Studio** | `lib/stores/studioStore.ts` | Studio/collage creation state |
| **Request** | `lib/stores/requestStore.ts` | Post request/upload flow state |
| **Transition** | `lib/stores/transitionStore.ts` | Page transition animation state |
| **API Client** | `lib/api/` | Backend API calls |
| **API Generated** | `lib/api/generated/` | Orval 자동 생성 — 절대 수동 편집 금지 (아래 섹션 참조) |
| **API Routes** | `app/api/v1/` | Next.js API proxy & server logic |
| **Supabase** | `lib/supabase/queries/` | DB queries (events, images, posts, profile, personalization) |
| **Shared Queries** | `packages/shared/supabase/queries/` | Cross-package queries (images, items) |
Expand All @@ -27,11 +33,84 @@ Paths below are under `packages/web/` unless absolute from repo root.
| **Git workflow** | `docs/GIT-WORKFLOW.md` | Branch, commit, PR conventions |
| **Code reviewer** | `.claude/agents/code-reviewer.md` | Repository code-review agent notes |

## Generated API (Orval + Zod)

> `lib/api/generated/`는 **자동 생성 코드** — 절대 수동 편집하지 않는다. Gitignored (`.gitkeep`만 트래킹).

### Source of truth

`packages/api-server/openapi.json` (Rust backend utoipa에서 생성)

### 재생성

```bash
cd packages/web && bun run generate:api
```

### 구조

```
lib/api/
├── generated/ # Orval 자동 생성 (수동 편집 금지)
│ ├── models/ # TypeScript 인터페이스 (response/request types)
│ ├── admin/ # Admin endpoint hooks (useListAdminPosts 등)
│ ├── posts/ # Posts endpoint hooks (useListPosts 등)
│ ├── search/ # Search endpoint hooks
│ ├── solutions/ # Solutions endpoint hooks
│ ├── spots/ # Spots endpoint hooks
│ ├── users/ # Users endpoint hooks
│ ├── zod/ # Zod 스키마 (decodedApi.zod.ts — 전체 ��드포인트 검증)
│ └── ... # 태그별 분리 (badges, categories, rankings 등)
├── mutator/
│ └── custom-instance.ts # Axios 인스턴스 커스텀 (baseURL, 인터셉터)
├── server-instance.ts # 서버 컴포넌트용 API 클라이언트
└── adapters/ # API 응답 → UI 모델 변환
```

### Orval 설정 (`orval.config.ts`)

| 설정 | 값 |
|------|-----|
| **Input** | `../api-server/openapi.json` |
| **Output mode** | `tags-split` (태그별 파일 분리) |
| **Client** | `react-query` (TanStack Query 5) |
| **HTTP client** | `axios` (custom-instance.ts mutator) |
| **Zod output** | `lib/api/generated/zod/` (별도 client: zod) |
| **제외 엔드포인트** | multipart POST 4개 (create_post, with-solutions, upload, analyze) |

### 사용 패턴

```ts
// Hook import (태그/operationId 기반)
import { useListPosts } from "@/lib/api/generated/posts/posts";

// Zod 스키마 import
import { listPostsQueryParams } from "@/lib/api/generated/zod/decodedApi.zod";

// Type import
import type { PaginatedResponsePostListItem } from "@/lib/api/generated/models";
```

### 새 엔드포인트 추가 시

1. Backend에서 OpenAPI spec 업데이트
2. `packages/api-server/openapi.json` 복사
3. `cd packages/web && bun run generate:api`
4. `@/lib/api/generated/{tag}/{operationId}`에서 생성된 hook import

### 동작 확장

- **Axios 인터셉터**: `lib/api/mutator/custom-instance.ts` 편집
- **Orval 설정**: `orval.config.ts` 편집
- **생성 코드 자체**: 절대 편집하지 않음

---

## Custom hooks

### Data fetching

- `useImages()` - Fetch and paginate images with filters
- `useImages()` / `useInfinitePosts()` - Fetch and paginate images/posts with filters
- `usePosts()` - Fetch and manage posts
- `useProfile()` - Fetch user profile data
- `useCategories()` - Fetch category list
Expand All @@ -41,11 +120,15 @@ Paths below are under `packages/web/` unless absolute from repo root.
- `useSpots()` - Fetch spot data for images
- `useComments()` - Fetch and manage comments
- `useTries()` - Fetch try-on results
- `useTrendingArtists()` - Fetch trending artist list
- `useExploreData()` - Unified explore hook: switches between browse mode (Supabase) and search mode (Meilisearch via `/api/v1/search`); exposes `mode`, artist/context facets, multi-select artist filter, sort, and pagination

### Social actions

- `usePostLike()` - Like/unlike posts
- `useSavedPost()` - Save/unsave posts
- `useReport()` - Submit content reports
- `useAdoptDropdown()` - Adopt a solution from dropdown

### Behavioral tracking

Expand All @@ -59,6 +142,7 @@ Paths below are under `packages/web/` unless absolute from repo root.
- `useImageUpload()` - Image uploads with compression
- `useSearch()` - Search with debouncing
- `useSearchURLSync()` - URL-based search state sync
- `usePretext()` - Pretext/context text generation

### UI & animation

Expand All @@ -68,6 +152,15 @@ Paths below are under `packages/web/` unless absolute from repo root.
- `useMediaQuery()` - Responsive breakpoint detection
- `useSpotCardSync()` - Sync spot selection with card UI
- `useDebounce()` - Debounce value changes
- `useItemCardGSAP()` - GSAP animation for item cards
- `useImageDimensions()` - Get image natural dimensions
- `useImageModalAnimation()` - Lightbox/modal open-close animation

### VTON

- `useVtonTryOn()` - Submit and poll VTON job
- `useVtonItemFetch()` - Fetch items compatible with VTON
- `useVtonScrollLock()` - Lock scroll while VTON modal is open

### Admin

Expand All @@ -76,3 +169,7 @@ Paths below are under `packages/web/` unless absolute from repo root.
- `useDashboard()` - Dashboard statistics
- `usePipeline()` - Pipeline monitoring
- `useServerLogs()` - Server log streaming
- `useAdminPosts()` / `useAdminPostEdit()` - Admin post list and metadata editing
- `useAdminReports()` - Admin content report list
- `useEditorialCandidates()` - Posts eligible for editorial promotion
- `useAdminPickList()` / `useCreatePick()` / `useUpdatePick()` / `useDeletePick()` - Decoded Pick CRUD (from `lib/hooks/admin/useAdminPicks.ts`)
28 changes: 24 additions & 4 deletions docs/agent/web-routes-and-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,51 @@ App Router 기준 (`packages/web/app/`). 작업 시 이 표와 실제 `app/` 트

| Route | Description |
| -------------------- | ---------------------------------------------------------------------------------- |
| `/` | Home - Hero carousel, trending, best sections, celebrity grid |
| `/explore` | Grid view with category filtering |
| `/` | Home — HeroItemSync, TrendingPostsSection, HelpFindSection, EditorialMagazine, DecodedPickSection, MasonryGrid, DomeGallerySection |
| `/explore` | Grid view with Meilisearch search, hierarchical filters, artist/context facets |
| `/feed` | Social feed timeline |
| `/search` | Full-screen overlay search with multi-tab results |
| `/images` | Image discovery grid with infinite scroll |
| `/posts/[id]` | Post detail (Lightbox, hero, related items, shop grid, comments, AI summary, try) |
| `/profile` | User profile with activity, badges, tries, stats, rankings, style DNA, collections |
| `/editorial` | Daily editorial page with curated content |
| `/magazine/personal` | Personal magazine issue viewer with decoding ritual |
| `/admin` | Admin dashboard (AI cost, audit, content, pipeline, server logs) |
| `/admin` | Admin dashboard (AI cost, audit, content, pipeline, server logs, picks) |
| `/admin/login` | Admin email/password login (exempted from proxy.ts auth middleware) |
| `/admin/content` | Content management — post visibility, status control |
| `/admin/editorial-candidates` | Posts eligible for editorial promotion (spot ≥ 4, solution ≥ 1/spot) |
| `/admin/picks` | Decoded Pick curation — create/edit daily curated picks |
| `/request/upload` | Image upload with DropZone |
| `/request/detect` | AI detection results with item spotting |
| `/login` | OAuth authentication (Kakao, Google, Apple) |
| `/debug/supabase` | Supabase debug tools |
| `/lab/*` | Experimental (ascii-text, fashion-scan) |

## Main page sections (`/`)

Sections rendered in order:

| Component | Description |
| --------- | ----------- |
| `HeroItemSync` | Hero carousel synced with item annotations; slides through recent + popular posts |
| `TrendingPostsSection` | Horizontal scroll of trending (popular) posts — up to 16 cards |
| `HelpFindSection` | Posts where `created_with_solutions = false` — community sourcing |
| `EditorialMagazine` | Magazine-style cards from posts with `post_magazine_title` |
| `DecodedPickSection` | Daily curated pick with style card + item grid; sourced from `decoded_picks` table |
| `MasonryGrid` | Masonry layout of popular posts (up to 16) |
| `DomeGallerySection` | Dome/panoramic gallery of popular post images (up to 20) |

## Key feature areas

- **Editorial & Magazine**: AI-curated editorial content, personal magazine issues, decoding ritual animations
- **Explore Search**: Meilisearch full-text search via `/api/v1/search` proxy; falls back to Supabase ilike. `useExploreData` hook switches between browse/search modes. Artist facets (client-side multi-select) and context filter (server-side).
- **Decoded Pick Curation**: Daily curated post managed from `/admin/picks`. `DecodedPickSection` on homepage displays the active pick with spot annotations and item cards.
- **Social Actions**: Like, save, comment on posts with real-time counts
- **Virtual Try-On (VTON)**: AI-powered virtual try-on with lazy-loaded modal
- **Behavioral Intelligence**: Event tracking (dwell time, scroll depth), personalization engine
- **Collection & Studio**: Boards, bookshelf, collage views, pins, issue management
- **Admin Dashboard**: AI cost tracking, audit logs, pipeline monitoring, server logs streaming
- **Admin Dashboard**: AI cost tracking, audit logs, pipeline monitoring, server logs streaming, editorial candidates, picks management
- **Error Handling**: `app/error.tsx` (route-level 500, inside layout, reports to Sentry), `app/global-error.tsx` (top-level fallback)
- **Design System v2.0**: 36 components with comprehensive token system

Next.js API proxy 목록은 [api-v1-routes.md](api-v1-routes.md)를 참고합니다.
Loading