Skip to content

Latest commit

 

History

History
220 lines (147 loc) · 16 KB

File metadata and controls

220 lines (147 loc) · 16 KB

Stash

CI Docker Release Node.js License Self-hosted Docker

English README

셀프호스팅 가정용 재고 관리 — 라벨과 스캐너가 중심입니다. 물건에 바코드·QR을 붙이고 스캔으로 입고·소비하며, 재고가 바뀌면 선택적 웹훅이 프린터나 Home Assistant 라벨을 갱신합니다. 대시보드에서 재고부족·유통기한을 보되, 식단·레시피 앱으로 키우지 않습니다.

현재 릴리스: v0.7.4

문서: docs/ROADMAP.md


기능

  • 중첩 위치(방 / 선반 / 상자)를 들여쓰기 트리로 표시, 카테고리
  • 수량, 재고부족 기준 수량, 유통기한·보증 만료일, 가격, 메모 — 이름·단위는 아이템 상세에서 바로 인라인 편집. 직접 등록 폼에서 촬영 또는 갤러리 선택으로 사진을 하나 골라둘 수 있고(업로드 시 자동 리사이즈), 가격은 매번 입력하는 대신 설정에서 한 번 고른 기본 통화(원/달러)를 그대로 씀
  • 통합 Item + Barcode 모델 — 기존 UPC/EAN, 직접 발급 내부 QR(아이템 딥링크), Matter 페어링 코드, 수동 입력 시리얼번호를 하나의 바코드 타입으로. 각 바코드마다 자체 인쇄 버튼이 있어서 바코드가 여러 개인 아이템도 원하는 걸 정확히 인쇄합니다. 바코드 없이 등록한 아이템은 내부 QR이 자동으로 발급되고(나중에 따로 안 만들어도 됨), 직접 등록 폼은 체크박스 대신 등록 / 등록 및 인쇄 버튼으로 나뉩니다. 바코드/QR/시리얼번호 수동 추가는 토글 하나로 접혀 있고, 카메라로 스캔하면 어떤 종류를 추가하는지 물어보는 대신 포맷(바코드 vs QR/Matter, Matter는 자산에서만)과 정확한 심볼로지를 자동으로 판별합니다
  • 수량 관리와 별개로 자산(기기) 모드 — 아이템을 자산으로 전환하면 개별 기기 하나를 추적: 상태(신품/사용중/수리필요/폐기), 시리얼번호 바코드 등록, 정비 이력(날짜·내용·비용) 기록. 자산은 수량 스텝퍼·재고부족 필드가 숨겨지고 장보기/재고부족 로직에서 제외되며, 자산 바코드를 스캔하면 수량 조정 없이 해당 자산의 상세 페이지로 바로 이동합니다.
  • 영수증·설명서·보증서·사진 등 파일 첨부 — 업로드 창구를 하나로 통합해 아이템·자산마다 PDF/이미지 문서를 여러 개 올려 보관하고, 파일 링크가 아니라 실제 썸네일로 미리 보여줍니다(업로드 시 이미지는 자동 리사이즈). 이미지 첨부 중 아무거나 대표 사진으로 지정할 수 있고, 이름 옆에 프로필 사진처럼 작게 표시됩니다 — 이미지가 하나뿐이면 자동으로 대표가 되고, 여러 장이면 직접 골라야 합니다.
  • 연속 카메라 스캔: 입고(+1) / 소비(−1) 모드, 화면 전환 없이 계속 스캔 — 직접 등록 폼이나 바코드/Matter 코드 추가에서도 카메라 스캔 지원. 실사용 인식률/속도를 위해 포맷 제한·고해상도·연속 오토포커스로 튜닝했고, 스캔 성공 시 삑 소리·진동, 저조도용 플래시 토글 지원. 새로 자동 생성된 아이템은 그 자리에서 바로 위치·기준수량을 채우는 미니시트 제공
  • 외부 제품 조회 연동을 다중 선택 가능(Open Food Facts, UPCItemDB, 네이버쇼핑) — 원하는 제공자만 켜거나 아예 꺼서 조회 자체를 생략
  • 대시보드: 총 자산가치, 재고부족·유통기한 임박 항목을 전면에, 첫 사용 시 온보딩 체크리스트(위치·알림·공개URL) 제공
  • 하단 탭으로 바로 가는 장보기 리스트 — 재고부족 항목은 물론 재고와 무관하게 수동으로 추가한 항목도 포함, 메모 표시·구매완료 체크 지원
  • 검색(이름 또는 바코드 값)·위치/카테고리 필터·정렬·페이지네이션이 있는 아이템 목록, 마지막 필터/정렬 기억; 여러 아이템을 선택해 위치/카테고리 일괄 변경·일괄 삭제
  • 삭제 시 실행취소 — 아이템을 지우면 바로 실행취소 토스트가 뜸
  • 대량 입력·스프레드시트 이전을 위한 CSV 가져오기 / 내보내기(바코드 값 포함)
  • 라벨 인쇄: 단일 PNG, 또는 A4 라벨 시트 PDF(한글 이름은 번들된 Noto Sans KR 서브셋으로 렌더링), 라벨 선택 화면에 검색 지원
  • 유통기한 / 보증 만료 푸시 알림 + 주간 재고부족 요약 알림(Web Push)
  • 휴지통(소프트 삭제) — 복구 + 30일 자동 영구삭제
  • 오프라인 지원 PWA: 앱 셸 캐시에 더해 아이템 목록/상세 응답도 캐시해 오프라인에서 조회 가능, 스캔/직접 등록 홈 화면 숏컷, 오프라인 스캔 큐(온라인 복귀 시 자동 동기화)
  • 넓은 화면에서는 하단 네비가 양 끝까지 늘어나지 않고 가운데 폭 제한 컬럼으로 모임; 더보기는 별도 페이지 대신 화면 위로 슬라이드업되는 바텀시트로 열림(위치/카테고리, 이력/라벨/휴지통, 설정/가족구성원/외부연동 그룹)
  • 프린터·라벨 기기 자동화(예: Home Assistant)용 재고 이벤트 웹훅 — 마지막 전송 실패를 설정 화면에서 확인 가능
  • 관리자 / 일반 역할, 최초 관리자 부트스트랩, 본인 비밀번호 변경, 가족 구성원 비밀번호 재설정(임시값 1회 발급, 조회 아님), 이 기기 로그아웃 vs 모든 기기에서 로그아웃, 백업/복원, 한/영 i18n, 라이트/다크 테마

