9.9 KiB
Books V2
Last updated: 2025-12-13
#docker #app #books-v2
Architecture Overview
Books V2 is a web application for tracking books read. It consists of a React frontend and a FastAPI backend.
- Frontend: The frontend is a single-page application built with React and Vite. It uses TypeScript for static typing, Tailwind CSS for styling, and TanStack Query for data fetching and caching.
- Backend: The backend is a RESTful API built with FastAPI, a modern, high-performance Python web framework. It uses SQLAlchemy as the ORM to interact with the database.
- Database: The application uses a MySQL database to store all its data. Alembic is used for database migrations.
API Endpoints
The API is versioned and all endpoints are available under the /api/v1 prefix.
Authentication
GET /me: Get the current authenticated user's information.GET /users: Get a list of all users.
Books
GET /books: Get a paginated list of books.- Query Parameters:
page,items_per_page,search,year,sort_by,sort_order,view_as_user_id
- Query Parameters:
POST /books: Create a new book.GET /books/{book_id}: Get a single book by ID.PUT /books/{book_id}: Update a book by ID.DELETE /books/{book_id}: Delete a book by ID.POST /books/from-next/{next_book_id}: Create a new book from a "next book".
Next Books
GET /next-books: Get a paginated list of books in the "to read" list.- Query Parameters:
page,items_per_page,search,sort_by,sort_order,view_as_user_id
- Query Parameters:
POST /next-books: Add a new book to the "to read" list.PUT /next-books/bulk-update-order: Bulk update the reading order of the "to read" list.GET /next-books/{book_id}: Get a single "next book" by ID.PUT /next-books/{book_id}: Update a "next book" by ID.DELETE /next-books/{book_id}: Delete a "next book" by ID.
Autocomplete
GET /autocomplete/formats: Get a list of all unique book formats.GET /autocomplete/authors: Get a list of all unique authors.GET /autocomplete/genres: Get a list of all unique genres.
Summary
GET /summary/all: Get a summary of all books.GET /summary/audiobooks: Get a summary of all audiobooks.GET /summary/non-audiobooks: Get a summary of all non-audiobooks.GET /summary/yearly: Get a yearly summary of reading stats.
Advanced Stats
GET /advanced-stats: Get advanced reading statistics.
Search
GET /search: Search for books using an external API (Google Books).- Query Parameters:
query,max_results
- Query Parameters:
Database Schema
The database consists of three main tables: users, books, and next_books.
users table
| Column | Type | Constraints |
|---|---|---|
id |
Integer |
Primary Key, Autoincrement |
username |
String(255) |
Not Null, Unique, Indexed |
email |
String(255) |
Nullable |
display_name |
String(255) |
Nullable |
created_at |
DateTime |
Not Null, Server Default |
last_login |
DateTime |
Nullable |
books table
| Column | Type | Constraints |
|---|---|---|
id |
Integer |
Primary Key, Autoincrement |
user_id |
Integer |
Foreign Key (users.id), Not Null, Indexed |
format |
String(50) |
Not Null |
title |
String(255) |
Not Null |
author |
String(255) |
Nullable |
genre |
String(255) |
Nullable |
date_started |
Date |
Not Null |
date_finished |
Date |
Nullable |
days |
Integer |
Nullable |
pages |
Integer |
Not Null |
| Unique | user_id, title |
next_books table
| Column | Type | Constraints |
|---|---|---|
id |
Integer |
Primary Key, Autoincrement |
user_id |
Integer |
Foreign Key (users.id), Not Null, Indexed |
title |
String(255) |
Not Null |
author |
String(255) |
Not Null |
genre |
String(255) |
Nullable |
pages |
Integer |
Nullable |
format |
String(255) |
Nullable |
purchased_status |
Boolean |
Nullable, Default: False |
reading_order |
Integer |
Nullable |
| Unique | user_id, title |
Authentication
Authentication is handled by the Traefik reverse proxy in conjunction with Authelia. Authelia is an authentication and authorization server that provides single sign-on (SSO) for web applications.
When a user accesses the Books V2 application, Traefik forwards the request to Authelia for authentication. If the user is not authenticated, Authelia presents a login page. Once the user authenticates, Authelia sets a Remote-User header in the request and forwards it to the Books V2 backend.
The backend's get_current_user dependency reads the Remote-User header, and then gets or creates the user in the database. This means that user management is handled by Authelia, and the Books V2 application trusts the Remote-User header set by the proxy.
Environment Variables
Backend (.env)
DB_USER: The username for the MySQL database.DB_PASSWORD: The password for the MySQL database.DB_HOST: The hostname or IP address of the MySQL database server.DB_PORT: The port of the MySQL database server.DB_NAME: The name of the MySQL database.DB_CHARSET: The character set for the MySQL database connection.TZ: The timezone for the application.
Frontend (.env)
VITE_API_URL: The base URL for the backend API.
Development Workflow
Frontend
- Start dev server:
npm run dev - Build for production:
npm run build - Run tests: No tests are currently configured.
- View logs: Logs are printed to the console where the dev server is running.
- Access container shell:
docker exec -it books_frontend /bin/sh
Backend
- Start dev server: The backend is run directly via
uvicornin theDockerfile, so there is no separate dev server command. - Run tests: No tests are currently configured.
- View logs:
docker logs -f books_backend - Access container shell:
docker exec -it books_backend /bin/bash - Database migrations: Migrations are handled by Alembic. To create a new migration, run
alembic revision --autogenerate -m "Your migration message". To apply migrations, runalembic upgrade head.
Deployment Process
The application is deployed using Docker Compose. The docker-compose.yml file defines two services: frontend and backend.
To deploy the application, run docker-compose up -d --build. This will build the Docker images for the frontend and backend and start the containers.
Common Tasks
- Adding a new API endpoint:
- Add a new function to
backend/app/api/v1/endpoints/books.py. - Add a new function to
frontend/src/utils/api.tsto call the new endpoint. - Use the new function in a React component.
- Add a new function to
- Adding a new database table:
- Create a new model in
backend/app/models. - Run
alembic revision --autogenerate -m "Add new table"to create a new migration. - Run
alembic upgrade headto apply the migration.
- Create a new model in
Known Issues
- No tests are configured for either the frontend or the backend.
- The "Required by" field in the service inventory is not populated.
File Structure
Frontend
frontend/
├── public/ # Static assets
├── src/
│ ├── components/ # Reusable React components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Library code (e.g., axios configuration)
│ ├── pages/ # Application pages
│ ├── stores/ # Zustand state management stores
│ ├── types/ # TypeScript type definitions
│ └── utils/ # Utility functions
├── Dockerfile.prod # Production Dockerfile
├── package.json # NPM dependencies and scripts
└── vite.config.ts # Vite configuration
Backend
backend/
├── alembic/ # Alembic database migration files
├── app/
│ ├── api/ # API endpoint definitions
│ ├── db/ # Database session management
│ ├── dependencies/ # FastAPI dependencies (e.g., auth)
│ ├── middleware/ # Custom middleware
│ ├── models/ # SQLAlchemy database models
│ ├── schemas/ # Pydantic data validation schemas
│ ├── services/ # Business logic
│ ├── config.py # Application configuration
│ └── main.py # Main FastAPI application
├── Dockerfile # Dockerfile for the backend
└── requirements.txt # Python dependencies