feat: uv config other feats

- add uv configuration for the backend
- update frontend to make auth work
- add new auth endpoints
- add bookmars feat
- add reader feat
This commit is contained in:
2026-06-03 22:06:01 -05:00
parent 730c748f5f
commit 6b4c0c43f8
137 changed files with 20319 additions and 2340 deletions
+117
View File
@@ -0,0 +1,117 @@
# 010 — Open Library metadata on import
**Status:** Implemented
**Created:** 2026-06-03
## Objective
After a user uploads an EPUB/PDF (`POST /api/books/ebooks/`), enrich the `EBook` with metadata and a cover from [Open Library](https://openlibrary.org/developers/api), using only **title** and **author** from the upload form. Prefer **Spanish** editions when available; fall back to English/any.
Upload must **never fail** if Open Library is down or no match is found.
## Trigger
- **Automatic:** `EBookUploadSerializer.create()` calls `enrich_ebook_metadata(ebook)` after file save.
- **Manual:** `POST /api/books/ebooks/{id}/enrich-metadata/` re-runs enrichment (owner only).
## Open Library usage
### Search
`GET https://openlibrary.org/search.json`
| Param | Value |
|-------|--------|
| `title` | User-provided title |
| `author` | User-provided author |
| `lang` | `es` (primary) or `en` (fallback) |
| `limit` | `5` |
| `fields` | `key,title,author_name,cover_i,first_publish_year,subject,language,edition_key,number_of_pages_median,publisher` |
Primary pass also uses query filter `language:spa`. Fallback omits language filter.
### Covers
`GET https://covers.openlibrary.org/b/id/{cover_i}-L.jpg` — downloaded and stored on `EBook.cover_image`.
## Match scoring
| Score | Behavior |
|-------|----------|
| ≥ 0.8 | Apply OL title/author + cover + full metadata |
| 0.6 0.8 | Metadata + cover only; keep user title/author |
| < 0.6 | `match_status: not_found`; no field changes except metadata stub |
Author overlap + title similarity (normalized strings, `difflib.SequenceMatcher`). Prefer hits with `cover_i`.
## Data model
No migration. Uses existing fields on `EBook`:
- `metadata_json` — full enrichment payload (see below)
- `cover_image` — downloaded cover file
- `title` / `author` — updated when match score ≥ 0.8
### `metadata_json` shape
```json
{
"source": "openlibrary",
"matched_at": "2026-06-03T12:00:00+00:00",
"match_language": "es",
"match_score": 0.92,
"match_status": "matched",
"user_input": { "title": "...", "author": "..." },
"openlibrary": {
"work_key": "/works/OL...",
"edition_key": "...",
"title": "...",
"authors": ["..."],
"cover_id": 12345,
"cover_url": "https://covers.openlibrary.org/b/id/12345-L.jpg",
"first_publish_year": 1605,
"subjects": ["..."],
"languages": ["spa"],
"publishers": ["..."],
"number_of_pages_median": 320
}
}
```
## API changes
### Upload response (unchanged path)
`POST /api/books/ebooks/` — response may include populated `cover_image` and updated `title`/`author` after sync enrichment.
### Detail
`GET /api/books/ebooks/{id}/` — adds read-only `metadata` (alias of `metadata_json`).
### Manual refresh
`POST /api/books/ebooks/{id}/enrich-metadata/` — returns updated `EBookDetailSerializer` payload.
## Configuration
| Env var | Default | Description |
|---------|---------|-------------|
| `OPENLIBRARY_ENABLED` | `true` | Kill switch |
| `OPENLIBRARY_PREFERRED_LANG` | `es` | Primary `lang` param |
| `OPENLIBRARY_FALLBACK_LANG` | `en` | Fallback `lang` param |
| `OPENLIBRARY_TIMEOUT_SECONDS` | `5` | HTTP timeout |
| `OPENLIBRARY_USER_AGENT` | `CloudReader/1.0` | User-Agent header |
## Code layout
```
backend/apps/books/services/
├── openlibrary.py # Search, scoring, cover download
└── metadata.py # enrich_ebook_metadata orchestrator
```
## Verification
1. Upload with title `Don Quijote`, author `Cervantes` → cover + Spanish-friendly metadata.
2. Upload with nonsense title/author → 201, no cover, `match_status: not_found`.
3. `POST .../enrich-metadata/` on existing ebook refreshes metadata.