범위 밖 (하지 않는 것)

  • 레시피 / 식단 계획 / 조리에 따른 자동 차감 — Stash는 무엇을 얼마나 갖고 있는지만 다룹니다. 무엇을 해먹을지 정하거나 재료를 레시피에서 깎지 않습니다.
  • 한 프로세스 안에서의 멀티테넌시·가구별 데이터 격리 — 인스턴스 하나 = 가구 하나. 다른 집은 groupId로 나누지 말고 컨테이너를 따로 띄웁니다.

스크린샷 & 사용 방법

1. 대시보드

로그인 후 홈 화면입니다. 총 자산가치와 재고부족, 유통기한 임박, 최근 등록을 보여줍니다. 카드의 + / 로 바로 수량을 조정하거나 장보기 리스트로 보기로 이동합니다.

대시보드

2. 스캔

화면 전환 없이 연속으로 바코드 / QR 코드를 스캔합니다. 입고(+1) 또는 소비(−1) 모드를 선택하여 계속 스캔할 수 있으며, 인식 시 소리/진동 알림 및 저조도용 플래시를 지원합니다. 등록되지 않은 바코드는 스캔 시 자동 등록되며, 그 자리에서 위치나 기준수량을 바로 설정할 수 있는 미니시트가 제공됩니다. 카메라가 없는 기기에서는 직접 입력도 가능합니다.

스캔

3. 아이템

