尚未检测到更新。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.