셀프호스팅 가정용 재고 관리 — 라벨과 스캐너가 중심입니다. 물건에 바코드·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로 나누지 말고 컨테이너를 따로 띄웁니다.
로그인 후 홈 화면입니다. 총 자산가치와 재고부족, 유통기한 임박, 최근 등록을 보여줍니다. 카드의 + / −로 바로 수량을 조정하거나 장보기 리스트로 보기로 이동합니다.
화면 전환 없이 연속으로 바코드 / QR 코드를 스캔합니다. 입고(+1) 또는 소비(−1) 모드를 선택하여 계속 스캔할 수 있으며, 인식 시 소리/진동 알림 및 저조도용 플래시를 지원합니다. 등록되지 않은 바코드는 스캔 시 자동 등록되며, 그 자리에서 위치나 기준수량을 바로 설정할 수 있는 미니시트가 제공됩니다. 카메라가 없는 기기에서는 직접 입력도 가능합니다.
검색, 위치 / 카테고리 필터, 정렬(최근 등록순 / 수량 적은순 / 유통기한 임박순)이 제공되는 전체 목록입니다. 여러 아이템을 선택하여 위치나 카테고리를 일괄 변경하고 일괄 삭제할 수 있으며, 전체 목록을 CSV로 가져오거나 내보낼 수 있습니다.
수량, 위치, 카테고리, 재고부족 기준 수량, 유통기한 / 보증 만료일, 가격, 사진을 편집합니다. 기존 바코드 연결, 내부 QR 발급, Matter 코드 추가, 프린터 출력 요청, 영수증/설명서 등 파일 첨부(이미지/PDF)가 가능하고, 아래에 수량 변경 및 정비 이력이 표시됩니다.
재고부족 항목과 수동으로 추가한 장보기 물품을 체크리스트로 보여줍니다. 사 온 만큼 +를 누르면 기준 수량을 넘는 순간 목록에서 자동으로 빠집니다. 개별 메모 작성 및 구매완료 체크 기능도 제공합니다.
화면 하단 네비게이션바의 더보기 버튼을 누르면 화면 위로 슬라이드업되는 바텀시트 메뉴입니다. 구조 관리(위치·카테고리), 작업·기록(이력 보기·라벨 인쇄·휴지통), 계정·연동(설정·가족 계정·연동 설정)으로 깔끔하게 구분되어 제공됩니다.
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
updateDocker Compose
docker compose -f docker-compose.prod.yml up -d시작 전에 .env에 POSTGRES_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의 이미지 이름)를 맞추세요.
새로 설치하면 사용자가 없을 때 /login에 최초 관리자 만들기가 나타납니다.
/login열기- 이름·이메일·비밀번호 입력
- 제출 —
ADMIN으로 로그인됩니다
공개 회원가입은 비활성화되어 있습니다. 이후 계정은 관리자가 더보기 → 가족 구성원 계정에서만 만듭니다.
더보기 → 위치 관리 / 카테고리 관리에서 물건이 있는 곳(방, 선반, 냉장고…)과 분류(식품, 생활용품, 전자제품…)를 만듭니다. 둘 다 중첩 가능하고 선택 사항이라, 아이템마다 나중에 채워도 됩니다.
| 할 일 | 위치 |
|---|---|
| 스캔으로 입고 / 소비 | 스캔 (하단 탭) |
| 바코드 없는 물건 등록 | 아이템 → 직접 등록 |
| 수량 빠르게 조정 | 아이템 카드의 + / − |
| 뭘 사야 하나 | 대시보드 → 장보기 리스트로 보기 |
| 대량 가져오기 / 내보내기 | 아이템 → CSV 가져오기 / 내보내기 |
| 라벨 인쇄 | 더보기 → 라벨 인쇄 |
| 삭제한 아이템 복구 | 더보기 → 휴지통 |
| 유통기한 / 보증 알림 | 설정 → 알림 |
| 백업 / 복원 | 설정 → 백업 / 복원 (백업은 암호화되지 않은 인벤토리 전체 덤프이므로 보관에 주의. 비밀번호 해시는 제외되며, 복원 시 필요하면 계정별 임시 비밀번호가 안내됩니다) |
설정 → 외부 연동에서 URL 하나를 등록합니다. 아이템 생성 / 수정 / 스캔 시, 그리고 명시적 출력 요청 시 Stash가 JSON 페이로드를 POST하므로, 받는 자동화(예: Home Assistant)가 자체적으로 라벨을 렌더링할 수 있습니다. 선택적으로 서명 시크릿(INVENTORY_WEBHOOK_SECRET)을 설정하면 수신 측이 X-Stash-Timestamp / X-Stash-Signature(HMAC-SHA256)로 검증할 수 있습니다. 페이로드 형식은 docs/ROADMAP.md 참고.
Home Assistant를 통해 다음을 사용할 수 있습니다.
- hass-niimbot — Niimbot 라벨 인쇄
- hass-gicisky — Gicisky 전자 라벨(재고 관리, 유통기한 표기 등)
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 # :3000http://localhost:3000/login 열기.
로컬 npm run dev에서 사진이 전부 안 보이면(web :3000 → api :8080) .env의 MEDIA_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 라벨에 인코딩되는 딥링크를 결정합니다. 실제 도메인으로 설정해야 아무 카메라 앱으로 스캔해도 앱이 열립니다
| 워크플로 | 트리거 | 목적 |
|---|---|---|
.github/workflows/ci.yml |
master 푸시 / PR |
설치, 빌드, 테스트 |
.github/workflows/docker-release.yml |
GitHub Release | GHCR로 이미지 푸시 |
MIT. LICENSE 참고.