검색, 위치 / 카테고리 필터, 정렬(최근 등록순 / 수량 적은순 / 유통기한 임박순)이 제공되는 전체 목록입니다. 여러 아이템을 선택하여 위치나 카테고리를 일괄 변경하고 일괄 삭제할 수 있으며, 전체 목록을 CSV로 가져오거나 내보낼 수 있습니다.

아이템

4. 아이템 상세

수량, 위치, 카테고리, 재고부족 기준 수량, 유통기한 / 보증 만료일, 가격, 사진을 편집합니다. 기존 바코드 연결, 내부 QR 발급, Matter 코드 추가, 프린터 출력 요청, 영수증/설명서 등 파일 첨부(이미지/PDF)가 가능하고, 아래에 수량 변경 및 정비 이력이 표시됩니다.

아이템 상세

5. 장보기 리스트

재고부족 항목과 수동으로 추가한 장보기 물품을 체크리스트로 보여줍니다. 사 온 만큼 +를 누르면 기준 수량을 넘는 순간 목록에서 자동으로 빠집니다. 개별 메모 작성 및 구매완료 체크 기능도 제공합니다.

장보기 리스트

6. 더보기

화면 하단 네비게이션바의 더보기 버튼을 누르면 화면 위로 슬라이드업되는 바텀시트 메뉴입니다. 구조 관리(위치·카테고리), 작업·기록(이력 보기·라벨 인쇄·휴지통), 계정·연동(설정·가족 계정·연동 설정)으로 깔끔하게 구분되어 제공됩니다.

더보기


빠른 시작

1. 설치

Proxmox (권장)

bash -c "$(curl -fsSL https://raw.githubusercontent.com/eigger/stash/master/proxmox/ct/stash.sh)"

community-scripts 스타일 설치 마법사가 Docker가 포함된 Debian 13 LXC를 만들고, 배포 파일과 랜덤 시크릿이 든 .env/opt/stash에 쓴 뒤 stash.service systemd 유닛으로 스택을 기동합니다. 완료 후 http://<LXC_IP>로 접속하세요.

업데이트 (update) — 컨테이너 안에서 실행합니다. 최신 릴리스 태그에서 docker-compose.prod.yml / Caddyfile / /usr/bin/update 자신을 받은 뒤 이미지를 pull하고, /health가 살아 있는지 확인합니다. 실패하면 배포 파일을 백업본으로 되돌립니다. .env 시크릿은 덮어쓰지 않습니다(없는 키만 주석으로 가산).

  • 로컬에서 compose를 고쳐 둔 경우: 기본은 중단됩니다. 덮어쓰려면 update --force
  • 특정 git ref에서 받으려면: STASH_REF=master update (이미지는 여전히 :latest)
  • 기존 설치본(옛 update만 있는 경우) 1회 부트스트랩 — 이걸 한 뒤에야 배포 파일 갱신이 동작합니다:
curl -fsSL https://raw.githubusercontent.com/eigger/stash/master/proxmox/install/update.sh -o /usr/bin/update && chmod +x /usr/bin/update
update

Docker Compose

docker compose -f docker-compose.prod.yml up -d

시작 전에 .envPOSTGRES_PASSWORD, JWT_SECRET을 강한 난수 값으로 설정하세요 (예: openssl rand -hex 32). 프로덕션에서는 JWT_SECRET이 없거나 changeme / dev-secret-change-me 같은 알려진 기본값이면 API가 기동을 거부합니다. 이미지는 ghcr.io/<owner>/stash-api / stash-web을 씁니다 — 포크했다면 GH_REPOSITORY_OWNER(및 proxmox/install/stash-install.sh의 이미지 이름)를 맞추세요.

2. 최초 관리자 생성

새로 설치하면 사용자가 없을 때 /login최초 관리자 만들기가 나타납니다.

  1. /login 열기
  2. 이름·이메일·비밀번호 입력
  3. 제출 — ADMIN으로 로그인됩니다

공개 회원가입은 비활성화되어 있습니다. 이후 계정은 관리자가 더보기 → 가족 구성원 계정에서만 만듭니다.

3. 위치·카테고리 설정

