Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3cdec48
Make the final Shorts journey available from every screen
ark1st Aug 17, 2026
a5a4953
Show the updated MapleWind icon in the deployed app
ark1st Aug 17, 2026
4b20d2e
Keep character exports and Shorts tied to the source content
ark1st Aug 17, 2026
ef1414b
Put free play before the team message in mobile navigation
ark1st Aug 17, 2026
caf3239
Make the mobile playback shortcut start from the oldest record
ark1st Aug 17, 2026
1de6f7d
Make mobile sharing invoke the native share sheet
ark1st Aug 17, 2026
0436aab
Give shared links a real MapleWind identity
ark1st Aug 17, 2026
f75acae
Use the real MapleWind mark in shared previews
ark1st Aug 17, 2026
953d9d0
Keep team-message media proportionate on every viewport
ark1st Aug 22, 2026
5fe881b
Let the MapleWind favicon blend with the browser chrome
ark1st Aug 22, 2026
b3f5b0f
Serve the transparent favicon from the browser fallback path
ark1st Aug 22, 2026
4b9af31
Let the 14th cohort recognize its emergency committee by nickname and…
ark1st Aug 22, 2026
47cb3db
Make new interface releases visible without stale shell HTML
ark1st Aug 22, 2026
dc07268
Clarify the club identity on the committee channel
ark1st Aug 23, 2026
7f60d36
Simplify login and committee navigation
ark1st Aug 23, 2026
34aa431
Remove search from the committee channel
ark1st Aug 23, 2026
0963542
Show complete multiline recap captions
ark1st Aug 23, 2026
210c31a
Give Shorts explicit playback control and visible BGM identity
ark1st Aug 23, 2026
3a4af10
Keep the MapleWind wordmark subordinate to content
ark1st Aug 23, 2026
c8acba1
Give the favicon mark more breathing room
ark1st Aug 23, 2026
b2e3fdb
Keep the Shorts journey moving after each soundtrack
ark1st Aug 23, 2026
db49974
Make MapleWind recognizable at a glance in navigation
ark1st Aug 23, 2026
6450c17
Keep the established MapleWind identity in the new wordmark
ark1st Aug 23, 2026
669e061
Preserve the legacy MapleWind wordmark beside the new app mark
ark1st Aug 23, 2026
7ebaf7b
Balance the legacy wordmark against the app icon
ark1st Aug 23, 2026
aa7b8b3
Keep the home feed framed as Shorts instead of worlds
ark1st Aug 23, 2026
55d6c12
Let desktop viewers enter the chronological Shorts journey
ark1st Aug 23, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dist/
.env.*
!.env.example
!dpbr_front/app/.env.example
!dpbr_front/app/.env.production

# Logs
logs
Expand Down
90 changes: 90 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Design

## Source of truth
- Status: Active
- Last refreshed: 2026-08-23
- Primary product surfaces: 홈 피드, 멤버 쇼츠, 멤버 상세, 운영진 한마디, 결산별 댓글, 날짜순 재생, 이미지 저장, 쇼츠 BGM 재생·정보
- Evidence reviewed: `README.md`, `prompt/dpbr_front/plan.md`, `dpbr_front/app/src/routes/+layout.svelte`, `dpbr_front/app/src/routes/+page.svelte`, `dpbr_front/app/src/routes/member/[id]/save/+page.svelte`, `dpbr_front/app/src/lib/components/Header.svelte`, `BottomNav.svelte`, `GuideRail.svelte`, `VideoCard.svelte`, `app.css`, 백엔드 캐릭터 컨트롤러·서비스·저장소와 결산 API 스키마

## Brand
- Personality: 동아리 구성원의 게임 활동을 가볍고 친근하게 돌아보는 커뮤니티
- Trust signals: 실제 캐릭터 정보, 획득 일자, 운영진 전용 콘텐츠의 명확한 구분
- Avoid: 같은 목적지의 중복 내비게이션, 핵심 콘텐츠를 가리는 장식, YouTube 명칭의 불필요한 직역

