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.6 KiB
4.6 KiB
Spec: 03 · Import Old Obstsorten DB
Taiga Story: #3 · 03-import-old-obstsorten-db
Status: Ready
Branch: feature/03-import-fruit-db
Depends on: 02-manage-fruits (fruits, fruit_synonyms, fruit_images tables)
1. Goal
Populate the fruits, fruit_synonyms, and fruit_images tables from the legacy XML export and image files. Delivered as a repeatable SQL/Go/Python script that can be re-run safely (delete-before-insert per fruit).
2. Background / Scope / Context / Constraints
- Source XML:
03-data/obstsorten.xml - Image directories:
- Fruit images:
03-data/einzelfruechte/(use files containing_s0before extension) - Flower images:
03-data/blueten/(use_s0files) - Tree images:
03-data/baume/(use_s0files)
- Fruit images:
- Image filename pattern:
{id}_*_s0.{ext}— prefix = fruit id - Type mapping from XML
typfield →fruit_typeenum (see below) created_atsourced from XMLaddeddate field (fallback: NOW())- OSDB number = XML
idfield - Script must be idempotent: delete existing images and synonyms for each fruit before re-inserting
Type Mapping
XML typ |
DB fruit_type |
|---|---|
x |
Apfelsorten (Alle Obstsorten → map to most common or skip if no direct match) |
a |
Apfelsorten |
bq |
Birnensorten (Birnen- und Quittensorten → split not possible in enum, use Birnensorten) |
b |
Birnensorten |
w |
Wein |
q |
Quittensorten |
aprpfi |
Aprikosen |
apr |
Aprikosen |
pfi |
Pfirsiche |
mirren |
Mirabellen |
mir |
Mirabellen |
ren |
Renekloden |
pflzwe |
Pflaumen |
pfl |
Pflaumen |
zwe |
Zwetschen |
k |
Sauerkirschen |
bo |
Brombeeren |
bob |
Brombeeren |
boe |
Erdbeeren |
boh |
Himbeeren |
boj |
Johannisbeeren |
bos |
Stachelbeeren |
wei |
Wein |
Note on ambiguous types (
x,bq,aprpfi,mirren,pflzwe,bo,k): these map to aggregate categories not directly in the enum. Use the primary type as shown above. Log a warning for each skipped or coerced row.
3. Necessary Refactorings
- Confirm
fruit_images.image_typeaccepts'fruit','flower','tree'(already in migration from story #2). - Leave title blank as specified.
4. Related Data Model
Tables consumed (no new migrations):
fruits— insert/upsert perosdb_numberfruit_synonyms— delete cascade then re-insert per fruitfruit_images— delete per fruit then re-insert
5. Affected Places / Related Components
Script: scripts/import_fruits.py
Recommended language: Python (XML parsing, file I/O, psycopg2).
scripts/
import_fruits.py ← main import script
README_import.md ← how to run
Steps:
- Parse
03-data/obstsorten.xmlwithxml.etree.ElementTree - For each
<sorte>element: a. Maptyp→ enum value (log+skip if unmappable) b. Splitsynonymby comma → list of synonyms c. DELETE FROM fruit_synonyms WHERE fruit_id = (SELECT id FROM fruits WHERE osdb_number = id_val) d. DELETE FROM fruit_images WHERE fruit_id = ... e. UPSERT intofruits(INSERT … ON CONFLICT (osdb_number) DO UPDATE) f. INSERT synonyms g. Find matching images in each image directory (glob{id}_*_s0.*) h. INSERT intofruit_imagesfor each found image - Log counts: fruits upserted, synonyms inserted, images inserted, warnings
DB connection from DATABASE_URL env var.
6. Out of Scope
- Importing publications (story #5)
- Modifying the fruit CRUD API
- GUI trigger for import
7. Verification
| Check | Expected |
|---|---|
| Script runs without error on full dataset | Exit 0 |
| Re-run is idempotent | Same row counts; no duplicate key errors |
| Spot-check: known fruit by osdb_number | Correct name, type, synonyms in DB |
| At least one image per fruit (if source exists) | fruit_images rows with non-null data |
Unknown typ values |
Logged as warnings, fruit still inserted with best-guess type |
GET /api/v1/fruits after import |
Returns populated list |
8. Open Questions
| # | Question | Impact |
|---|---|---|
| 1 | Exact XML element/attribute names in obstsorten.xml? |
Parser field mapping |
| 2 | What to do with typ = 'x' (Alle Obstsorten)? Skip, or map to first enum value? |
Data integrity |
| 3 | Are there fruits without any matching image file? | Expected → just 0 images |
| 4 | added date field format in XML? |
created_at parse |
| 5 | Should bq, aprpfi, mirren, pflzwe, bo, k map as above or produce error? |
Type fidelity |