Files
basket_utils/SERVER-SETUP.md
T

152 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fastify · MongoDB 실행 안내
## 저장소
사용자가 지정한 MongoDB 서버는 `172.16.0.7:27017`, 프로젝트 DB는 `basket_utils`다. SQLite 선택은 이 설정으로 대체한다. 서버는 MongoClient 연결 풀을 재사용한다.
프로젝트 루트 `.config.json`에서 설정을 관리한다. 예시는 `.config.json.sample`에 있으며 새 환경에서는 복사해 사용한다. 기존 설정 파일이 있으면 덮어쓰지 않는다.
```powershell
Copy-Item .config.json.sample .config.json
```
```json
{
"mongodb": {
"uri": "mongodb://172.16.0.7:27017",
"db": "basket_utils"
},
"server": {
"host": "0.0.0.0",
"port": 3000,
"mode": "development",
"allowedOrigins": [
"http://localhost:5173",
"http://127.0.0.1:5173",
"http://192.168.5.10:5173"
],
"secureCookie": false
},
"bootstrap": { "password": "" },
"qa": { "db": "basket_utils_qa", "password": "" }
}
```
MongoDB 인증 정보가 필요하면 `mongodb.uri`에 설정한다. 실제 `.config.json`은 Git 추적에서 제외하고 예시 파일에는 비밀번호를 넣지 않는다. 설정 변경 후 서버를 재시작한다.
## 개발 실행
```powershell
npm install
npm run dev
```
Vite 화면은 PC에서 `http://localhost:5173`, 같은 네트워크의 휴대폰에서 `http://192.168.5.10:5173`으로 접근한다. PC의 IP가 바뀌면 주소도 바뀐다. Vite의 `/api` 요청은 `server.port`에 지정한 Fastify 포트로 전달된다.
LAN 접속에는 Windows 방화벽과 공유기의 기기 간 통신 허용도 필요하다. MongoDB 주소와 휴대폰이 접속할 웹 주소는 별개다.
## 최초 운영자
공개 기본 운영자 계정은 만들지 않는다. 사용할 이메일로 회원가입한 뒤, 서버 PC에서 해당 계정을 명시적으로 승격할 수 있다.
```powershell
node .\server\bootstrap-admin.js --email=your-email@example.com --promote-existing
```
`your-email@example.com`을 실제 가입한 이메일로 바꾼다. 기존 비밀번호는 유지된다. 이후 `/admin`에서 운영자 계정으로 로그인하여 다른 사용자의 가입 신청을 승인한다. 웹에서 최초 운영자 권한을 자동 부여하지 않는다.
PowerShell에서는 `npm.ps1`을 통해 실행할 때 옵션이 npm 자체 설정으로 해석되어 스크립트에 전달되지 않을 수 있으므로 위처럼 Node로 직접 실행한다. 명령 끝에 역슬래시(`\`)를 붙이지 않는다.
새 운영자를 직접 만들 때는 `.config.json``bootstrap.password`에 사용할 비밀번호를 일시적으로 설정하고 아래 명령을 실행한다. 실행 후 비밀번호 값은 다시 빈 문자열로 바꾼다.
```powershell
node .\server\bootstrap-admin.js --email=your-email@example.com
```
## 사용자 승인과 팀 참여
1. 최초 방문자는 로그인 화면에서 사용 신청으로 이동해 이메일·비밀번호·표시 이름을 등록한다.
2. 서비스 운영자는 별도 `/admin` 페이지에서 승인 대기 사용자를 확인하고 이용을 승인한다. 개발 주소는 `http://localhost:5173/admin`이며, 운영 환경에서는 서비스 주소 뒤에 `/admin`을 붙인다.
3. 승인된 사용자가 로그인하면 소속 팀이 있는 경우 **소속 팀**, 없는 경우 **팀 검색** 화면으로 진입한다. **소속 팀 | 팀 검색** 토글로 두 화면을 전환하며, 새 팀 만들기도 이용할 수 있다. 서비스 이용 승인만으로 기존 팀에 자동 가입되지 않는다.
4. 기존 팀을 검색해 가입을 신청하면 팀 소유자의 승인을 기다린다.
5. 팀 소유자는 팀원 관리에서 가입 신청을 승인하고 열람자 또는 편집자 권한을 부여한다. 이후에도 팀원별 권한을 변경할 수 있다.
운영자는 팀 선택·검색·팀원 관리·전술 목록 화면 우측 하단의 **운영자 승인 페이지** FAB로 가입 승인 페이지에 접근한다. 로그인 전과 승인 페이지, 전술 편집 화면에서는 FAB를 표시하지 않는다. 기존 `/admin` 직접 접근과 운영자 권한 검사는 유지한다.
2026-09-09 UX 검증: 운영 DB와 분리된 메모리 서버에서 PC 1280×900 및 모바일 390×844 화면을 확인했다. 소속 팀 유무에 따른 로그인·세션 복원 분기, 토글 클릭·방향키 전환, 팀 검색·가입 요청, 팀원 관리 복귀, 운영자 FAB의 승인 페이지 진입·새로고침·복귀, 로그아웃 및 일반 계정의 FAB 숨김과 `/admin` 접근 제한을 확인했다. 최종 전체 테스트 119개가 통과했다.
열람자는 팀 전술을 조회할 수 있고 서버에 저장할 수 없다. 편집자와 소유자는 팀 전술을 서버에 저장할 수 있다. 소유자 권한 이전은 지원하지 않는다. 서비스 운영자 권한과 팀 소유자 권한은 별개이며, 운영자도 다른 팀에 자동으로 참여하지 않는다.
가입 신청은 MongoDB `team_join_requests`에 저장한다. 서버 시작 시 필요한 컬렉션 인덱스를 준비하며, 기존 계정·팀·전술을 삭제하거나 다시 만들 필요는 없다. 코드 반영 후에는 서버를 재시작하고 운영 화면은 다시 빌드한다.
팀 검색은 이름 두 글자 이상으로 검색하며 한 번에 최대 20개를 표시한다. 가입 대기/승인 상태는 내 가입 요청에서 확인하고, 팀 목록 새로고침으로 최신 상태를 불러온다. 팀 소유자는 내 팀 아래의 **팀원 관리**에서 승인하고, 기존 팀원의 역할을 선택한 뒤 **역할 저장**을 누른다.
## 팀 전술 목록
로그인 → 팀 선택 → 전술 목록 → 저장된 전술 열기 또는 새 전술 시작 → 전술 캔버스 순서로 사용한다. 새 팀을 만든 경우에도 먼저 비어 있는 전술 목록으로 이동한다.
전술 목록에는 해당 팀의 저장된 전술 이름과 수정 시각을 표시한다. 새 전술은 이름과 수비 형태를 정한 뒤 시작하고, 캔버스에서 저장하면 서버 목록에 추가된다. 열람자는 기존 전술을 열 수 있지만 새 전술 생성과 서버 저장은 할 수 없다.
캔버스의 **전술 목록**으로 돌아오면 다른 전술을 선택할 수 있고, 목록의 **팀 목록으로**에서 팀을 바꿀 수 있다. 이 기기에 남은 임시 저장본은 별도의 **임시 저장 계속하기**로 연다. 저장된 전술의 열기 버튼은 서버에 저장된 내용을 불러온다.
2026-09-08 전술 목록 UX 검증: 메모리 QA 서버에서 팀 선택 후 목록 진입, 기존 전술 열기, 임시본 이어서 편집, 서버 저장본과 임시본 구분, 이름·수비 형태를 지정한 새 전술 생성/저장/목록 반영, 새 팀의 빈 목록, 열람자의 생성·저장 제한을 확인했다. PC 및 모바일 화면 크기에서 목록 배치를 확인했고 전체 테스트 115개와 빌드가 통과했다.
## 운영 실행
`.config.json``server.mode``production`, `server.allowedOrigins`를 실제 HTTPS 서비스 주소 배열, `server.secureCookie``true`로 설정한다.
```powershell
npm run build
npm run server
```
Fastify가 `dist` 화면과 API를 제공한다. 실제 도메인을 허용 출처로 설정하고 HTTPS 프록시 뒤에서 실행한다. 운영 세션 쿠키는 Secure를 사용한다.
로그인 세션은 1시간 동안 유지되며, 인증된 조회·저장 요청 및 전술판의 클릭·드래그·키보드 등 사용자 입력에 따라 서버 만료 시각과 쿠키 유효기간이 연장된다. 로컬 입력의 활동 알림은 요청 수를 제한해 전송하고, 입력 없이 화면만 열어 두면 주기적으로 연장하지 않는다. 만료된 세션은 활동 알림으로 복구되지 않으며 다시 로그인해야 한다. 이전 7일 세션에 활동 기록이 없으면 로그인 시각을 기준으로 1시간 만료를 적용한다.
휴대폰의 HTTP LAN 화면 접속만으로 OS 파일 공유 조건이 충족되지는 않는다. 카카오톡으로 MP4 파일을 직접 공유하는 실기기 검증에는 지원 브라우저와 신뢰할 수 있는 HTTPS가 필요하다.
## 검증
```powershell
npm test
npm run build
```
테스트 계정은 격리된 테스트 저장소에서 사용한다. 운영 `basket_utils` DB에 QA용 계정을 임의로 넣거나 기존 컬렉션을 삭제하지 않는다.
2026-09-08 검증 결과: 106개 테스트 및 빌드 통과. 별도 QA DB에서 로그인·승인·다중 팀 저장/전환과 서버 재시작 후 데이터 유지, PC/모바일 화면, MP4 생성·재생을 확인했다. 기존 번들 크기 경고는 남아 있다.
JSON 설정 전환 후에는 설정 로더 검증 5개와 정적 파일 보호 검증 1개를 추가해 총 112개 테스트와 빌드가 통과했다. 설정 파일이 없거나 JSON 구문·값 타입이 잘못되면 시작 시 오류를 안내하며, JSON 구문 오류에 설정 원문을 출력하지 않는다. 운영 모드에서는 Secure 쿠키가 강제되고 개발용 HTTP 출처는 허용하지 않는다.
QA seed 명령은 `basket_utils_qa` 또는 `basket_utils_qa_` 뒤에 영문·숫자·하이픈이 붙은 DB 이름만 허용한다. 이번 검증 DB는 `basket_utils_qa_20260908review`이며 테스트 데이터는 운영 DB와 분리되어 있다. QA 서버는 검증 후 종료했다.
### 팀 가입·관리 화면 추가 검증 (2026-09-08)
- 전체 테스트 115개 통과, 배포 빌드 및 `git diff --check` 통과. 기존 번들 크기 경고는 유지된다.
- 이번 화면 검증은 운영 MongoDB와 연결하지 않는 로컬 메모리 QA 서버에서 진행했다.
- 사용 신청 → 별도 `/admin` 로그인/승인 → 신청자 로그인 → 팀 검색/가입 신청 → 소유자 승인 → 열람자/편집자 역할 저장을 브라우저에서 확인했다.
- 가입 대기 상태의 새로고침 유지, 일반 계정의 관리자 페이지 접근 제한, 관리자 직접 로그인/새로고침/뒤로가기, 계정 전환 후 화면 초기화를 확인했다.
- 새 팀 생성, 편집자의 서버 저장, 열람자의 저장 버튼 비활성화와 서버 가져오기 대상 제외를 확인했다. 서버 테스트에서도 같은 세션의 역할 변경 이후 저장 권한을 검증한다.
- PC 1280×900 및 모바일 390×844 화면에서 가입 양식·승인·팀원 관리 배치를 확인했다. 모바일은 브라우저 화면 크기 검증이며 실물 휴대폰 검증은 아니다.
### 기존 편집 화면과 모바일 전체화면
- 로그인 후 팀을 선택하면 전술 목록을 먼저 표시한다. 저장된 전술을 열거나 이름과 수비 형태를 정해 새 전술을 시작한다.
- 일반 화면은 기존 선수 목록·행동 도구·단계/재생 UI를 유지한다. 기본 이동 모드에서 선수 드래그는 이동 행동을 기록하며, 명시적으로 `배치`를 선택했을 때만 시작 위치를 변경한다.
- 모바일 전체화면은 화면 배치만 바꾸며 현재 단계와 기록된 행동을 유지한다. 도구와 재생 UI는 코트 크기를 줄이지 않는 접이식 오버레이로 표시한다.
- 브라우저 전체화면은 사용자가 버튼을 눌렀을 때만 요청하고, 성공하면 가로 방향 잠금을 요청한다. 종료 시 잠금을 해제한다. 방향 잠금은 브라우저 지원에 따라 실패할 수 있으므로, 전체화면 편집 중 세로 화면에서는 회전 안내와 종료 버튼을 표시하고 편집 입력을 차단한다. 가로 화면이 되면 안내를 닫는다. 브라우저 자체 종료 안내의 표시 시간은 앱에서 제어하지 않는다.
- 패스는 현재 단계의 최종 공 소유 선수를 선택했을 때만 표시한다. 패스 후 기존 소유자의 패스·슛은 숨기고, 공을 받은 선수를 선택하면 표시한다.
- 전체화면 왼쪽은 선수 구성 버튼만 표시한다. 오른쪽 상단에는 저장·전체화면·메뉴, 하단에는 단계·행동 버튼을 배치한다. 행동 도구 모음과 별도의 실행 취소·다시 실행 도구박스는 오른쪽 중앙에 배치한다. 단계 패널은 최대 160px 폭으로 목록, 진행도, 재생 버튼을 세로로 배치하며 코트 크기를 바꾸지 않는다.
- 세로 일반 화면은 코트와 도구 영역을 실제 레이아웃으로 분리한다. `visualViewport.height` 변화를 반영해 주소창을 제외한 표시 높이에 화면을 맞추며, 페이지 스크롤 대신 패널 내부 스크롤을 사용한다. 가로 전체화면은 코트 전체를 좌우 도구 사이의 중앙 영역에 맞춰 가로로 늘려 표시한다. 끝선의 작은 안전 여백을 제외하고 중앙 영역을 채우며, 선수·경로·드래그는 같은 카메라 좌표계를 사용한다. 일반 화면과 영상 출력의 비율, 행동 편집의 경로·좌표·시선 설정은 유지한다.
- 재생 바는 이전·다음 버튼 사이의 폭을 사용하고, 현재 시간 / 전체 시간은 바 아래에 작은 중앙 정렬 자막으로 표시한다.
- 모바일 전체화면 진입 버튼은 저장 버튼과 구별되는 진한 청록색과 1.8초 주기의 부드러운 확대·축소 및 퍼지는 테두리로 표시한다. 전체화면 진입 후에는 강조 애니메이션을 멈추며, 동작 줄이기 설정에서는 색상만 강조한다. 전체화면 SVG와 선수 구성 아이콘은 버튼 중앙에 정렬한다.
이전의 전체 화면 공통 작전판/움직임 모드 분리는 요구 범위와 달라 철회했다.
2026-09-08 추가 수정 검증: 전체 118개 테스트와 빌드 통과. 메모리 QA 서버에서 390×844 세로 전체화면의 회전 안내·종료·편집 영역 inert 처리, 가로 전환 시 안내 해제, 844×390 및 740×360의 단계/행동 패널 동시 표시와 코트 크기 유지, 단계 추가, 드래그 기록과 실행 취소/다시 실행, 패스 후 공 소유권에 따른 패스·슛 표시를 확인했다. 740px 행동 패널의 가로 넘침도 수정했다. 일반 PC 1280×900과 모바일 화면의 기존 UI를 유지한다. 이 검증은 브라우저 화면 크기 검증이며 실물 휴대폰의 방향 잠금 성공을 보증하지 않는다.
2026-09-08 수정 검증: 전체 118개 테스트, 빌드, `git diff --check` 통과. 사용하지 않는 이전 모드 전용 함수와 해당 테스트는 제거했다. 메모리 QA 서버에서 연속 드래그로 두 구간 추가 → 한 구간 실행 취소/다시 실행 → 서버 저장 → 목록 복귀 → 재열기 후 같은 경로 유지까지 확인했다. 새 전술도 이동 모드로 시작하며 첫 드래그가 경로를 만든다.
1280×900 일반 화면은 기존 3열 UI를 유지하고 전체화면 버튼을 숨긴다. 390×844 일반 화면의 가로 넘침과 버튼 클릭 영역을 확인했다. 844×390 및 740×360 가로 전체화면에서는 도구·단계 목록을 함께 열어도 코트 영역 크기가 유지되고 선수 10명이 가려지지 않는다. 두 패널을 연 상태의 선수 드래그와 단계 추가, 전체화면 종료 후 현재 단계 유지, 재진입 시 재생 바 닫힘을 확인했다. 브라우저 자체 전체화면 진입과 QA 전용 `Permissions-Policy: fullscreen=()` 환경의 대체 화면을 각각 확인했다. 실물 휴대폰의 터치 감도와 브라우저 안내 지속 시간은 별도 확인 대상이다. 기존 번들 크기 경고는 유지된다.