A Spring Shell–powered personal library manager with barcode scanning, hierarchical storage (bookcase → shelf → book), and hexagonal architecture.
- Demo / Screenshots
- Features
- Tech Stack
- Architecture Overview
- Getting Started
- Environment Variables
- Database
- Auth
- API Docs
- Testing
- Lint / Format
- Deployment
- Troubleshooting
- Contributing
- License
(Add screenshots of CLI and/or web UI here if you have them.)
- ISBN barcode scanning — CLI and web; metadata from Google Books API
- Hierarchical organization — Bookcase → Shelf → Book
- Shelf capacity — Per-shelf limits; overflow prevented
- Multi-author — Many-to-many book–author
- Availability — AVAILABLE, CHECKED_OUT, RESERVED, LOST, ARCHIVED
- Interactive CLI — Spring Shell commands with prompts
- REST API — CRUD and search for books, bookcases, shelves; import by ISBN
- Multi-user auth — User registration, form login, session-based access; Spring Security with per-user bookcases/data
- Hexagonal architecture — Ports & adapters; ArchUnit in tests
| Layer | Technology | Notes |
|---|---|---|
| Language | Java 17 | pom.xml; CI runs on Java 21 |
| Framework | Spring Boot 3.5.7 | Web, Data JPA, Security |
| CLI | Spring Shell 3.4.1 | Interactive shell |
| HTTP client | Spring WebFlux | Google Books API |
| Database | PostgreSQL | Runtime; H2 for tests |
| API docs | SpringDoc OpenAPI 2.8.0 | Swagger UI |
| Build | Maven | Wrapper: ./mvnw |
| Format | Spotless (Google Java Format) | spotless:check / apply |
- Inbound: Spring Shell CLI (
cli/command/), REST controllers (web/). - Core: Domain modules under
library/—cataloging(book, author; includes book location/search queries),stacks(bookcase, shelf),registration,classification(booklist). Each has contracts (ports/DTOs), core (domain + application), infrastructure (JPA, external clients). - Outbound: JPA repositories (PostgreSQL), Google Books client (WebClient).
CLI + REST → Facades / DTOs → Application services → Domain
↓
PostgreSQL, Google Books API ← Repository interfaces ← Ports
- Java 17+ (OpenJDK/Temurin; CI uses 21)
- PostgreSQL (local or Docker)
- Maven 3.8+ or use the project Maven Wrapper (
./mvnw)
git clone https://github.com/leodvincci/Bibby.git
cd BibbyThe app reads the database from environment variables (see Environment Variables). There is no .env.example in the repo; set DB_URL, DB_USERNAME, and DB_PASSWORD for your PostgreSQL instance.
For a local Postgres (e.g. the Quickstart container below):
export DB_URL=jdbc:postgresql://localhost:5332/amigos
export DB_USERNAME=amigoscode
export DB_PASSWORD=password1. Start PostgreSQL (e.g. Docker)
docker run -d \
--name bibby-postgres \
-e POSTGRES_DB=amigos \
-e POSTGRES_USER=amigoscode \
-e POSTGRES_PASSWORD=password \
-p 5332:5432 \
postgres:latest2. Start the app
./mvnw spring-boot:run3. Use the CLI
You should see the Bibby banner and prompt:
Bibby:_
Type help for commands.
Run from JAR (after build):
./mvnw clean package
java -jar target/Bibby-0.0.1-SNAPSHOT.jarCommon gotcha: If you see database connection errors, ensure DB_URL, DB_USERNAME, and DB_PASSWORD are set and match the running Postgres (host, port, database, user, password).
Used by src/main/resources/application.properties (no in-file defaults for DB).
| Variable | Purpose | Example (local) |
|---|---|---|
DB_URL |
PostgreSQL JDBC URL | jdbc:postgresql://localhost:5332/amigos |
DB_USERNAME |
Database user | amigoscode |
DB_PASSWORD |
Database password | password |
GOOGLE_BOOKS_API_KEY |
Google Books API key (ISBN lookup) | (your key from Google Cloud Console) |
Optional overrides (Spring Boot convention): SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD can override if you prefer.
The repo contains a .env and .envrc (e.g. dotenv); do not commit real secrets. Use .env locally and set the same variables in your deployment environment.
- Schema: Managed by Hibernate;
spring.jpa.hibernate.ddl-auto=create-dropin the main config (schema recreated on each run; data is lost on restart). - Migrations: No Flyway/Liquibase; schema is driven by JPA entities.
- Seeds: No seed scripts in the repo; use CLI or API to create data.
- Tests: Use an in-memory H2 database (
src/test/resources/application.properties).
For production, switch to a different ddl-auto (e.g. update or validate) and/or add migrations in a separate change.
Bibby supports multiple users: each user registers, logs in with their own credentials, and sees their own data (e.g. bookcases are scoped by user).
- Registration:
POST /api/v1/user/registration/registerwith JSON body{"email":"...", "password":"..."}. Passwords are stored with BCrypt. - Login: Form login;
POST /loginwith form fields (e.g.username= email,password). Success returns 200 and JSON{"message":"Login successful"}; session cookie is set. - Session: Authenticated requests use the session cookie. Most API endpoints require authentication. Permitted without auth: registration, Swagger UI, OpenAPI docs,
/actuator/health,/actuator/info,/actuator/readiness, and/h2-console/**. Logout:POST /logout(default Spring Security). - CORS: Allowed origins include
http://localhost:5173,https://*.vercel.app, andhttps://bibby-web.vercel.app; credentials allowed. If the frontend runs elsewhere, updateWebSecurityConfigs.java.
- Swagger UI:
http://localhost:8080/swagger-ui.html(or/swagger-ui/index.html) - OpenAPI JSON:
http://localhost:8080/v3/api-docs
Base URL when running locally: http://localhost:8080. Protected endpoints require an authenticated session (log in via /login first when using the browser).
Example endpoints (from the controllers):
| Area | Method | Path | Notes |
|---|---|---|---|
| Auth | POST | /api/v1/user/registration/register |
Body: {"email","password"} |
| Books | POST | /api/v1/books/fetchbookmetadata |
Body: {"isbn":"..."}; returns metadata |
| Books | GET | /api/v1/books/lookup/{isbn} |
Google Books lookup |
| Books | GET | /api/v1/books/search/{isbn} |
Find in DB by ISBN |
| Books | GET | /api/v1/books/findBookByTitle |
Body: {"title":"..."} (GET with body) |
| Books | POST | /api/v1/books/addnewbook |
Body: book DTO (title, isbn, authors, publisher, shelfId) |
| Books | POST | /api/v1/books/{bookId}/shelf |
Body: {"shelfId":...} |
| Books | GET | /api/v1/books/shelf/{shelfId} |
Books on shelf |
| Books | GET | /api/v1/books/booklocation |
Query: ?bookId=... |
| Bookcase | POST | /api/v1/bookcase/create |
Auth required. Body: location, zone, indexId, shelfCount, shelfCapacity |
| Bookcase | DELETE | /api/v1/bookcase/delete/{bookcaseId} |
Auth required |
| Bookcase | GET | /api/v1/bookcase/locations |
All locations |
| Bookcase | GET | /api/v1/bookcase/location/{location} |
Bookcases at location |
| Bookcase | GET | /api/v1/bookcase/all |
All bookcases for current user (auth) |
| Shelves | GET | /api/v1/shelves/options |
All shelf options |
| Shelves | GET | /api/v1/shelves/options/{bookcaseId} |
Shelf options for one bookcase |
Full request/response shapes: use Swagger UI at /swagger-ui.html.
# All tests
./mvnw test
# Single test class
./mvnw test -Dtest=BookServiceTest
# Full build + tests (same as CI)
./mvnw clean verifyTest reports: target/surefire-reports/ (and failsafe if integration tests are added). No JaCoCo plugin is configured in the repo; for coverage you would need to add the plugin and then run ./mvnw test jacoco:report (TODO/verify if you add it).
Spotless (Google Java Format) is configured and runs in CI:
# Check only
./mvnw spotless:check
# Apply formatting
./mvnw spotless:apply-
Docker: The repo includes a multi-stage
Dockerfile. Build and run the app image; the app expectsDB_URL,DB_USERNAME, andDB_PASSWORDat runtime (e.g. pass via-eor your orchestrator’s env config).docker build -t bibby:latest . docker run -it --rm \ -e DB_URL=jdbc:postgresql://host.docker.internal:5332/amigos \ -e DB_USERNAME=amigoscode \ -e DB_PASSWORD=password \ -p 8080:8080 \ bibby:latest -
Railway: Referenced in config (e.g.
application-dev.properties); deploy by connecting the repo and setting the same env vars. No Railway-specific config files are in the repo. -
Docker Compose: Not in the repo; you can add a
docker-compose.ymlthat starts Postgres and the app if you want one-command local run.
| Issue | What to try |
|---|---|
| DB connection refused | Ensure Postgres is running; check host/port in DB_URL; verify user/password and that the database exists. For Docker Postgres: docker ps | grep postgres. |
| Port 8080 in use | Run on another port: ./mvnw spring-boot:run -Dserver.port=8081 |
| CORS / cookie errors from frontend | Session cookies use SameSite=None; Secure. Use HTTPS in production; for local frontend use http://localhost:5173 (already in CORS config). Add other origins in WebSecurityConfigs.java if needed. |
| Env vars not applied | The app reads DB_URL, DB_USERNAME, DB_PASSWORD from the environment. Export them in the same shell where you run ./mvnw spring-boot:run, or use a .env + tool that injects them (e.g. dotenv via .envrc). |
| Data gone after restart | Expected with create-drop. Use a different profile or override spring.jpa.hibernate.ddl-auto for persistence. |
| Build / test failures | ./mvnw clean install -U; run tests with ./mvnw test. CI runs mvn -B -ntp clean verify and mvn spotless:check. |
- Open issues and discussions on GitHub. For code changes, use a feature branch and open a pull request against
main. - CI must pass (
mvn clean verifyandspotless:check). Format with./mvnw spotless:applybefore pushing. - Conventions: hexagonal boundaries (see
docs/and ArchUnit tests), package-by-feature underlibrary/, and documented decisions indocs/the-devlogs/.
This project is a personal learning project and is not licensed for external use. For educational or derivative use, please reach out for permission.
Copyright © 2024–2026 Leo D. Penrose. All rights reserved.
Author: Leo D. Penrose · Building Bibby
