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
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00
2026-09-11 01:17:47 +02:00

SpiceManagementSystem

Warenwirtschafts-Panel für Gewürzmischungen — verwaltet Rohstoffe, Rezepte, Produkte, Chargen und Shopify-Sync.

Built with Laravel + Filament, deployed via Docker.


Lokale Entwicklung

Voraussetzungen: PHP 8.4, Composer, Node.js, MariaDB

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:

cd ~/app && docker compose exec app php artisan <befehl>

Shopify-Import

Erstimport (Produkte + Lagerbestand + Beschreibung)

cd ~/app && docker compose exec app php artisan shopify:import

Optionen:

  • --dry-run — zeigt nur an was importiert würde, speichert nichts

Produktbilder herunterladen

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

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

{
  "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):

{ "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:

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)

  • DB-Schema mit Produkthistorie
  • Rezepte mit Versionierung
  • Produktgrößen, Preise, SKU, GTIN mit Barcode-Vorschau
  • Inventar (eindeutige Items mit Ausgangs-Flag)
  • Chargen (LOT) mit automatischem Rohstoff-Abzug
  • Warenausgang (Produktverkauf)
  • Shopify-Import (Produkte, Varianten, Lagerbestand, Bilder, Beschreibung, Preise)
  • Continuous Deployment via Gitea Actions + Docker
  • Frontend (Sidebar, Navigation, Barcode-Preview, Bild-Grid)
  • LOT-API (JSON, öffentlich, Subdomain api.sms.spices.blue)
  • Dashboard (Füllstände, Lager, Sales-Zeitspanne)
S
Description
No description provided
Readme
1.3 MiB
0 Stars 1 Watchers 0 Forks
Languages
PHP 97.5%
Blade 1.4%
Dockerfile 0.6%
Shell 0.4%
JavaScript 0.1%