Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
Stacks는 무료 도서 대여 앱, 내 책을 카탈로그하고 친구에게 대여·반납 알림 제공
Don't let your books collect dust. Stacks is a free book lending app: catalog the books you own, lend them to friends with due-date reminders so they come back, and borrow theirs.
라이프스타일TypeScript · CSSGitHub @grahamhagenah온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Stacks: a lending library for the books you own. Catalog your shelf, connect with friends, and lend and borrow.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A social book-lending app where you can catalog your personal library, connect with friends, and share books.
Live: bookstacks.app
/demo (or "explore a demo library" on the home page) to try a fully stocked library without signing up# Install dependencies
npm install
# Set up the database
npm run setup
# Start the dev server
npm run dev
The app runs at localhost:3000.
Create a .env file in the project root:
# Required
DATABASE_URL="file:./dev.db"
SESSION_SECRET="your-secret-key-change-in-production"
# Email notifications (optional for dev, required for prod)
RESEND_API_KEY=re_xxxxxxxxxxxx
APP_URL=https://bookstacks.app
FROM_EMAIL=Stacks <[email protected]>
| Variable | Description | Required |
|---|---|---|
DATABASE_URL | SQLite database path | Yes |
SESSION_SECRET | Secret for session cookies | Yes |
RESEND_API_KEY | API key from resend.com | Production |
APP_URL | Your app's public URL | Production |
FROM_EMAIL | Sender address for emails | Production |
Visiting /demo creates a private sandbox and signs the visitor in to it: a library of 14 books, three friends with their own shelves, books lent out (one overdue) and borrowed (one due soon), and pending friend and borrow requests to act on. The demo friends accept friend requests and approve borrow requests immediately so every flow can be tried.
User.demoGroup. Demo users never appear in search, suggestions or the admin dashboard for real users, and can't send requests to real users.demo.stacks.invalid domain, so no mail is ever sent.app/models/demo.server.ts.Email notifications are sent via Resend when:
Without RESEND_API_KEY, the app works normally but emails are logged to console instead of sent.
Book request emails include:
| Command | Description |
|---|---|
npm run dev | Start development server |
npm run build | Build for production |
npm start | Run production server |
npm test | Run unit tests |
npm run typecheck | Check TypeScript types |
npm run lint | Lint with ESLint |
npm run format | Format with Prettier |
The app uses SQLite with Prisma ORM.
# Visual database browser
npx prisma studio
# After changing schema.prisma: write a migration, apply it locally and
# regenerate the client (the live server applies it on its next start)
npx prisma migrate dev --name what-changed
# Reset database (destroys all data)
npx prisma migrate reset
# Create the app
fly launch
# Create a persistent volume for SQLite
fly volumes create data --size 1 --app bookshelf-c524
# Set secrets
fly secrets set SESSION_SECRET=$(openssl rand -hex 32)
fly secrets set RESEND_API_KEY=re_xxxxxxxxxxxx
fly secrets set APP_URL=https://bookstacks.app
fly secrets set FROM_EMAIL="Stacks <[email protected]>"
fly deploy
# View logs
fly logs
# SSH into the machine
fly ssh console
# Check app status
fly status
# Update secrets
fly secrets set KEY=value
The database is backed up continuously with Litestream to Cloudflare R2: every change, kept for 30 days, so it can be restored to any point in that time. It's off until these four secrets are set; without them the app starts as it always has.
stacks-backups).https://<account-id>.r2.cloudflarestorage.com).fly secrets set LITESTREAM_BUCKET=stacks-backups LITESTREAM_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com LITESTREAM_ACCESS_KEY_ID=... LITESTREAM_SECRET_ACCESS_KEY=...
Check it's working with fly logs (look for litestream lines) or, on the machine, litestream snapshots -config /etc/litestream.yml /data/sqlite.db.
To restore: if the volume comes up empty, start.sh restores the latest backup by itself. To roll back to a moment in time, on the machine: litestream restore -config /etc/litestream.yml -timestamp 2026-10-22T09:00:00Z -o /data/restored.db /data/sqlite.db, then stop the app and swap the files.
app/
├── components/ # Reusable UI components
├── models/ # Prisma database functions
├── routes/ # Remix routes (pages and API)
├── email.server.ts # Email sending logic
├── db.server.ts # Database connection
└── session.server.ts # Authentication
prisma/
├── schema.prisma # Database schema
└── seed.ts # Seed data
| File | Purpose |
|---|---|
app/models/user.server.ts | User, friend, and notification functions |
app/models/book.server.ts | Book CRUD and lending functions |
app/email.server.ts | Resend email integration |
app/routes/search.tsx | Open Library search and book adding |
app/routes/notifications.tsx | Handle friend/book requests |
app/routes/friends.tsx | Friend list, suggestions, search |
Books are fetched from the Open Library API:
https://openlibrary.org/search.json?q={query}https://openlibrary.org/works/{key}.jsonhttps://covers.openlibrary.org/b/olid/{cover_id}-L.jpgBook metadata includes: title, author, cover, publication date, page count, subjects, publisher, and description.