## Product goals
- Goals: 이름·닉네임·결산 내용 통합 검색, 멤버별 활동 결산 탐색, 운영진 공지 확인, 날짜순·랜덤 결산 감상, 각 결산에 귀속된 댓글 참여, 쇼츠 BGM의 직접 재생 제어와 곡 정보 확인, 멤버의 14기 활동을 한 장의 캐릭터 카드로 저장·공유
- Non-goals: 범용 동영상 플랫폼, 전역 톡 또는 실시간 채팅 서비스 구현
- Success signals: 모바일·데스크톱 상단에서 이름·닉네임·쇼츠 제목/설명으로 멤버를 찾을 수 있고, 모바일 날짜순 재생으로 오래된 결산부터 감상하며 각 쇼츠에서 해당 결산의 댓글만 조회·작성·삭제할 수 있음

## Personas and jobs
- Primary personas: COMMUNITY_PROJECT 동아리원과 활동 기록을 둘러보는 방문자
- User jobs: 이름·닉네임·기억나는 결산 내용으로 구성원 기록 검색, 운영진 메시지 확인, 날짜순 또는 랜덤으로 결산 감상, 현재 결산에 댓글 작성·조회
- Key contexts of use: 세로형 모바일 화면과 데스크톱 브라우저

## Information architecture
- Primary navigation: 모바일 하단의 홈, 날짜순 재생, 운영진 한마디, 내 페이지 4개 항목과 데스크톱 가이드 레일
- Core routes/screens: `/`, `/shorts/[id]`, `/member/[id]`, `/member/admin-team`, `/member/[id]/save`
- Content hierarchy: 홈 상단은 브랜드와 검색 진입 아이콘만 노출한다. 운영진 한마디는 모바일 하단과 데스크톱 가이드 레일에서 진입한다. 전역 톡 화면은 두지 않고 현재 쇼츠의 우측 액션 레일에서 결산별 댓글 시트를 연다. 영상 썸네일에는 서버·레벨 대신 `결산 N개`만 표시한다.

## Design principles
- 한 기능은 한 위치에서 명확하게 찾을 수 있도록 중복 진입점을 줄인다.
- 운영진 한마디는 모바일 하단과 데스크톱 가이드 레일에서 찾을 수 있게 하고, 모바일 상단에는 중복 진입점을 두지 않는다.
- 검색은 제출된 하나의 질의를 이름·닉네임·쇼츠 제목/설명에 동일하게 적용하며, URL의 `q` 파라미터로 공유·복원이 가능하게 한다.
- 모바일은 YouTube의 축약형 헤더 패턴처럼 기본 상태에 돋보기만 두고, 클릭할 때 `뒤로가기 + 검색 입력 + 검색 버튼`으로 전환한다.
- 영상 카드의 오버레이 정보는 콘텐츠 양처럼 탐색 결정에 직접 필요한 정보만 남긴다.
- 모바일 하단은 빈 슬롯 없는 균등한 4버튼 구조로 구성한다. 네 탭은 동일한 64px 높이, 24px 아이콘, 라벨 기준선을 사용하며 특정 탭만 원형 배경이나 돌출 형태로 강조하지 않는다. 모바일 `날짜순 재생`은 가장 오래된 결산부터 시작하고, 데스크톱 `자유 재생`은 전체 결산 중 하나를 무작위로 골라 해당 쇼츠 딥링크를 연다.
- 현재 쇼츠의 재생·일시정지는 영상 위의 명시적인 원형 버튼과 미디어 영역 탭으로 동일하게 제어하며, 음소거 상태와 독립적으로 동작한다. 사용자가 직접 멈춘 음원은 댓글 창이나 탭 전환 뒤에 임의로 다시 재생하지 않는다.
- 현재 BGM은 하단 정보 스택의 `음표 + 곡명 · 아티스트` 필로 노출하고, 선택하면 전체 곡명·재생 구간·검증된 원본 주소를 확인한다. 파일명이나 YouTube ID를 사용자용 곡명으로 대신 표시하지 않는다.
- 댓글은 전역 대화방이 아니라 현재 Settlement에 귀속한다. 쇼츠를 벗어나지 않고 YouTube 댓글 문법의 하단 시트로 조회·작성·삭제한다.
- 캐릭터 저장 카드는 YouTube 채널의 `16:9 배너 + 원형 프로필 + 채널명/핸들 + 콘텐츠 통계` 문법을 9:16 공유 이미지 안에 재구성한다.
- 캐릭터 원본 이미지를 세로 배경으로 과도하게 확대·크롭하지 않고, 대표 결산은 16:9 프레임에 `object-fit: contain`으로 온전히 보여준다.
- Tradeoffs: 모바일 상단을 검색 중심으로 단순화하는 대신 운영진 콘텐츠는 하단 내비게이션에서 지속적으로 접근할 수 있게 한다.

