Analyzes all Taiga stories, maps hard/soft dependencies, and writes full specs (Goal, Data Model, Components, Verification, Open Questions) for every story before any implementation begins. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.0 KiB
4.0 KiB
Spec: 05 · Import Existing Publications
Taiga Story: #5 · 05-import-existing-publications
Status: Ready
Branch: feature/05-import-publications
Depends on: 03-import-fruit-db (fruits must exist), 04-fruit-publications (publications tables)
1. Goal
A standalone Python script imports all publications from 03-data/osws.xml, their cover images, linked fruits (determined by filesystem scan), PDFs, and fruit images into the database.
2. Background / Scope / Context / Constraints
- Separate file from the fruit import script — do not merge.
- Publication identified by XML
<obj>element where<osw>=1. - Fruit linking is NOT derived from
obstsorten.xmltags (unreliable subset) but from filesystem scan of03-data/osdb/{publicationId}/. - Image existence is not guaranteed — skip silently if file not found.
authorfield: skip if value is".".- Cover image path given by
<img>tag content (relative to03-data/).
File patterns in 03-data/osdb/{publicationId}/
| Pattern | Import target |
|---|---|
{fruitId}_{publicationId}_s0.jpg |
publication_fruit_images |
{fruitId}_{publicationId}.pdf |
publication_descriptions |
- Collect unique
fruitIdvalues from both patterns → union = linked fruit set. - Look up each
fruitIdagainstfruits.osdb_number→ skip if no match. - Link matched fruits via
publication_fruits.
3. Necessary Refactorings
- Script must run AFTER
import_fruits.py(fruits table populated). - Idempotent: use
INSERT … ON CONFLICT (osdb_pub_id) DO UPDATEfor publications; delete cascade clears linked data before re-import if re-run.
4. Related Data Model
Tables written (all created by story #4 migration):
publicationspublication_fruitspublication_descriptionspublication_fruit_images
5. Affected Places / Related Components
scripts/
import_fruits.py ← existing (story #3)
import_publications.py ← new
README_import.md ← update with run order and env var requirements
Script: scripts/import_publications.py
Steps:
- Parse
03-data/osws.xml; iterate<obj>where<osw>=1 - For each publication:
a. Extract id, name, author (skip if
".") b. Resolve cover image:03-data/{img_tag_value}— read bytes; skip if missing c.UPSERTintopublications(conflict onosdb_pub_id) d. Scan03-data/osdb/{id}/for*_s0.jpgand*.pdffiles e. Collect unique fruit IDs from filenames f. Resolve fruit IDs →fruits.idviaosdb_number; skip unresolved g. Delete existingpublication_fruitsfor this pub; re-insert linked fruits h. Delete existingpublication_descriptionsfor this pub; import PDFs i. Delete existingpublication_fruit_imagesfor this pub; import images - Log: publications upserted, cover images loaded, fruits linked, PDFs imported, images imported, skips
DB from DATABASE_URL env var.
6. Out of Scope
- Modifying publication CRUD API
- GUI import trigger
- Fruit import (handled by script #3)
7. Verification
| Check | Expected |
|---|---|
| Script runs to completion | Exit 0, logs summary counts |
| Re-run is idempotent | Same final row counts |
Publication with osw != 1 |
Not imported |
Author "." |
Stored as NULL |
| Cover image file missing | Skipped, publication still imported |
| Fruit ID from filename not in fruits table | Skipped with log warning |
GET /api/v1/publications after import |
Returns populated list |
| Spot-check: known publication | Correct title, linked fruits visible |
8. Open Questions
| # | Question | Impact |
|---|---|---|
| 1 | Exact XML element structure in osws.xml? (tag names, nesting) |
Parser field mapping |
| 2 | Can 03-data/osdb/{id}/ be missing entirely for some publications? |
Directory scan guard |
| 3 | Re-import strategy: delete-then-insert vs upsert per file? | Idempotency |
| 4 | Encoding of XML file (UTF-8 or Latin-1)? | ElementTree encoding param |