feat: Stores (Geschäfte) für Einkaufslisten (closes #52) #54

Merged
admin-mrrm merged 1 commit from feat/stores-for-shopping-lists into main 2026-04-25 17:00:12 +02:00
Owner

Schließt #52.

Was ändert sich

Neue Entity: Store (Geschäft)

Eigene User-owned Entity mit Name + erweiterb-arem JSONB-details-Feld:

{ address?, url?, phone?, notes? }

Neue Eigenschaften (z.B. openingHours, category) werden nur in storeDetailsSchema ergänzt — keine DB-Migration nötig.

Backend

  • Migration 0004_volatile_odin.sql: stores-Tabelle + lists.store_id (nullable FK, ON DELETE SET NULL — löscht man ein Geschäft, bleibt die Liste erhalten und storeId wird auf null gesetzt).
  • StoresModule: GET/POST /stores, PATCH/DELETE /stores/:id. Ownership-Check identisch zu ListsModule (ownerSub).
  • ListsService: storeId bei create/update durchreichen + Ownership-Prüfung (Store muss dem gleichen User gehören wie die Liste).

shared-types

  • stores.ts neu: storeDetailsSchema, Store, CreateStoreDto, UpdateStoreDto.
  • lists.ts: listSchema / createListDtoSchema / updateListDtoSchema um storeId?: string | null erweitert.

api-client

  • StoresResource (list/create/update/delete) neu.
  • ApiClient.stores ergänzt.

feature-lists

  • StoresScreen: CRUD-Screen für Geschäfte — Name + Details (address/url/phone/notes) inline bearbeiten.
  • ListsOverviewScreen: Store-Picker im Create-Formular (nur bei type === 'shopping'); Store-Name als Subtitle im Listeneintrag; onManageStores?-Prop.
  • stores-hooks.ts: useStores, useCreateStore, useUpdateStore, useDeleteStore.

feature-shopping-list

  • ShoppingList.storeId? und UpdateShoppingListDto.storeId ergänzt.
  • toShoppingList() mappt storeId automatisch durch (bestehender Spread).
  • ShoppingListScreen: StoreBadge im Header — zeigt Geschäft, erlaubt Wechsel und Zuweisung.
  • adapters.test.ts: storeId-Fälle ergänzt, alle 16 Tests grün.

Web + Mobile

  • Web: /stores-Route + „Stores"-Link in der Navbar + onManageStores in ListsRoute.
  • Mobile: app/stores/index.tsx + Link auf Home-Screen.

Test plan

  • pnpm -r typecheck — alle 10 Workspaces grün
  • pnpm --filter feature-shopping-list test — 16 Tests grün
  • Store „Aldi" anlegen (/stores) — name + address + url befüllen
  • Neue Shopping-Liste „Wocheneinkauf" mit Store „Aldi" anlegen
  • Liste öffnen → Store im Header sehen; Store wechseln
  • Store „Aldi" löschen → Liste zeigt keinen Store mehr (storeId: null)
  • Regression: notes- und todo-Listen bleiben unverändert

🤖 Generated with Claude Code

Schließt #52. ## Was ändert sich ### Neue Entity: `Store` (Geschäft) Eigene User-owned Entity mit Name + erweiterb-arem JSONB-`details`-Feld: ``` { address?, url?, phone?, notes? } ``` Neue Eigenschaften (z.B. `openingHours`, `category`) werden nur in `storeDetailsSchema` ergänzt — **keine DB-Migration nötig**. ### Backend - **Migration `0004_volatile_odin.sql`**: `stores`-Tabelle + `lists.store_id` (nullable FK, `ON DELETE SET NULL` — löscht man ein Geschäft, bleibt die Liste erhalten und `storeId` wird auf `null` gesetzt). - **StoresModule**: `GET/POST /stores`, `PATCH/DELETE /stores/:id`. Ownership-Check identisch zu ListsModule (ownerSub). - **ListsService**: `storeId` bei `create`/`update` durchreichen + Ownership-Prüfung (Store muss dem gleichen User gehören wie die Liste). ### shared-types - `stores.ts` neu: `storeDetailsSchema`, `Store`, `CreateStoreDto`, `UpdateStoreDto`. - `lists.ts`: `listSchema` / `createListDtoSchema` / `updateListDtoSchema` um `storeId?: string | null` erweitert. ### api-client - `StoresResource` (list/create/update/delete) neu. - `ApiClient.stores` ergänzt. ### feature-lists - `StoresScreen`: CRUD-Screen für Geschäfte — Name + Details (address/url/phone/notes) inline bearbeiten. - `ListsOverviewScreen`: Store-Picker im Create-Formular (nur bei `type === 'shopping'`); Store-Name als Subtitle im Listeneintrag; `onManageStores?`-Prop. - `stores-hooks.ts`: `useStores`, `useCreateStore`, `useUpdateStore`, `useDeleteStore`. ### feature-shopping-list - `ShoppingList.storeId?` und `UpdateShoppingListDto.storeId` ergänzt. - `toShoppingList()` mappt `storeId` automatisch durch (bestehender Spread). - `ShoppingListScreen`: `StoreBadge` im Header — zeigt Geschäft, erlaubt Wechsel und Zuweisung. - `adapters.test.ts`: `storeId`-Fälle ergänzt, alle 16 Tests grün. ### Web + Mobile - Web: `/stores`-Route + „Stores"-Link in der Navbar + `onManageStores` in ListsRoute. - Mobile: `app/stores/index.tsx` + Link auf Home-Screen. ## Test plan - [x] `pnpm -r typecheck` — alle 10 Workspaces grün - [x] `pnpm --filter feature-shopping-list test` — 16 Tests grün - [ ] Store „Aldi" anlegen (`/stores`) — name + address + url befüllen - [ ] Neue Shopping-Liste „Wocheneinkauf" mit Store „Aldi" anlegen - [ ] Liste öffnen → Store im Header sehen; Store wechseln - [ ] Store „Aldi" löschen → Liste zeigt keinen Store mehr (`storeId: null`) - [ ] Regression: notes- und todo-Listen bleiben unverändert 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: Stores (Geschäfte) für Einkaufslisten (closes #52)
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
689c27065a
Neue `stores`-Entity — User-owned Geschäfte mit Name + erweiterb-
arem JSONB-`details`-Feld (address, url, phone, notes; neue Felder
ohne DB-Migration ergänzbar).

## shared-types
- Neues `stores.ts`: storeDetailsSchema / Store / CreateStoreDto /
  UpdateStoreDto.
- `lists.ts`: listSchema / createListDtoSchema / updateListDtoSchema
  um `storeId?: string | null` erweitert.

## API (apps/api)
- Neues StoresModule: Controller + Service + Drizzle-Schema.
  Endpoints: GET/POST /stores, PATCH/DELETE /stores/:id.
  Ownership-Check identisch zu ListsModule (ownerSub).
- Migration 0004_volatile_odin.sql: `stores`-Tabelle + `lists.store_id`
  nullable FK mit ON DELETE SET NULL.
- ListsService: storeId beim create/update durchreichen + Ownership-
  Prüfung (storeId muss dem gleichen User gehören).

## api-client
- Neues StoresResource (list/create/update/delete).
- ApiClient bekommt `stores`-Property.

## feature-lists
- `stores-hooks.ts`: useStores / useCreateStore / useUpdateStore /
  useDeleteStore.
- `StoresScreen`: CRUD-Screen für Geschäfte — Name + Details (address/
  url/phone/notes) inline bearbeiten, analog NotesListScreen.
- `ListsOverviewScreen`: Store-Picker (nur bei type=shopping) im
  Create-Formular; Store-Name als Subtitle im Listen-Eintrag;
  `onManageStores?`-Prop für Link zum StoresScreen.

## feature-shopping-list
- `ShoppingList.storeId?: string | null` in types.ts.
- `UpdateShoppingListDto.storeId` ergänzt.
- `toShoppingList()` mappt storeId automatisch durch (Spread).
- `ShoppingListScreen`: StoreBadge zeigt aktuelles Geschäft im Header;
  inline Store wechseln / zuweisen via useUpdateShoppingList.
- adapters.test.ts: storeId-Fälle für toShoppingList ergänzt.

## Web + Mobile
- Web: /stores-Route + "Stores"-Link im Nav + onManageStores in ListsRoute.
- Mobile: app/stores/index.tsx + Link auf Home-Screen + expo-router
  typed-routes um /stores erweitert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
admin-mrrm force-pushed feat/stores-for-shopping-lists from 689c27065a
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
to 8613a6c642
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2026-04-25 16:43:38 +02:00
Compare
admin-mrrm deleted branch feat/stores-for-shopping-lists 2026-04-25 17:00:12 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
admin-mrrm/mrrmlabapp!54
No description provided.