## Visual language
- Color: `app.css`의 `--yt-*` 시맨틱 토큰을 사용하며 라이트·다크 테마를 함께 지원한다. 저장 카드는 테마와 무관하게 YouTube 다크 표면(`#0f0f0f`, `#212121`)과 단풍바람 레드 포인트를 사용한다.
- Typography: GAME_API_PROVIDER Lv1 Gothic과 시스템 폰트 폴백
- Spacing/layout rhythm: 모바일 하단 내비게이션과 데스크톱 가이드 레일의 기존 간격 유지
- Shape/radius/elevation: 기존 원형 액션과 둥근 표면 토큰 재사용
- Motion: 기존 hover, active, snap 동작 유지; 불필요한 전환 추가 금지
- Imagery/iconography: Lucide 아이콘과 프로젝트 로고 자산 재사용. 빨간 파비콘 안의 단풍바람 심볼은 캔버스 가장자리와 충분한 여백을 두어 작은 브라우저 탭에서도 답답해 보이지 않게 한다. 탐색 헤더는 YouTube 워드마크 문법처럼 `빨간 단풍바람 심볼 + 굵은 단풍바람 텍스트`를 한 덩어리로 표시하며, 쇼츠 위에서는 텍스트를 흰색으로 전환한다.

## Components
- Existing components to reuse: `BrandWordmark`, `Header`, `BottomNav`, `GuideRail`, `VideoCard`, `ShortsThumbnail`, `CommentItem`, `BottomSheetLogin`
- New/changed components: `BottomNav` 4버튼 구조와 날짜순 재생 액션, `Header`의 검색 중심 모바일 상단, `GuideRail` 자유 재생 행, 쇼츠 우측 댓글 액션과 `SettlementCommentsSheet`, 쇼츠 재생·일시정지 컨트롤과 `AudioInfoSheet`, `VideoCard`의 결산 개수 배지, 9:16 `단풍바람 14기 캐릭터 카드`
- Variants and states: 모바일 검색 닫힘/열림, 활성 경로, 날짜순·자유 재생 조회 중, 댓글 시트 닫힘/열림, BGM 재생/일시정지/종료/자동재생 차단/오류, BGM 정보 시트 닫힘/열림, 댓글 로딩·비어 있음·오류·작성 중, 검색 중 로딩, 검색 결과 없음, API 오류 토스트
- Token/component ownership: 색상은 `app.css`, 내비게이션 동작은 `src/lib/utils/nav.ts`

## Accessibility
- Target standard: 기존 의미론을 유지하며 WCAG 2.1 AA를 지향
- Keyboard/focus behavior: 검색 폼은 Enter 제출을 지원하고, 링크와 버튼의 네이티브 키보드 동작 및 명확한 `aria-label` 유지
- Contrast/readability: `--yt-text`, `--yt-text-muted`, `--yt-border` 토큰 사용
- Screen-reader semantics: 운영진 한마디, 날짜순 재생, 현재 결산 댓글, BGM 재생 상태, BGM 정보와 `이름, 닉네임, 내용 검색`의 목적을 한국어 접근성 이름으로 제공
- Reduced motion and sensory considerations: 새 자동 애니메이션을 추가하지 않음

## Responsive behavior
- Supported breakpoints/devices: 최소 320px 모바일부터 `lg` 이상 데스크톱
- Layout adaptations: 모바일은 축약형 상단 검색과 하단 내비게이션, 데스크톱은 항상 보이는 상단 검색과 접이식 좌측 가이드 레일. 캐릭터 카드는 화면에서는 최대 360px로 축소하되 저장 결과는 720×1280 PNG를 기준으로 한다.
- Touch/hover differences: 재생·음소거 버튼은 최소 44px 터치 영역을 보장하고 데스크톱에만 hover 피드백을 추가한다.