더보기 → 위치 관리 / 카테고리 관리에서 물건이 있는 곳(방, 선반, 냉장고…)과 분류(식품, 생활용품, 전자제품…)를 만듭니다. 둘 다 중첩 가능하고 선택 사항이라, 아이템마다 나중에 채워도 됩니다.

4. 일상 사용

할 일 위치
스캔으로 입고 / 소비 스캔 (하단 탭)
바코드 없는 물건 등록 아이템 → 직접 등록
수량 빠르게 조정 아이템 카드의 + /
뭘 사야 하나 대시보드 → 장보기 리스트로 보기
대량 가져오기 / 내보내기 아이템 → CSV 가져오기 / 내보내기
라벨 인쇄 더보기 → 라벨 인쇄
삭제한 아이템 복구 더보기 → 휴지통
유통기한 / 보증 알림 설정 → 알림
백업 / 복원 설정 → 백업 / 복원 (백업은 암호화되지 않은 인벤토리 전체 덤프이므로 보관에 주의. 비밀번호 해시는 제외되며, 복원 시 필요하면 계정별 임시 비밀번호가 안내됩니다)

5. 재고 이벤트 웹훅 (선택)

설정 → 외부 연동에서 URL 하나를 등록합니다. 아이템 생성 / 수정 / 스캔 시, 그리고 명시적 출력 요청 시 Stash가 JSON 페이로드를 POST하므로, 받는 자동화(예: Home Assistant)가 자체적으로 라벨을 렌더링할 수 있습니다. 선택적으로 서명 시크릿(INVENTORY_WEBHOOK_SECRET)을 설정하면 수신 측이 X-Stash-Timestamp / X-Stash-Signature(HMAC-SHA256)로 검증할 수 있습니다. 페이로드 형식은 docs/ROADMAP.md 참고.

Home Assistant를 통해 다음을 사용할 수 있습니다.


프로젝트 구조

stash/
  apps/
    api/      # Fastify + Prisma
    web/      # Next.js App Router (PWA, 한/영)
  packages/
    shared/   # 공유 Zod 스키마
  scripts/    # capture-screenshots.mjs
  docker-compose.yml / docker-compose.prod.yml
  Caddyfile
  proxmox/    # LXC 원클릭 설치

로컬 개발

npm install
cp .env.example .env   # POSTGRES_PASSWORD / JWT_SECRET 은 openssl rand -hex 32 로 생성
docker compose up -d postgres
npm run prisma:migrate
npm run seed -w apps/api   # 선택: 부트스트랩 UI 대신 관리자 시드
npm run dev:api            # :8080
npm run dev:web            # :3000

http://localhost:3000/login 열기.

로컬 npm run dev에서 사진이 전부 안 보이면(web :3000 → api :8080) .envMEDIA_AUTH_DISABLED=true 주석을 해제하세요. 교차 오리진이라 미디어 쿠키가 <img>에 안 실립니다. 프로덕션에서는 절대 켜지 마세요.

유용한 스크립트: npm run build, npm run test, npm run prisma:generate.


프로덕션 참고

  • 스택: PostgreSQL 16 + API + Web + Caddy (:80)
  • API는 시작 시 prisma migrate deploy 실행(프로덕션 compose)
  • 이미지: ghcr.io/<owner>/stash-api / stash-web (latest + semver 태그)
  • LXC 업데이트: 컨테이너 안에서 update (릴리스 태그에서 compose/Caddyfile 동기화 + 이미지 pull + 헬스 확인)
  • 외부 바코드 조회(Open Food Facts, UPCItemDB)는 선택 — 수동 입력과 자체 발급 QR만으로도 전체 동작
  • APP_PUBLIC_URL은 자체 발급 QR 라벨에 인코딩되는 딥링크를 결정합니다. 실제 도메인으로 설정해야 아무 카메라 앱으로 스캔해도 앱이 열립니다

CI/CD

워크플로 트리거 목적
.github/workflows/ci.yml master 푸시 / PR 설치, 빌드, 테스트
.github/workflows/docker-release.yml GitHub Release GHCR로 이미지 푸시

라이선스

MIT. LICENSE 참고.