Files
SpiceManagementSystem/README.md
T
Malek TellissiandClaude Sonnet 4.6 e14baca7e0
Deploy / deploy (push) Successful in 15s
Add LOT API v1 endpoint with full batch details
Route changed to /api/v1/{lot_number}. LotResource now includes
packing details, units_produced, quantity_g and recipe version.
CORS config added for public API access. README documents the
endpoint, example response and subdomain setup instructions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-12 16:43:48 +02:00

277 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SpiceManagementSystem
Warenwirtschafts-Panel für Gewürzmischungen — verwaltet Rohstoffe, Rezepte, Produkte, Chargen und Shopify-Sync.
Built with [Laravel](https://laravel.com) + [Filament](https://filamentphp.com), deployed via Docker.
---
## Lokale Entwicklung
**Voraussetzungen:** PHP 8.4, Composer, Node.js, MariaDB
```bash
composer install
npm install && npm run build
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serve
```
Die App läuft dann auf `http://localhost:8000`.
---
## Produktion (Docker)
Der Deploy läuft automatisch via Gitea Actions bei jedem Push auf `main`:
1. Dateien per SCP auf den VPS kopieren
2. `docker compose up -d --build` — baut das Image neu und startet die Container
3. `php artisan migrate --force` — läuft automatisch im Container
### Artisan-Befehle auf dem Server
Da die App in Docker mit PHP 8.4 läuft, müssen alle artisan-Befehle **im Container** ausgeführt werden:
```bash
cd ~/app && docker compose exec app php artisan <befehl>
```
---
## Shopify-Import
### Erstimport (Produkte + Lagerbestand + Beschreibung)
```bash
cd ~/app && docker compose exec app php artisan shopify:import
```
Optionen:
- `--dry-run` — zeigt nur an was importiert würde, speichert nichts
### Produktbilder herunterladen
```bash
cd ~/app && docker compose exec app php artisan shopify:images
```
Optionen:
- `--force` — lädt Bilder auch für Produkte neu, die bereits welche haben
### Lagerbestand + Preise synchronisieren
```bash
cd ~/app && docker compose exec app php artisan shopify:sync
```
---
## Chargen (LOT) & Rohstoff-Abzug
Beim Anlegen einer Charge wird der Rohstoffbestand automatisch abgezogen:
```
Charge: 50 Einheiten × 100g Standbodenbeutel = 5000g
→ Kurkuma (60%): 3000g vom Lager abgezogen
→ Pfeffer (30%): 1500g vom Lager abgezogen
→ Ingwer (10%): 500g vom Lager abgezogen
```
- Beim **Bearbeiten** einer Charge wird der Abzug neu berechnet
- Beim **Löschen** werden die Mengen zurückgebucht
- Chargen können direkt auf der Produktseite angelegt werden
---
## Rezept-Versionierung
Rezepte sind versioniert und einem Produkt zugeordnet:
- Jedes Rezept hat eine Versionsnummer (v1, v2, …)
- Beim Anlegen eines neuen Rezepts über das Produktformular wird die Version automatisch hochgezählt
- Ältere Versionen bleiben erhalten (z.B. für Chargen-Rückverfolgung)
---
## LOT-API
Öffentliche JSON-API zur Rückverfolgung von Chargen. Kein Auth erforderlich.
### Endpunkt
```
GET https://api.sms.spices.blue/api/v1/{lot_number}
```
### Beispiel-Antwort
```json
{
"data": {
"lot_number": "LOT-2024-001",
"produced_at": "2024-10-01",
"expires_at": "2026-10-01",
"units_produced": 50,
"quantity_g": 5000,
"product": {
"name": "Curry Klassik",
"description": "..."
},
"packing": {
"name": "Standbodenbeutel",
"size_g": 100,
"sku": "CUR-100",
"gtin": "4012345678901"
},
"recipe": {
"version": 3,
"created_at": "2024-09-15"
},
"spices": [
{
"name": "Kurkuma",
"percentage": 60.0,
"origin": {
"country": "Indien",
"farmer": "Singh Farm",
"supplier": "Gewürzhandel GmbH",
"notes": null
}
}
]
}
}
```
Fehler (nicht gefunden):
```json
{ "error": "LOT-Nummer nicht gefunden." }
```
### Subdomain-Setup auf dem Server
Der Container läuft intern auf `127.0.0.1:5000`. Der Host-Proxy (Nginx/Caddy) muss `api.sms.spices.blue` auf denselben Port zeigen — Beispiel für Nginx:
```nginx
server {
server_name api.sms.spices.blue;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
Danach SSL via `certbot --nginx -d api.sms.spices.blue` erneuern.
---
## Cronjob
Auf dem Server einrichten, damit der Laravel-Scheduler läuft:
```
* * * * * cd ~/app && docker compose exec -T app php artisan schedule:run >> /dev/null 2>&1
```
---
## Datenbankstruktur
```
Table spices {
id int [pk]
name varchar(255)
quantity decimal(10,2) -- immer in Gramm
unit varchar
}
Table recipes {
id int [pk]
product_id int [ref: > products.id, nullable]
version int -- auto-increment pro Produkt
name varchar(255)
description text
}
Table recipes_spices {
recipe_id int [ref: > recipes.id]
spice_id int [ref: > spices.id]
amount_in_percent decimal(4,2)
}
Table packings {
id int [pk]
name varchar(255)
size decimal(10,2) -- Gramm pro Einheit
}
Table products {
id int [pk]
title text
images json
description text
recipes_id int [ref: > recipes.id]
}
Table products_sizes {
id int [pk]
product_id int [ref: > products.id]
packing_id int [ref: > packings.id]
sku varchar
shopify_variant_id varchar
gtin varchar
price float
}
Table products_inventory {
id int [pk]
product_id int [ref: > products.id]
size_id int [ref: > products_sizes.id]
out_at timestamp
}
Table batches {
id int [pk]
lot_number varchar [unique]
product_id int [ref: > products.id]
size_id int [ref: > products_sizes.id]
recipe_id int [ref: > recipes.id]
units_produced int
quantity_g decimal(10,2) -- berechnet: units × packing.size
produced_at date
expires_at date
}
Table batch_origins {
id int [pk]
batch_id int [ref: > batches.id]
spice_id int [ref: > spices.id]
supplier_id int [ref: > suppliers.id, nullable]
origin_country varchar
farmer varchar
notes text
}
```
---
## Vision & Todo
**Fokus: Warenwirtschaft (Lager, Rohstoffe, Produkte)**
- [x] DB-Schema mit Produkthistorie
- [x] Rezepte mit Versionierung
- [x] Produktgrößen, Preise, SKU, GTIN mit Barcode-Vorschau
- [x] Inventar (eindeutige Items mit Ausgangs-Flag)
- [x] Chargen (LOT) mit automatischem Rohstoff-Abzug
- [x] Warenausgang (Produktverkauf)
- [x] Shopify-Import (Produkte, Varianten, Lagerbestand, Bilder, Beschreibung, Preise)
- [x] Continuous Deployment via Gitea Actions + Docker
- [x] Frontend (Sidebar, Navigation, Barcode-Preview, Bild-Grid)
- [x] LOT-API (JSON, öffentlich, Subdomain api.sms.spices.blue)
- [ ] Dashboard (Füllstände, Lager, Sales-Zeitspanne)