## Interaction states
- Loading: 검색 질의가 바뀌면 목록 영역에서 기존 로딩 안내 제공
- Empty: 통합 검색 결과가 없으면 `검색 결과가 없습니다.`를 제공
- Error: 쇼츠 조회 실패 토스트 및 콘솔 진단 정보 유지
- Success: 날짜순 재생은 가장 오래된 Settlement부터 시작하고 회원 피드 종료 뒤에는 랜덤 피드를 이어 붙인다. 재생 버튼은 일시정지 위치에서 이어 재생하며, 음원 구간이 끝나면 0.5초 뒤 다음 결산으로 자동 이동한다. 사용자가 직접 일시정지한 경우에는 자동 이동하지 않는다. BGM 정보 버튼은 현재 Settlement의 메타데이터와 재생 구간을 표시한다. 댓글 작성 즉시 현재 결산 댓글 목록 맨 위에 표시하고, 캐릭터 카드는 저장 완료 토스트와 함께 PNG를 내려받는다.
- Disabled: 날짜순·자유 재생 조회, 댓글 제출, 이미지 생성 중 중복 실행을 차단하고 시각적 진행 상태를 제공한다.
- Offline/slow network, if applicable: 현재 화면을 유지하며 실패 토스트 또는 쇼츠 내부 음원 오류 상태를 표시한다.

## Content voice
- Tone: 짧고 친근한 한국어
- Terminology: 사용자 노출 명칭은 `운영진 한마디`, 모바일 `날짜순 재생`, 데스크톱 `자유 재생`, `댓글`, `결산 N개`로 통일하고 `톡`은 사용하지 않는다.
- Microcopy rules: 동작과 목적지가 한 번에 이해되는 명사형 라벨을 사용하고 검색 입력에는 `이름, 닉네임, 내용 검색`을 표시한다. 저장 결과의 명칭은 `단풍바람 14기 캐릭터 카드`, 동아리 설명은 `가천대 메이플스토리 동아리`로 통일한다.

## Implementation constraints
- Framework/styling system: SvelteKit 2, Svelte 5, TypeScript, Tailwind CSS 4
- Design-token constraints: 기존 `--yt-*` 토큰과 컴포넌트 유틸리티 클래스를 우선 사용
- Performance constraints: 카드별 결산 개수는 N+1 요청 없이 캐릭터 조회에 포함하며, 검색은 페이지네이션 쿼리에서 결산 콘텐츠 존재 조건으로 처리해 클라이언트 전체 로드를 피함
- Compatibility constraints: 정적 어댑터와 클라이언트 내비게이션을 유지하고, BGM 곡명·아티스트·원본 주소는 백엔드 Settlement API의 nullable 메타데이터 필드에서 받는다.
- Test/screenshot expectations: `npm run check`, `npm run build`, 모바일·데스크톱 브라우저 스모크 확인

## Open questions
- 현재 없음
10 changes: 10 additions & 0 deletions dpbr_front/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ FROM node:20-alpine AS builder

WORKDIR /app

ARG PUBLIC_API_URL=/api
ARG PUBLIC_API_PREFIX=/v1
ARG PUBLIC_KAKAO_CLIENT_ID=
ARG PUBLIC_KAKAO_REDIRECT_URI=

ENV PUBLIC_API_URL=$PUBLIC_API_URL \
PUBLIC_API_PREFIX=$PUBLIC_API_PREFIX \
PUBLIC_KAKAO_CLIENT_ID=$PUBLIC_KAKAO_CLIENT_ID \
PUBLIC_KAKAO_REDIRECT_URI=$PUBLIC_KAKAO_REDIRECT_URI

# 의존성 파일 복사 및 설치
COPY app/package*.json ./
RUN npm ci
Expand Down
2 changes: 1 addition & 1 deletion dpbr_front/app/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# API 백엔드 URL
# 개발 환경: http://localhost:8000
# 프록시 prefix 환경 예시: /msgs14_dev/api
# 프록시 prefix 환경: /msgs13_dev/api
PUBLIC_API_URL=http://localhost:8000
# API 라우터 prefix (백엔드 API_V1_PREFIX와 동일하게 맞춤)
PUBLIC_API_PREFIX=/api/v1
Expand Down
7 changes: 7 additions & 0 deletions dpbr_front/app/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
.env
.env.*
!.env.example
node_modules/
.svelte-kit/
build/
dist/
.DS_Store
52 changes: 1 addition & 51 deletions dpbr_front/app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions dpbr_front/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
"vite": "^6.0.0"
},
"dependencies": {
"html-to-image": "^1.11.11",
"html2canvas": "^1.4.1"
"html-to-image": "^1.11.11"
},
"type": "module"
}
}
90 changes: 70 additions & 20 deletions dpbr_front/app/src/app.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
@import "tailwindcss";

