From af3911b4b672ec093c813b478acc39f20fb3cc1f Mon Sep 17 00:00:00 2001 From: Ilyes BEN BRIK Date: Sat, 18 Jul 2026 18:25:59 +0200 Subject: [PATCH] add new features description --- README.md | 396 +++++++++++++++++++++++++++++------------------------- 1 file changed, 210 insertions(+), 186 deletions(-) diff --git a/README.md b/README.md index 88bb9a9..99cb0ea 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,60 @@ # 📚 Bookoholik — Home Library Management System -A modern, multilingual web application for managing your personal home library. Track your books, manage writers, lend books to friends, and generate reports — all from a clean, responsive interface. +A modern, multilingual, self-hosted web application for managing your personal home library. Track books across multiple locations, scan book covers with AI, manage writers and publishers, lend books to friends, and generate reports — all from a responsive mobile-friendly interface. ![Vue.js](https://img.shields.io/badge/Vue.js-3.4-4FC08D?logo=vuedotjs&logoColor=white) ![PHP](https://img.shields.io/badge/PHP-8.3-777BB4?logo=php&logoColor=white) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-16-4169E1?logo=postgresql&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker&logoColor=white) [![GitHub stars](https://img.shields.io/github/stars/XKlibure/home-library?style=social)](https://github.com/XKlibure/home-library) -[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) -[![Docker](https://img.shields.io/badge/Docker-Ready-blue?logo=docker)](docker-compose.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) +[![Docker](https://img.shields.io/badge/Docker-Ready-blue?logo=docker)](docker-compose.yml) [![SonarCloud](https://sonarcloud.io/api/project_badges/measure?project=bookoholik&metric=alert_status)](https://sonarcloud.io/dashboard?id=bookoholik) + --- ## ✨ Features +### 📷 AI Book Scanner (NEW) +- **Scan book covers** with your phone camera to extract title and author +- **Scan back pages** to extract ISBN, publisher, and publication year +- Powered by **Google Gemini Flash** Vision AI (free tier — 1,500 scans/day) +- Supports **Arabic calligraphy**, French, and English book covers +- Falls back to Tesseract OCR if no API key configured +- Editable results — correct OCR output before searching/adding +- Automatically searches your library for matches +- One-tap "Add Book" with pre-filled details from scan + ### 📖 Book Management - Full CRUD for your book collection - Search by title, author, genre, language, year - Filter by read status, borrowed status, location - ISBN lookup via Open Library API -- Track book location (room / shelf) +- Assign books to specific shelves (Address → Room → Shelf) +- Link books to publishers from your registry - Mark books as read/unread +### 📍 Multi-Location Library (NEW) +- Manage **multiple physical addresses** (Home, Office, Summer House, etc.) +- Set a **primary location** for your library +- Create **rooms** within each address (Living Room, Study, etc.) +- Create **shelves** within each room with capacity tracking +- Full hierarchy: Address → Rooms → Shelves → Books +- Visual tree view of your entire library layout +- Book count per location/room/shelf + +### 🏢 Publishers Management (NEW) +- Dedicated publisher/edition house registry +- Multilingual names (English, Arabic, French) +- Contact info: address, city, country, phone, email, website +- Link publishers to books +- View book count per publisher + ### ✍️ Writers Management - Dedicated writers/authors registry - Multilingual names (English, Arabic, French) - Nationality, birth/death year, biography -- Link writers to books when adding a book +- Select writers when adding a book (dropdown + manual entry) - View book count per writer ### 📖 Genres Management @@ -51,10 +79,16 @@ A modern, multilingual web application for managing your personal home library. - Create/disable/delete users - JWT-based authentication +### ⚙️ User Settings (NEW) +- Update profile information (name, username, email) +- Change password with strength validation +- View account info and role + ### 💾 Backup System - Automatic daily database backups (2:00 AM) - Manual backup creation - Download and manage backup files +- Secure `.pgpass` authentication (no env var exposure) ### 🌍 Multilingual Interface - **English** 🇬🇧 @@ -62,6 +96,22 @@ A modern, multilingual web application for managing your personal home library. - **French** 🇫🇷 - Language switcher in the UI, preference saved per user +### 📱 Mobile Responsive (NEW) +- Hamburger menu navigation on mobile +- Touch-friendly card layouts +- Camera capture directly from phone +- Optimized for phone-first usage + +### 🔒 Security Hardened +- Rate limiting on login (5/15min) and registration (3/hr) +- CORS restricted to configured origin +- Content Security Policy headers +- JWT with 8-hour expiry +- No hardcoded secrets — fails fast if env not set +- Container resource limits +- Password policy enforcement (10+ chars with complexity) +- Command injection prevention + --- ## 🏗️ Architecture @@ -69,16 +119,16 @@ A modern, multilingual web application for managing your personal home library. ``` ┌─────────────────────────────────────────────────┐ │ Frontend │ -│ Vue.js 3 + Vite + Tailwind │ -│ (nginx:alpine) │ -│ Port 3000 │ +│ Vue.js 3 + Vite + Tailwind CSS │ +│ (nginx:alpine) │ +│ Port 3000 │ └─────────────────┬───────────────────────────────┘ │ HTTP API calls ┌─────────────────▼───────────────────────────────┐ │ Backend │ -│ PHP 8.3 + Apache + Composer │ -│ Custom REST API │ -│ Port 8080 │ +│ PHP 8.3 + Apache + Tesseract OCR + GD │ +│ Custom REST API + Gemini Vision │ +│ Port 8080 │ └─────────────────┬───────────────────────────────┘ │ PostgreSQL protocol ┌─────────────────▼───────────────────────────────┐ @@ -95,49 +145,37 @@ A modern, multilingual web application for managing your personal home library. ### Prerequisites - [Docker](https://docs.docker.com/get-docker/) or [Podman](https://podman.io/getting-started/installation) with Compose support -- No other dependencies required — everything runs in containers +- (Optional) [Google Gemini API Key](https://aistudio.google.com/apikey) for AI book scanning (free) ### Installation 1. **Clone the repository** ```bash - git clone bookoholik - cd bookoholik + git clone https://github.com/XKlibure/home-library.git + cd home-library ``` -2. **Configure environment (optional)** +2. **Configure environment** - Create a `.env` file in the project root to override defaults: + ```bash + cp .env.example .env + # Edit .env — generate strong passwords: + # DB_PASSWORD, JWT_SECRET, APP_KEY (see .env.example for instructions) + ``` + For AI book scanning, add your free Gemini key: ```env - # Database - DB_DATABASE=home_library - DB_USERNAME=library_user - DB_PASSWORD=library_secret - DB_PORT=5432 - - # Backend - BACKEND_PORT=8080 - APP_ENV=production - APP_DEBUG=false - JWT_SECRET=your-secure-jwt-secret-change-this - - # Frontend - FRONTEND_PORT=3000 - API_URL=http://localhost:8080/api + GEMINI_API_KEY=your-key-from-aistudio.google.com ``` - > If no `.env` file is provided, the defaults shown above are used automatically. - -3. **Build and start the application** +3. **Build and start** ```bash docker compose up -d --build ``` Or with Podman: - ```bash podman compose up -d --build ``` @@ -148,56 +186,69 @@ A modern, multilingual web application for managing your personal home library. |----------|----------------------------| | Frontend | http://localhost:3000 | | Backend API | http://localhost:8080/api | - | Database | localhost:5432 | -5. **Login with default credentials** +5. **Login** + + | Field | Value | + |----------|--------------| + | Username | `admin` | + | Password | `Admin1234!` | + + > ⚠️ **Change this password immediately** via Settings page! - | Field | Value | - |----------|--------------------| - | Username | `admin` | - | Password | `Admin1234!` | +### Access from Phone (LAN) - > ⚠️ **Change this password immediately after first login!** +To use the scanner from your phone on the same network: +```env +# In .env, set your computer's LAN IP: +API_URL=http://192.168.1.x:8080/api +CORS_ORIGIN=http://192.168.1.x:3000 +``` +Then rebuild frontend: `docker compose up -d --build frontend` --- ## 📁 Project Structure ``` -bookoholik/ -├── docker-compose.yml # Container orchestration -├── .env # Environment variables (create manually) +home-library/ +├── docker-compose.yml +├── .env.example +├── sonar-project.properties +├── CONTRIBUTING.md +├── LICENSE ├── docker/ │ ├── Dockerfile.frontend # Vue.js multi-stage build -│ ├── Dockerfile.backend # PHP 8.3 + Apache +│ ├── Dockerfile.backend # PHP 8.3 + Apache + Tesseract + GD │ ├── Dockerfile.db # PostgreSQL + init script │ ├── Dockerfile.backup # Backup cron service -│ ├── nginx.conf # Frontend nginx configuration +│ ├── nginx.conf # Frontend nginx + security headers │ ├── apache.conf # Backend Apache vhost -│ ├── init.sql # Database schema & seed data +│ ├── init.sql # Database schema (10 tables) │ └── backup-cron.sh # Automated backup script ├── backend/ -│ ├── composer.json # PHP dependencies -│ ├── public/ -│ │ ├── index.php # Application entry point -│ │ └── .htaccess # Apache URL rewriting -│ ├── routes/ -│ │ └── api.php # API route definitions +│ ├── composer.json +│ ├── public/index.php # Entry point + CORS + security headers +│ ├── routes/api.php # 50+ API routes │ └── app/ -│ ├── Config/ -│ │ └── Database.php # PDO connection singleton +│ ├── Config/Database.php │ ├── Controllers/ │ │ ├── AuthController.php │ │ ├── BooksController.php │ │ ├── WritersController.php │ │ ├── GenresController.php +│ │ ├── PublishersController.php # NEW +│ │ ├── LocationsController.php # NEW +│ │ ├── ScanController.php # NEW (AI Vision) │ │ ├── LendingController.php │ │ ├── ReportsController.php │ │ ├── UsersController.php │ │ └── BackupController.php │ ├── Middleware/ │ │ ├── AuthMiddleware.php -│ │ └── AdminMiddleware.php +│ │ ├── AdminMiddleware.php +│ │ ├── UserMiddleware.php # NEW +│ │ └── RateLimiter.php # NEW │ └── Router.php ├── frontend/ │ ├── package.json @@ -205,34 +256,33 @@ bookoholik/ │ ├── tailwind.config.js │ ├── index.html │ └── src/ -│ ├── main.js # App entry + i18n setup -│ ├── App.vue # Root layout + nav + lang switcher -│ ├── i18n/ -│ │ ├── index.js # i18n configuration -│ │ ├── en.js # English translations -│ │ ├── ar.js # Arabic translations -│ │ └── fr.js # French translations -│ ├── router/ -│ │ └── index.js # Vue Router + guards -│ ├── services/ -│ │ └── api.js # Axios HTTP client -│ ├── store/ -│ │ ├── auth.js # Authentication store (Pinia) -│ │ └── toast.js # Toast notifications store +│ ├── main.js +│ ├── App.vue # Responsive nav + hamburger menu +│ ├── i18n/ # en.js, ar.js, fr.js +│ ├── router/index.js # 15 routes with guards +│ ├── services/api.js # Axios + token expiry check +│ ├── store/ # auth.js, toast.js │ └── views/ │ ├── LoginView.vue │ ├── DashboardView.vue │ ├── BooksView.vue │ ├── BookFormView.vue │ ├── BookDetailView.vue +│ ├── ScanBookView.vue # NEW (camera + AI) │ ├── WritersView.vue │ ├── GenresView.vue +│ ├── PublishersView.vue # NEW +│ ├── LocationsView.vue # NEW (hierarchy) │ ├── LendingView.vue │ ├── ReportsView.vue +│ ├── SettingsView.vue # NEW (profile + password) │ ├── UsersView.vue │ └── BackupView.vue -└── storage/ - └── backups/ # (created by container) +└── .github/ + ├── workflows/sonarqube.yml + └── ISSUE_TEMPLATE/ + ├── bug_report.md + └── feature_request.md ``` --- @@ -242,37 +292,71 @@ bookoholik/ ### Authentication | Method | Endpoint | Description | |--------|----------|-------------| -| POST | `/api/auth/login` | Login (public) | -| POST | `/api/auth/register` | Register (public) | +| POST | `/api/auth/login` | Login (rate limited) | +| POST | `/api/auth/register` | Register (rate limited) | | GET | `/api/auth/me` | Get current user | +| PUT | `/api/auth/profile` | Update profile info | | PUT | `/api/auth/password` | Change password | +### Book Scanner +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/api/scan/cover` | Scan front cover (AI + OCR) | +| POST | `/api/scan/back` | Scan back page (AI + OCR) | + ### Books | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/books` | List books (paginated, filterable) | -| GET | `/api/books/{id}` | Get book details | +| GET | `/api/books/{id}` | Get book details + lending history | | POST | `/api/books` | Create book | | PUT | `/api/books/{id}` | Update book | | DELETE | `/api/books/{id}` | Delete book | | POST | `/api/books/{id}/toggle-read` | Toggle read status | -| POST | `/api/books/isbn-lookup` | Lookup by ISBN | +| POST | `/api/books/isbn-lookup` | Lookup by ISBN (Open Library) | + +### Publishers +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/publishers` | List publishers (searchable) | +| GET | `/api/publishers/{id}` | Get publisher details | +| POST | `/api/publishers` | Create publisher (admin) | +| PUT | `/api/publishers/{id}` | Update publisher (admin) | +| DELETE | `/api/publishers/{id}` | Delete publisher (admin) | + +### Locations (Addresses → Rooms → Shelves) +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/locations/tree` | Full hierarchy for dropdowns | +| GET | `/api/locations` | List all addresses | +| GET | `/api/locations/{id}` | Get address + rooms + shelves | +| POST | `/api/locations` | Create address (admin) | +| PUT | `/api/locations/{id}` | Update address (admin) | +| DELETE | `/api/locations/{id}` | Delete address (admin) | +| GET | `/api/locations/{id}/rooms` | List rooms in address | +| POST | `/api/rooms` | Create room (admin) | +| PUT | `/api/rooms/{id}` | Update room (admin) | +| DELETE | `/api/rooms/{id}` | Delete room (admin) | +| GET | `/api/rooms/{id}/shelves` | List shelves in room | +| POST | `/api/shelves` | Create shelf (admin) | +| PUT | `/api/shelves/{id}` | Update shelf (admin) | +| DELETE | `/api/shelves/{id}` | Delete shelf (admin) | ### Writers | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/writers` | List all writers | | GET | `/api/writers/{id}` | Get writer + books | -| POST | `/api/writers` | Create writer | -| PUT | `/api/writers/{id}` | Update writer | -| DELETE | `/api/writers/{id}` | Delete writer | +| POST | `/api/writers` | Create writer (admin) | +| PUT | `/api/writers/{id}` | Update writer (admin) | +| DELETE | `/api/writers/{id}` | Delete writer (admin) | ### Genres | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/genres` | List all genres | -| POST | `/api/genres` | Create genre | -| PUT | `/api/genres/{id}` | Update genre | +| POST | `/api/genres` | Create genre (admin) | +| PUT | `/api/genres/{id}` | Update genre (admin) | | DELETE | `/api/genres/{id}` | Delete genre (admin) | ### Lending @@ -296,16 +380,12 @@ bookoholik/ | GET | `/api/reports/export/csv` | Export CSV | | GET | `/api/reports/export/pdf` | Export PDF | -### Admin — Users +### Admin — Users & Backup | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/users` | List users | | PUT | `/api/users/{id}` | Update user | | DELETE | `/api/users/{id}` | Delete user | - -### Admin — Backup -| Method | Endpoint | Description | -|--------|----------|-------------| | POST | `/api/backup/create` | Create backup | | GET | `/api/backup/list` | List backups | | GET | `/api/backup/download/{file}` | Download backup | @@ -315,128 +395,60 @@ bookoholik/ ## 🔧 Common Operations -### Stop the application ```bash +# Stop docker compose down -``` -### Reset database (fresh start) -```bash -docker compose down -v -docker compose up -d --build -``` +# Reset database (fresh start) +docker compose down -v && docker compose up -d --build -### View logs -```bash -docker compose logs -f # All services -docker compose logs -f backend # Backend only -docker compose logs -f frontend # Frontend only -``` +# View logs +docker compose logs -f backend -### Rebuild a single service -```bash +# Rebuild single service docker compose up -d --build frontend -``` -### Change API URL (if running on a different host) -```bash -API_URL=http://your-server:8080/api docker compose up -d --build frontend +# Access from phone (set your LAN IP in .env first) +API_URL=http://192.168.1.x:8080/api docker compose up -d --build frontend ``` --- -## 🔒 Security Notes - -This application has been security-hardened against the OWASP Top 10. Below are the administrator responsibilities for production deployment. - -### ⚠️ MANDATORY Before Going to Production - -1. **Generate strong secrets** — Copy `.env.example` to `.env` and generate all secrets: - ```bash - cp .env.example .env - # Generate each secret: - sed -i "s|CHANGE_ME_GENERATE_STRONG_PASSWORD|$(openssl rand -base64 24)|" .env - sed -i "s|CHANGE_ME_GENERATE_WITH_openssl_rand_base64_48|$(openssl rand -base64 48)|" .env - sed -i "s|CHANGE_ME_GENERATE_WITH_openssl_rand_base64_32|$(openssl rand -base64 32)|" .env - ``` - -2. **Change default admin password** — The default admin password is `Admin1234!`. Login and change it immediately via the Settings page. - -3. **Set `APP_DEBUG=false`** — Never enable debug mode in production. +## 🔒 Security -4. **Configure CORS origin** — Set `CORS_ORIGIN` in `.env` to your actual frontend URL: - ```env - CORS_ORIGIN=https://your-domain.com - ``` - -5. **Use HTTPS** — Deploy behind a reverse proxy (nginx/Caddy/Traefik) with TLS certificates. Update `API_URL` to use `https://`. - -6. **Database port is NOT exposed by default** — If you need direct DB access for development, uncomment the ports section in `docker-compose.yml`. Never expose in production. - -### 🔐 Backup Encryption (Recommended) - -Backups are stored as `.sql.gz` files. For production, encrypt them at rest: - -```bash -# Generate a GPG key for backup encryption -gpg --gen-key - -# Modify docker/backup-cron.sh to pipe through gpg: -# pg_dump ... | gzip | gpg --symmetric --cipher-algo AES256 --batch --passphrase-file /run/secrets/backup_key > ${BACKUP_FILE}.gpg -``` - -### 🔄 Disable Open Registration (Optional) - -Registration is rate-limited (3 per hour per IP) but publicly accessible. To restrict it to admin-only: - -1. Edit `backend/routes/api.php` -2. Change: - ```php - $router->post('/api/auth/register', [AuthController::class, 'register']); - ``` - To: - ```php - $router->post('/api/auth/register', [AuthController::class, 'register'], [AdminMiddleware::class]); - ``` - -### 🛡️ Additional Hardening (Recommended) - -| Action | How | -|--------|-----| -| Enable HSTS | Add `Strict-Transport-Security: max-age=31536000; includeSubDomains` in your reverse proxy | -| Rotate JWT secret | Change `JWT_SECRET` quarterly — all users will need to re-login | -| Monitor failed logins | Check container logs: `docker compose logs backend \| grep 401` | -| Update dependencies | Run `composer audit` and `npm audit` weekly | -| Scan container images | Use `trivy image bookoholik_backend` before deploying | -| Restrict registration | Move `/api/auth/register` behind `AdminMiddleware` (see above) | -| Database SSL | Enable SSL in PostgreSQL for encrypted connections between backend and DB | - -### 📋 Security Features Implemented +This application is security-hardened against the OWASP Top 10: | Feature | Status | |---------|--------| | SQL Injection protection (PDO prepared statements) | ✅ | | XSS prevention (Vue.js auto-escaping + htmlspecialchars) | ✅ | | CORS restricted to configured origin | ✅ | -| JWT authentication with expiry (8h) | ✅ | -| Rate limiting on login (5/15min) and registration (3/hr) | ✅ | +| JWT authentication with 8h expiry | ✅ | +| Rate limiting (login: 5/15min, register: 3/hr) | ✅ | | Password policy (10+ chars, uppercase, lowercase, number) | ✅ | | Role-based access control (Admin/User/Viewer) | ✅ | -| Security headers (X-Content-Type-Options, X-Frame-Options, CSP, etc.) | ✅ | +| Security headers (CSP, X-Frame-Options, etc.) | ✅ | | No hardcoded secrets (fails fast if env not set) | ✅ | | Command injection prevention (escapeshellarg) | ✅ | | Container resource limits (memory/CPU) | ✅ | | Database port not exposed by default | ✅ | -| Backup file permissions restricted (chmod 600) | ✅ | -| Secure .pgpass usage (not env var in process) | ✅ | -| HTML escaping in PDF exports | ✅ | -| Request timeout (30s) | ✅ | +| Secure backup file permissions (chmod 600) | ✅ | +| Request timeout (30s default, 60s for scans) | ✅ | | Token expiry check on frontend | ✅ | | Generic error messages (no stack traces to client) | ✅ | -### ⚠️ Known Advisory +See [Security Notes](#security-production) below for production deployment checklist. -- `firebase/php-jwt ^6.10` has advisory `PKSA-y2cr-5h3j-g3ys`. This is acknowledged in `composer.json`. Monitor for a patched version and upgrade when available. + +### Production Deployment Checklist + +1. Generate strong secrets in `.env` (see `.env.example`) +2. Change default admin password immediately +3. Set `APP_DEBUG=false` +4. Configure `CORS_ORIGIN` to your frontend domain +5. Deploy behind HTTPS reverse proxy (nginx/Caddy/Traefik) +6. Database port is NOT exposed by default ✓ +7. Optionally disable open registration (see `CONTRIBUTING.md`) --- @@ -445,14 +457,26 @@ Registration is rate-limited (3 per hour per IP) but publicly accessible. To res | Layer | Technology | |-------|-----------| | Frontend | Vue.js 3, Vite 5, Tailwind CSS 3, Pinia, Vue Router, Vue I18n, Axios | -| Backend | PHP 8.3, Apache, Custom Router, Firebase PHP-JWT, DomPDF | -| Database | PostgreSQL 16 | +| Backend | PHP 8.3, Apache, Custom Router, Firebase PHP-JWT, DomPDF, Tesseract OCR | +| AI Vision | Google Gemini Flash (free tier) | +| Database | PostgreSQL 16 (10 tables) | | Containerization | Docker / Podman Compose | -| Web Server (Frontend) | Nginx Alpine | -| Backup | pg_dump + cron | +| Web Server | Nginx Alpine (frontend), Apache (backend) | +| CI/CD | GitHub Actions + SonarQube | +| Backup | pg_dump + cron + gzip | + +--- + +## 🤝 Contributing + +Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. + +- 🐛 [Report a Bug](.github/ISSUE_TEMPLATE/bug_report.md) +- 💡 [Request a Feature](.github/ISSUE_TEMPLATE/feature_request.md) +- 🌐 **Translate** — Copy `frontend/src/i18n/en.js` to add a new language --- ## 📄 License -This project is licensed under the [MIT License](LICENSE). You are free to use, modify, and distribute this software. See the [LICENSE](LICENSE) file for details. +This project is licensed under the [MIT License](LICENSE). You are free to use, modify, and distribute this software.