Reference
Development
Shelf is a .NET 10 app: ASP.NET Core minimal APIs and Blazor pages over EF Core and SQLite, with a little plain JavaScript for the readers and the player. Contributions are welcome on GitHub.
The pieces
| Folder | What it holds |
|---|---|
src/Shelf.Api |
The app: Books (the library, files, reading, lending, imports), Readers (accounts, sign-in, passkeys, the activity log), Components (the Blazor pages), Data (the database and migrations), and wwwroot (styles, scripts, fonts, and the vendored PDF.js and JSZip). |
src/Shelf.ServiceDefaults |
Health checks, telemetry, and resilience, shared with the app host. |
Shelf.AppHost |
An Aspire host that runs the app with a dashboard. |
tests/Shelf.Api.Tests |
Server tests with xUnit, against the real app on a throwaway database. |
tests/e2e |
Browser tests with Playwright. |
site |
This documentation. |
Running it
dotnet run --project src/Shelf.Api # http://localhost:5041
dotnet run --project Shelf.AppHost --launch-profile http # with the Aspire dashboard
The first run in Development adds one sample book, which goes to the first account. src/Shelf.Api/Shelf.Api.http has requests to try against it.
Tests
dotnet test
The browser tests start Shelf on an empty data folder and drive it in Chromium: lending, passkeys, two-step sign-in, uploads, imports, search, both readers, OCR, read aloud, the player, comics, offline reading with highlights, and an accessibility audit of every page in both themes.
cd tests/e2e
npm ci
npx playwright install chromium # or set CHROMIUM_PATH to a Chromium already installed
npx playwright test
CI runs both on every push and pull request, along with a check that the vendored front-end files match their pinned versions and a Docker build.
Changing the database
After changing the model in ShelfDb, add a migration named for the change, once for SQLite and once for PostgreSQL, which keeps its own:
dotnet tool restore
dotnet ef migrations add AddSomething --project src/Shelf.Api --context ShelfDb
dotnet ef migrations add AddSomething --project src/Shelf.Api --context PostgresShelfDb --output-dir Data/PostgresMigrations
Shelf applies migrations when it starts. To run the server tests against PostgreSQL, set SHELF_TEST_POSTGRES to a server's connection string without a database, such as Host=localhost;Username=shelf;Password=shelf;Maximum Pool Size=4; each test shelf gets a database of its own, and the small pool keeps the classes running side by side within PostgreSQL's 100 connections. CI runs them both ways. dotnet ef database update --project src/Shelf.Api applies them without starting it.
The design system
docs/design-system.md describes the look: color, type, and spacing tokens, the self-hosted Inter and Lora fonts, navigation, and the rules for covers, buttons, status labels, empty states, and dark mode. The tokens at the top of wwwroot/app.css are the only place colors, type, and spacing are set; this site uses the same ones.
Dependencies
Dependabot proposes updates to the NuGet packages, the GitHub Actions, the Docker images, and the npm packages for the vendored files, the browser tests, and this site. PDF.js, JSZip, and the fonts are copied into wwwroot from pinned npm packages; docs/maintenance.md covers updating them.
Releasing
Shelf follows semantic versioning. The version is set once, in Directory.Build.props, and the build stamps the commit beside it.
- Bump
VersionPrefixinDirectory.Build.props. - Add a section for the version to
CHANGELOG.md. - Commit, push, and tag:
git tag v1.3.0 && git push origin v1.3.0
The release workflow checks the tag against Directory.Build.props, runs the tests, publishes ghcr.io/doodersrage/shelf:1.3.0 and :latest, and makes a GitHub release from the changelog entry.
This documentation
The site is built from Markdown in site/content, with the changelog taken from CHANGELOG.md:
cd site
npm ci
npm run build # into site/_site
npm run serve # build, then serve it at http://localhost:8000
The screenshots in docs/images, used here and in the README, are made by a script that starts Shelf on an empty data folder, fills a demo shelf of public-domain books, and photographs the pages:
cd tests/e2e
npm run screenshots
A workflow publishes it to GitHub Pages on every push to main that changes it.