A simple full-stack app for tracking a personal book collection. Every change is recorded, so you can see exactly what happened to a book and when.
- Add, edit and delete books
- Slug-based URLs for each book
- Multiple authors per book
- Publish date with validation (no future dates allowed)
- Full audit history shown as a timeline or a searchable table
- Soft delete — removed books stay in history but disappear from the list
- Draggable add/edit and history dialogs
Backend
- .NET 10 Web API
- Entity Framework Core
- SQLite
- Swashbuckle (Swagger)
Frontend
- React 19 with TypeScript
- Vite
- MUI (Material UI)
- React Router
- TanStack Query
- React Hook Form + Zod
- Dayjs
book-audit/
├── backend/
│ └── BookAudit.Api/ # Web API
└── frontend/
└── book-audit-client/ # React SPA
cd backend/BookAudit.Api
dotnet restore
dotnet build
dotnet ef database update
dotnet run --launch-profile httpLocal Swagger: http://127.0.0.1:5000/swagger
cd frontend/book-audit-client
npm install
npm run devLocal app: http://localhost:5173/
docker compose up --buildDocker Swagger: http://localhost:5132/swagger
If the database already exists and migrations fail, remove the old volume:
docker volume rm book-audit_backend-dataEvery create, update, delete, author addition or author removal is captured by an EF Core interceptor. The frontend shows these events in two views: a timeline grouped by day, and a paginated, filterable list.
- Slugs are generated automatically from the book title.
- Renaming a book updates the slug and the URL changes with it.
- Audit history is stored in the same SQLite database.
- Generic audit with
IAuditableEntity: Currently the interceptor explicitly tracksBookandBookAuthor. A marker interface likeIAuditableEntityplus an[AuditIgnore]attribute would let any entity opt-in to audit logging without touching the interceptor. - Centralized
AuditLogtable: Today history is stored in a book-specificBookHistorytable. A genericAuditLogtable withEntityName,EntityId,Action,PropertyName,OldValue,NewValuewould support publishers, categories and other future entities. - Optimistic updates on all mutations: Update and delete already use optimistic cache updates; create could also be made optimistic once the server-generated
id/slughandling is worked out.