Compare commits

..

2 Commits

Author SHA1 Message Date
57133a38db README.md 스펙 정리 2026-01-25 17:07:53 +09:00
c44bcb4a0f lotto lab API 정리
- API 스펙 정리 문서 업로드
 - 스펙 다운로드 기능 추가

나스 배포 오류 수정
2026-01-25 17:05:16 +09:00
6 changed files with 119 additions and 11 deletions

View File

@@ -1,16 +1,27 @@
# React + Vite
# Web UI
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
블로그, 로또 추천 실험, 여행 기록을 한 곳에서 모아 보는 개인 웹 UI입니다.
Currently, two official plugins are available:
## 블로그
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
- 마크다운 기반 글 작성 및 자동 목록화 (`src/content/blog`)
- 태그 기반 카테고리 분류와 카테고리별 목록 뷰
- 목록/본문 분리 UI, 페이지네이션 지원
- 인라인 스타일(링크/강조/코드/이미지) 렌더링 지원
## React Compiler
## Lotto Lab
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
- 최신 로또 결과 조회
- 추천 번호 생성 (가중치/최근 회차/회피 수 등 파라미터 반영)
- 프리셋 파라미터로 빠른 추천 생성
- 추천 히스토리 목록 확인 및 삭제
- 번호 복사 기능
- API 스펙 다운로드 링크 제공 (`public/lotto-api.md`)
## Expanding the ESLint configuration
## 여행 기록 (Travel Archive)
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
- 지도 기반 지역 선택 (GeoJSON)
- 선택한 지역의 사진 목록 로딩 및 캐시
- 스크롤 기반 사진 추가 로딩 (chunked lazy load)
- 썸네일/모달 뷰, 키보드/스와이프 네비게이션
- 앨범/파일 메타 정보 표시

View File

@@ -7,7 +7,7 @@
"dev": "vite",
"clean": "rimraf dist",
"build": "npm run clean && vite build",
"deploy:nas": "node -e 'const isWin = process.platform === \"win32\"; const src = \"dist\"; const dstWin = \"Z:\\\\docker\\\\webpage\\\\frontend\\\\\"; const dstMac = \"/Volumes/gahusb.synology.me/docker/webpage/frontend/\"; const dst = isWin ? dstWin : dstMac; const fs = require(\"fs\"); if (!fs.existsSync(src)) { console.error(\"dist not found. Run build first.\"); process.exit(1); } if (!fs.existsSync(dst)) { console.error(\"NAS path not found. Check mount: \" + dst); process.exit(1); } if (isWin) { const cmd = \"powershell -NoProfile -ExecutionPolicy Bypass -Command \\\"$ErrorActionPreference=\\\"Stop\\\"; $src=\\\"dist\\\"; $dst=\\\"Z:\\\\docker\\\\webpage\\\\frontend\\\\\\\"; if(!(Test-Path $src)){ throw \\\"dist not found. Run build first.\\\" }; if(!(Test-Path $dst)){ throw \\\"NAS drive not found. Check Z: mapping.\\\" }; robocopy $src $dst /MIR /R:1 /W:1 /E /NFL /NDL /NP; if($LASTEXITCODE -ge 8){ exit $LASTEXITCODE }\\\"\"; require(\"child_process\").execSync(cmd); } else { require(\"child_process\").execSync(\"rsync -av --delete --delete-delay --inplace dist/ \" + dst); }'",
"deploy:nas": "node scripts/deploy-nas.cjs",
"release:nas": "npm run build && npm run deploy:nas",
"lint": "eslint .",
"preview": "vite preview"

63
public/lotto-api.md Normal file
View File

@@ -0,0 +1,63 @@
# Lotto API 스펙 (프론트 참고)
## 추천 1개 생성
요청:
GET /api/lotto/recommend?recent_window=200&recent_weight=2.0&avoid_recent_k=5&sum_min=120&sum_max=180&max_overlap_latest=1
응답 핵심:
{
"id": 123,
"saved": true,
"deduped": false,
"numbers": [1,2,3,4,5,6],
"based_on_latest_draw": 1145,
"explain": {...},
"metrics": {...},
"recent_overlap": {...},
"params": {...}
}
## 히스토리 목록 (페이지/필터/검색)
기본: GET /api/history?limit=30&offset=0
즐겨찾기만: GET /api/history?favorite=true
태그 필터: GET /api/history?tag=jeju
메모 검색: GET /api/history?q=맛집
정렬: GET /api/history?sort=favorite_desc
응답:
{
"items": [
{
"id": 123,
"created_at": "...",
"numbers": [...],
"params": {...},
"based_on_draw": 1145,
"favorite": false,
"note": null,
"tags": [],
"metrics": {...},
"recent_overlap": {...}
}
],
"limit": 30,
"offset": 0,
"filters": {...}
}
## 히스토리 수정 (즐겨찾기/메모/태그)
요청:
PATCH /api/history/{id}
{
"favorite": true,
"note": "이번주는 이 조합",
"tags": ["jeju","safe"]
}

27
scripts/deploy-nas.cjs Normal file
View File

@@ -0,0 +1,27 @@
const { execSync } = require("child_process");
const fs = require("fs");
const isWin = process.platform === "win32";
const src = "dist";
const dstWin = "Z:\\docker\\webpage\\frontend\\";
const dstMac = "/Volumes/gahusb.synology.me/docker/webpage/frontend/";
const dst = isWin ? dstWin : dstMac;
if (!fs.existsSync(src)) {
console.error("dist not found. Run build first.");
process.exit(1);
}
if (!fs.existsSync(dst)) {
console.error("NAS path not found. Check mount: " + dst);
process.exit(1);
}
if (isWin) {
const cmd =
'powershell -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference=\\"Stop\\"; $src=\\"dist\\"; $dst=\\"Z:\\\\docker\\\\webpage\\\\frontend\\\\\\"; if(!(Test-Path $src)){ throw \\"dist not found. Run build first.\\" }; if(!(Test-Path $dst)){ throw \\"NAS drive not found. Check Z: mapping.\\" }; $log = Join-Path (Get-Location) \\"robocopy.log\\"; robocopy $src $dst /MIR /R:1 /W:1 /E /NFL /NDL /NP /V /TEE /LOG:$log; $rc = $LASTEXITCODE; if($rc -ge 8){ Write-Host \\"robocopy failed with code $rc. See $log\\"; exit $rc } else { exit 0 }"';
execSync(cmd, { stdio: "inherit" });
} else {
execSync(`rsync -av --delete --delete-delay --inplace ${src}/ ${dst}`, {
stdio: "inherit",
});
}

View File

@@ -360,7 +360,10 @@ export default function Functions() {
</section>
<footer className="lotto-foot">
backend: FastAPI / nginx proxy / DB: sqlite
backend: FastAPI / nginx proxy / DB: sqlite {' '}
<a className="lotto-foot__link" href="/lotto-api.md" download>
API 스펙 다운로드
</a>
</footer>
</div>
);

View File

@@ -322,6 +322,10 @@
font-size: 12px;
}
.lotto-foot__link {
color: var(--accent);
}
.button.danger {
border-color: rgba(247, 116, 125, 0.5);
color: #fbc4c8;