尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證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.