:root {
color-scheme: light;
}
@custom-variant dark (&:where(.dark, .dark *));

@font-face {
font-family: 'GAME_API_PROVIDERLv1Gothic';
Expand All @@ -25,29 +23,71 @@
font-display: swap;
}

@theme {
--color-primary: #fac486;
--color-primary-dark: #ff8e42;
--color-secondary: #FFE0B2;
--color-bg-app: #FFF3E0;
--color-bg-card: #ffffff;
--color-bg-light: #f7f9fa;
--color-border: #edf1f5;
--color-border-dark: #e1e8ee;
--color-text-primary: #292e33;
--color-text-secondary: #6c7680;
--color-text-muted: #98a5b3;
--color-text-accent: #525c66;
--color-bg-overlay: #101010;
/* 유튜브 스타일 시맨틱 토큰 — 라이트 */
:root {
color-scheme: light;
--yt-bg: #ffffff;
--yt-surface: #f2f2f2;
--yt-surface-hover: #e5e5e5;
--yt-text: #0f0f0f;
--yt-text-muted: #606060;
--yt-border: #e5e5e5;
--yt-accent: #ff0000;
--yt-chip: #f2f2f2;
--yt-chip-active: #0f0f0f;
--yt-chip-active-text: #ffffff;
}

/* 유튜브 스타일 시맨틱 토큰 — 다크 */
.dark {
color-scheme: dark;
--yt-bg: #0f0f0f;
--yt-surface: #212121;
--yt-surface-hover: #3d3d3d;
--yt-text: #f1f1f1;
--yt-text-muted: #aaaaaa;
--yt-border: #303030;
--yt-accent: #ff0000;
--yt-chip: #272727;
--yt-chip-active: #f1f1f1;
--yt-chip-active-text: #0f0f0f;
}

@theme inline {
--color-yt-bg: var(--yt-bg);
--color-yt-surface: var(--yt-surface);
--color-yt-surface-hover: var(--yt-surface-hover);
--color-yt-text: var(--yt-text);
--color-yt-text-muted: var(--yt-text-muted);
--color-yt-border: var(--yt-border);
--color-yt-accent: var(--yt-accent);
--color-yt-chip: var(--yt-chip);
--color-yt-chip-active: var(--yt-chip-active);
--color-yt-chip-active-text: var(--yt-chip-active-text);

/* 기존 토큰 재매핑 (미수정 화면 안전망) */
--color-primary: var(--yt-chip);
--color-primary-dark: var(--yt-accent);
--color-secondary: var(--yt-surface);
--color-bg-app: var(--yt-bg);
--color-bg-card: var(--yt-bg);
--color-bg-light: var(--yt-surface);
--color-border: var(--yt-border);
--color-border-dark: var(--yt-border);
--color-text-primary: var(--yt-text);
--color-text-secondary: var(--yt-text-muted);
--color-text-muted: var(--yt-text-muted);
--color-text-accent: var(--yt-text-muted);
--color-bg-overlay: #0f0f0f;
}

html,
body {
font-family: 'GAME_API_PROVIDERLv1Gothic', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: white;
color: var(--color-text-primary);
background-color: var(--yt-bg);
color: var(--yt-text);
}

/* 상호작용 가능한 요소들에 손가락 커서 강제 적용 */
Expand All @@ -64,4 +104,14 @@ input[type="button"]:disabled,
input[type="submit"]:disabled,
input[type="reset"]:disabled {
cursor: not-allowed;
}
}

/* 쇼츠 뷰어 등 가로 snap 컨테이너의 스크롤바 숨김 */
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}

.no-scrollbar::-webkit-scrollbar {
display: none;
}
Loading