Files
osdb-1-claude-opusplan/docs/planning/specs/06-fruit-search.md
T
juliaandClaude Sonnet 4.6 1070ba3ac1 docs: add sprint planning — dependency diagram + specs for all 8 stories
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>
2026-06-16 11:53:24 +02:00

138 lines
4.1 KiB
Markdown

# Spec: 06 · Fruit Search
**Taiga Story:** #6 · `06-fruit-search`
**Status:** Ready
**Branch:** `feature/06-fruit-search`
**Depends on:** `02-manage-fruits` (fruits + fruit_synonyms)
---
## 1. Goal
Improve the fruit list search: users can filter by name/synonym text and optionally by type. Combined-type aliases (e.g. "Birnen- und Quittensorten") match both constituent types.
---
## 2. Background / Scope / Context / Constraints
- Target component: `FruitList.vue` (search bar already exists as placeholder from story #2).
- Search is case-insensitive, substring match on `fruits.name` OR any `fruit_synonyms.synonym`.
- Type filter is optional; when set, filters to exactly that enum value OR to its alias group.
- Combined-type aliases (not in the enum — only in search UI):
| Alias | Matches enum values |
|-------|-------------------|
| Birnen- und Quittensorten | `Birnensorten`, `Quittensorten` |
| Aprikosen und Pfirsiche | `Aprikosen`, `Pfirsiche` |
| Mirabellen und Reineclauden | `Mirabellen`, `Renekloden` |
| Pflaumen und Zwetschen | `Pflaumen`, `Zwetschen` |
- Search is client-triggered (on input, debounced) or button-triggered — consistent with existing UX pattern.
- API already supports `?name=` and `?type=` query params (placeholder from story #2); this story implements them correctly on the backend.
---
## 3. Necessary Refactorings
- `GET /api/v1/fruits` handler: add SQL filter logic for `name` (ILIKE on name + JOIN synonyms) and `type` (exact enum match or multi-value IN for aliases).
- `FruitList.vue`: wire up search input + type dropdown to API query params.
---
## 4. Related Data Model
No new tables or migrations. Query pattern:
```sql
SELECT DISTINCT f.*
FROM fruits f
LEFT JOIN fruit_synonyms fs ON fs.fruit_id = f.id
WHERE
($name = '' OR f.name ILIKE '%' || $name || '%' OR fs.synonym ILIKE '%' || $name || '%')
AND ($types IS NULL OR f.fruit_type = ANY($types::fruit_type[]))
ORDER BY f.name;
```
`$types` is an array expanded from the selected alias or single type value.
---
## 5. Affected Places / Related Components
### Backend
| File | Change |
|------|--------|
| `backend/internal/repository/fruit_repo.go` | `List(name, types []string)` — parameterized SQL |
| `backend/internal/handler/fruit_handler.go` | Parse `?name=` and `?type=` query params; resolve alias → types array |
| `backend/internal/domain/fruit.go` | Add alias map constant |
### Frontend
| File | Change |
|------|--------|
| `frontend/src/views/FruitList.vue` | Search text input (debounced 300 ms) + type dropdown (enum values + aliases) |
| `frontend/src/api/fruits.ts` | `listFruits({name?, type?})` passes query params |
| `frontend/src/stores/fruitStore.ts` | Store search state; trigger reload on change |
### Type Dropdown Options
```
(All)
Apfelsorten
Birnensorten
Quittensorten
Birnen- und Quittensorten ← alias
Aprikosen
Pfirsiche
Aprikosen und Pfirsiche ← alias
Mirabellen
Renekloden
Mirabellen und Reineclauden ← alias
Pflaumen
Zwetschen
Pflaumen und Zwetschen ← alias
Sauerkirschen
Süßkirschen
Brombeeren
Erdbeeren
Himbeeren
Johannisbeeren
Stachelbeeren
Wein
```
---
## 6. Out of Scope
- Full-text search index (pg `tsvector`) — ILIKE sufficient for expected dataset size
- Search in comment field
- Sorting controls
- Pagination (defer to later if needed)
---
## 7. Verification
| Check | Expected |
|-------|---------|
| Search "Boskop" → results include fruit named "Boskop" | Pass |
| Search "boskop" (lowercase) | Same results (case-insensitive) |
| Search by synonym term | Fruits with matching synonym appear |
| Filter "Birnensorten" | Only Birnensorten fruits |
| Filter "Birnen- und Quittensorten" | Birnensorten AND Quittensorten fruits |
| Combined name + type filter | Intersection of both |
| Empty search + no type filter | All fruits |
| `go test ./...` — repo list filter tests | Green |
---
## 8. Open Questions
| # | Question | Impact |
|---|----------|--------|
| 1 | Debounce delay: 300 ms sufficient or user preference? | UX |
| 2 | Search on `Enter` only vs real-time? | UX |
| 3 | Type dropdown: grouped by alias vs flat list? | UX clarity |