feat: import Vendoo 1.40.2 capability graph contract hotfix

This commit is contained in:
Markus Müller
2026-07-09 15:35:59 +02:00
parent 52d480adc9
commit a53295b33d
1334 changed files with 211685 additions and 209 deletions
+27
View File
@@ -0,0 +1,27 @@
.git
.gitignore
.env
.env.*
!.env.example
node_modules
npm-debug.log*
*.log
*.db
*.db-*
*.sqlite
*.sqlite3
backups
operations
logs
uploads
runtime
data
local-ai/comfyui
local-ai/downloads
local-ai/.env.local-flux
MockupDesign
*.zip
FILE_CHECKSUMS_SHA256.txt
release-output
.vendoo-github-state.json
operations/first-admin-code.txt
+78 -22
View File
@@ -1,33 +1,89 @@
NODE_ENV=development # Vendoo 1.37.0 Beispielkonfiguration für Windows, Docker und NAS
HOST=127.0.0.1 # Diese Datei enthält ausschließlich Platzhalter. Für den Betrieb als .env kopieren.
PORT=8124 # Niemals eine produktive .env in Release-ZIPs, Git oder Support-Logs aufnehmen.
PUBLIC_BASE_URL=http://localhost:8124
TRUST_PROXY=0
COOKIE_SECURE=false
COOKIE_SAMESITE=lax
ALLOWED_ORIGINS=http://localhost:8124
DATA_DIR=./data
DB_PATH=./db/vendoo.db
UPLOAD_DIR=./uploads
BACKUP_DIR=./backups
SESSION_SECRET=
ANTHROPIC_API_KEY= ANTHROPIC_API_KEY=
OPENAI_API_KEY= OPENAI_API_KEY=
OPENROUTER_API_KEY= OPENROUTER_API_KEY=
OLLAMA_URL=http://localhost:11434 OLLAMA_URL=http://localhost:11434
LOCAL_IMAGE_ENABLED=false
SMTP_HOST= LOCAL_IMAGE_URL=http://127.0.0.1:8188
SMTP_PORT=587 LOCAL_IMAGE_TOKEN=
SMTP_SECURE=false LOCAL_IMAGE_WORKFLOW_PATH=local-ai/workflows/vendoo_flux_schnell_api.json
SMTP_USER= LOCAL_IMAGE_INSTALL_PATH=local-ai/comfyui
SMTP_PASSWORD= LOCAL_IMAGE_REQUIRE_TOKEN=true
SMTP_FROM= LOCAL_IMAGE_ALLOW_REMOTE=false
ETSY_API_KEY= ETSY_API_KEY=
ETSY_CLIENT_SECRET= ETSY_CLIENT_SECRET=
EBAY_CLIENT_ID= EBAY_CLIENT_ID=
EBAY_CLIENT_SECRET= EBAY_CLIENT_SECRET=
EBAY_RUNAME= EBAY_RU_NAME=
EBAY_SANDBOX=true EBAY_SANDBOX=true
SMTP_HOST=smtp.example.de
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=
SMTP_PASS=
SMTP_FROM=Vendoo <vendoo@example.de>
PORT=8124
# Docker veröffentlicht standardmäßig nur an 127.0.0.1. Für NAS-Reverse-Proxy ggf. bewusst anpassen.
VENDOO_PUBLISH_ADDRESS=127.0.0.1
VENDOO_HOST_PORT=8124
# Vom Smartphone erreichbare Basis-URL für QR-Fotouploads.
# Beispiel im LAN: http://192.168.178.50:8124
# Öffentlich ausschließlich per HTTPS verwenden.
PUBLIC_BASE_URL=
# Nur für den geführten VPS-Modus; setup.sh trägt die Domain automatisch ein.
VENDOO_DOMAIN=
# Optional: öffentliche JSON-Manifest-URL für die Updateprüfung
VENDOO_UPDATE_MANIFEST_URL=
# Server-, Mehrbenutzer- und Deployment-Sicherheit (1.37.0)
# Standardmäßig nur auf diesem PC erreichbar. Für LAN bewusst auf 0.0.0.0 setzen.
VENDOO_BIND_HOST=127.0.0.1
# Kommagetrennte zusätzliche Hostnamen/IPs, z. B. vendoo.intern,192.168.178.50
VENDOO_ALLOWED_HOSTS=
# Kommagetrennte zusätzliche Browser-Ursprünge, jeweils mit Protokoll und Port
VENDOO_ALLOWED_ORIGINS=
# Nur hinter einem korrekt konfigurierten Reverse Proxy aktivieren
VENDOO_TRUST_PROXY=false
VENDOO_SESSION_DAYS=3
VENDOO_SESSION_IDLE_MINUTES=120
VENDOO_READ_RATE_LIMIT=360
VENDOO_MUTATION_RATE_LIMIT=120
# Produktionsbereitstellung 1.37.0
# Mindestens 32 zufällige Zeichen. Wird beim ersten Admin-Setup abgefragt.
VENDOO_SETUP_TOKEN=
VENDOO_REQUIRE_SETUP_TOKEN=true
VENDOO_COOKIE_SECURE=auto
VENDOO_COOKIE_SAMESITE=lax
# Konkrete Extension-Origins, z. B. chrome-extension://abcdefghijklmnop...
VENDOO_EXTENSION_ORIGINS=
VENDOO_ALLOW_ANY_EXTENSION_ORIGIN=false
# Optionale getrennte Laufzeitpfade. Windows kann die Standardwerte leer lassen.
VENDOO_DATA_DIR=
VENDOO_DB_PATH=
VENDOO_UPLOADS_DIR=
VENDOO_BACKUP_DIR=
VENDOO_OPERATIONS_DIR=
VENDOO_LOG_DIR=
# Docker setzt automatisch /app/data/config/vendoo.env; lokal bleibt dieser Wert leer.
VENDOO_CONFIG_PATH=
# Security, Secrets & Observability (1.37.0)
# Normalerweise automatisch verwaltet; keine manuelle Bearbeitung erforderlich.
# VENDOO_SECRETS_PATH=/app/data/config/secrets.enc.json
# VENDOO_MASTER_KEY_FILE=/app/data/config/master.key
# Optional: externer 32-Byte-Master-Key als Base64 oder 64 Hex-Zeichen.
# VENDOO_MASTER_KEY=
VENDOO_JSON_LOGS=true
SMTP_TLS_REJECT_UNAUTHORIZED=true
+1
View File
@@ -0,0 +1 @@
* @Masterluke77
+27
View File
@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: '05:00'
timezone: Europe/Berlin
open-pull-requests-limit: 5
groups:
npm-production:
dependency-type: production
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
time: '05:30'
timezone: Europe/Berlin
open-pull-requests-limit: 5
- package-ecosystem: docker
directory: /
schedule:
interval: monthly
time: '06:00'
timezone: Europe/Berlin
open-pull-requests-limit: 5
+20
View File
@@ -0,0 +1,20 @@
## Änderung
<!-- Was wurde geändert und warum? -->
## Sicherheit und Daten
- [ ] Keine `.env`, Tokens, Datenbanken, Uploads, Backups, Logs oder Modelle enthalten
- [ ] Bestehende Benutzer- und Artikeldaten bleiben erhalten
- [ ] Originalbilder werden nicht überschrieben
- [ ] FASHN VTON / Virtual Try-on wurde nicht wieder eingeführt
## Prüfung
- [ ] `npm ci`
- [ ] `npm run verify:git`
- [ ] `npm run check`
- [ ] `npm run verify:architecture`
- [ ] `npm run verify:deployment`
- [ ] `npm run verify:db`
- [ ] Windows-/Docker-/Browser-Abnahme dokumentiert oder ausdrücklich als offen markiert
+104
View File
@@ -0,0 +1,104 @@
name: Vendoo CI
on:
push:
branches: [main, develop, 'feature/**', 'release/**', 'hotfix/**']
pull_request:
branches: [main, develop]
permissions:
contents: read
concurrency:
group: vendoo-ci-${{ github.ref }}
cancel-in-progress: true
jobs:
quality:
name: Syntax, Sicherheit und Release-Gates
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Repository auschecken
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Node.js 22 aktivieren
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: npm
- name: Abhängigkeiten reproduzierbar installieren
run: npm ci
- name: Git-Sicherheitsgate
run: npm run verify:git
- name: Git-Sicherheitsgate Regressionstest
run: npm run verify:git-regression
- name: Git-Staging-Filter Regressionstest
run: npm run verify:git-staging
- name: Syntaxprüfung
run: npm run check
- name: ESM-Exportverträge prüfen
run: npm run verify:esm-exports
- name: FLUX-Loop-Hotfix prüfen
run: npm run verify:flux-loop
- name: Vollständigen Modul-Capability-Graph prüfen
run: npm run verify:capabilities
- name: Plattformarchitektur und Design Tokens prüfen
run: npm run verify:architecture
- name: Theme Manager, Accessibility und Komponenten-Tokens prüfen
run: npm run verify:themes
- name: Security, Secrets und Observability prüfen
run: npm run verify:security
- name: Auth, Benutzer, Sitzungen und Einstellungen prüfen
run: npm run verify:identity
- name: Artikel, Lager und Medien prüfen
run: npm run verify:catalog
- name: Modulmanager, Pakete und Aktivierungsgrenzen prüfen
run: npm run verify:modules
- name: Deployment-Gate
run: npm run verify:deployment
- name: Persistenten Konfigurationsspeicher prüfen
run: npm run verify:config
- name: Geführte Shell-Installer simulieren
run: npm run verify:installer-shell
- name: Datenbankmigrationen prüfen
run: npm run verify:db
- name: Docker-Compose-Dateien validieren
run: |
cp .env.example .env
python - <<'PY'
from pathlib import Path
p=Path('.env')
s=p.read_text()
s=s.replace('VENDOO_SETUP_TOKEN=', 'VENDOO_SETUP_TOKEN=ci-only-not-a-production-secret-1234567890')
s=s.replace('VENDOO_DOMAIN=', 'VENDOO_DOMAIN=vendoo.example.invalid')
p.write_text(s)
PY
docker compose -f compose.yaml config -q
docker compose -f compose.yaml -f compose.bind-mounts.example.yaml config -q
docker compose -f compose.vps.yaml config -q
rm -f .env
- name: Docker-Image testweise bauen
run: docker build --pull --tag vendoo:ci .
+150
View File
@@ -0,0 +1,150 @@
name: Vendoo Release
on:
release:
types: [published]
permissions:
contents: read
concurrency:
group: vendoo-release-${{ github.event.release.tag_name }}
cancel-in-progress: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: masterluke77/vendoo
jobs:
release-assets:
name: Release-Paket und Prüfsummen
permissions:
contents: write
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Repository auschecken
uses: actions/checkout@v6
- name: Node.js 22 aktivieren
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: npm
- name: Abhängigkeiten installieren
run: npm ci
- name: Release-Tag gegen Paketversion prüfen
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
EXPECTED="v$(node -p "require('./package.json').version")"
test "$RELEASE_TAG" = "$EXPECTED" || { echo "Release-Tag $RELEASE_TAG passt nicht zu $EXPECTED." >&2; exit 1; }
- name: Vollständige Prüfung
run: |
npm run verify:git
npm run verify:git-regression
npm run verify:git-staging
npm run check
npm run verify:esm-exports
npm run verify:flux-loop
npm run verify:capabilities
npm run verify:architecture
npm run verify:themes
npm run verify:security
npm run verify:identity
npm run verify:catalog
npm run verify:modules
npm run verify:deployment
npm run verify:config
npm run verify:installer-shell
npm run verify:db
- name: Release-Staging erzeugen
run: node tools/build-release.mjs
- name: ZIP und SHA-256 erzeugen
id: package
shell: bash
run: |
PACKAGE_NAME="$(cat release-output/RELEASE_NAME.txt)"
cd release-output
zip -r -9 "${PACKAGE_NAME}.zip" "${PACKAGE_NAME}"
sha256sum "${PACKAGE_NAME}.zip" > "${PACKAGE_NAME}.zip.sha256.txt"
echo "package_name=${PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
- name: Assets an GitHub Release anhängen
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
PACKAGE_NAME: ${{ steps.package.outputs.package_name }}
run: |
gh release upload "$TAG" \
"release-output/${PACKAGE_NAME}.zip" \
"release-output/${PACKAGE_NAME}.zip.sha256.txt" \
--clobber
- name: Build-Artefakte sichern
uses: actions/upload-artifact@v4
with:
name: ${{ steps.package.outputs.package_name }}
path: |
release-output/${{ steps.package.outputs.package_name }}.zip
release-output/${{ steps.package.outputs.package_name }}.zip.sha256.txt
if-no-files-found: error
retention-days: 30
container:
name: GHCR-Container veröffentlichen
permissions:
contents: read
packages: write
attestations: write
id-token: write
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- name: Repository auschecken
uses: actions/checkout@v6
- name: Docker Buildx aktivieren
uses: docker/setup-buildx-action@v3
- name: Bei GHCR anmelden
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Container-Metadaten erzeugen
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ github.event.release.tag_name }}
type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }}
type=raw,value=latest,enable=${{ !github.event.release.prerelease }}
- name: Container bauen und veröffentlichen
id: push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
provenance: true
sbom: true
- name: Container-Provenienz attestieren
uses: actions/attest@v4
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
+58 -25
View File
@@ -1,4 +1,4 @@
# Environment and secrets # Secrets and local configuration
.env .env
.env.* .env.*
!.env.example !.env.example
@@ -8,51 +8,84 @@
*.p12 *.p12
*.pfx *.pfx
*.crt *.crt
*.cer
# Node.js # Dependencies
node_modules/ node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Databases and SQLite runtime files # SQLite runtime data
db/*.db db/*.db
db/*.db-shm db/*.db-shm
db/*.db-wal db/*.db-wal
db/*.sqlite db/*.sqlite
db/*.sqlite3 db/*.sqlite3
*.db-shm
*.db-wal
# Runtime data # User and runtime data
uploads/* uploads/*
!uploads/.gitkeep !uploads/.gitkeep
backups/* backups/
!backups/.gitkeep
logs/ logs/
*.log
tmp/ tmp/
temp/ temp/
sessions/ sessions/
data/ data/
docker-data/ docker-data/
*.log
# Generated files and local state # OS and editor files
coverage/
dist/
.cache/
*.pid
*.seed
# Editors and operating systems
.vscode/
.idea/
.DS_Store .DS_Store
Thumbs.db Thumbs.db
desktop.ini desktop.ini
.vscode/
.idea/
# Local Docker overrides # Local overrides
compose.override.yaml compose.override.yaml
docker-compose.override.yml docker-compose.override.yml
# Local AI runtimes and downloaded model data
local-ai/comfyui/
local-ai/downloads/
local-ai/extract-temp/
local-ai/fashn-vton/.venv/
local-ai/fashn-vton/engine/
local-ai/fashn-vton/weights/
local-ai/fashn-vton/outputs/
local-ai/fashn-vton/runtime/
local-ai/fashn-vton/hf-cache/
local-ai/fashn-vton/fashn-vton-*.zip
local-ai/fashn-vton/python311/
local-ai/fashn-vton/uv/
local-ai/fashn-vton/uv-cache/
local-ai/fashn-vton/downloads/
# Local update, rollback and slice archives
updates/
# Operations Center runtime
operations/staging/
operations/updates/
operations/rollback/
operations/apply-*/
operations/pending-operation.json
operations/last-operation.json
# Deployment assistant state
.vendoo-install-mode
runtime/
# Generated deployment and release output
release-output/
*.release.zip
*.release.sha256.txt
.vendoo-github-state.json
# First-run and local installer state
operations/first-admin-code.txt
config/local/
# Installed Vendoo module packages (runtime)
modules/
# Python cache
__pycache__/
*.pyc
+1
View File
@@ -0,0 +1 @@
Vendoo 1.20.0 image-stack cleanup completed.
+9
View File
@@ -0,0 +1,9 @@
registry=https://registry.npmjs.org/
audit=false
fund=false
strict-ssl=true
prefer-offline=true
fetch-retries=5
fetch-retry-factor=2
fetch-retry-mintimeout=10000
fetch-retry-maxtimeout=120000
@@ -0,0 +1,25 @@
# Vendoo 1.40.1 Start hier
Dieses Paket behebt den Startabbruch aus Vendoo 1.40.0:
```text
SyntaxError: The requested module './lib/ai-flux-prompt-jobs.mjs'
does not provide an export named 'stopFluxPromptJobLoop'
```
## Ursache
`server.mjs` band den FLUX-Studio-Worker mit Start- und Stop-Lifecycle ein. Das Jobmodul exportierte `startFluxPromptJobLoop`, aber die zugehörige Stop-Funktion fehlte. Der normale Syntaxcheck erkennt solche ESM-Vertragsfehler nicht, weil er Module nicht vollständig gegeneinander instanziiert.
## Behoben
- `stopFluxPromptJobLoop` wird jetzt exportiert.
- Das Polling-Intervall wird mit `clearInterval()` beendet.
- Der interne Timerzustand wird zurückgesetzt.
- Ein erneuter Start bleibt idempotent.
- Ein neues ESM-Export-Vertragsgate prüft künftig alle lokalen benannten Imports gegen die tatsächlich vorhandenen Exporte.
- GitHub CI und Release-Workflow führen das neue Gate verpflichtend aus.
## Keine Datenänderung
Version 1.40.1 enthält keine neue Datenbankmigration und löscht oder verändert keine bestehenden Artikel, Benutzer, Bilder, Uploads, Module, Secrets oder Backups.
@@ -0,0 +1,41 @@
# Neue Funktionen und Korrekturen in Vendoo 1.40.1
## FLUX-Worker-Lifecycle
Das FLUX-Studio-Modul besitzt jetzt einen vollständigen Start-/Stop-Vertrag:
- Start nur, wenn noch kein Timer läuft.
- Stop beendet den vorhandenen Timer.
- Stop kann mehrfach sicher aufgerufen werden.
- Nach einem Stop kann das Modul erneut aktiviert werden.
Dies ist besonders für den Modulmanager wichtig, weil FLUX Studio als optionales Modul kontrolliert deaktiviert und wieder aktiviert werden kann.
## ESM-Export-Vertragsprüfung
Das neue Werkzeug `tools/verify-esm-export-contracts.mjs` prüft statische lokale benannte Imports, beispielsweise:
```js
import { startWorker, stopWorker } from './worker.mjs';
```
gegen die tatsächlich exportierten Namen des Zielmoduls. Re-Exports über `export * from ...` werden ebenfalls berücksichtigt.
Dadurch blockieren CI und Release künftig unter anderem:
- fehlende Funktions-Exporte,
- umbenannte Exporte ohne angepassten Import,
- fehlende lokale Moduldateien,
- fehlerhafte Kompatibilitätsfassaden.
## Bestehender Modulmanager bleibt erhalten
Alle Funktionen aus Vendoo 1.40.0 bleiben enthalten:
- Module aktivieren und deaktivieren,
- Abhängigkeiten prüfen,
- `.vmod` installieren und exportieren,
- installierte Fremdmodule entfernen,
- ausführbare Drittmodule quarantänisieren,
- Kernmodule schützen,
- Modulzustand sichern und wiederherstellen.
@@ -0,0 +1,62 @@
# Installation und Abnahme Vendoo 1.40.1
## Update einer bestehenden Installation
1. Vendoo vollständig schließen.
2. Dieses ZIP vollständig entpacken.
3. Im entpackten Paket den Ordner `vendoo` öffnen.
4. Den gesamten Inhalt über den bestehenden Vendoo-Ordner kopieren.
5. Bei Windows **Dateien im Ziel ersetzen** bestätigen.
6. Den bestehenden Vendoo-Ordner vorher nicht löschen oder leeren.
7. `setup.bat` starten.
8. **Update** auswählen.
9. Danach Vendoo starten.
## Nicht löschen
Folgende vorhandene Daten müssen erhalten bleiben:
- `.env`
- `config/`
- `master.key`
- `secrets.enc.json`
- Datenbank
- `uploads/`
- `backups/`
- `operations/`
- `updates/`
- `modules/`
- FLUX-/ComfyUI-Modelle und Laufzeitdaten
## Erwarteter Start
Der bisherige Fehler darf nicht mehr erscheinen. Vendoo muss bis zur normalen Serverausgabe starten.
Danach prüfen:
1. `http://127.0.0.1:8124/readyz`
2. Anmeldung
3. **Administration → Module**
4. FLUX Studio deaktivieren
5. FLUX Studio wieder aktivieren
6. FLUX-Studio-Seite öffnen
7. einen Testprompt anlegen oder zumindest Warteschlange und Status laden
## Lokale technische Prüfung
Im Vendoo-Ordner können zusätzlich ausgeführt werden:
```text
npm run verify:esm-exports
npm run verify:flux-loop
npm run verify:all
```
## GitHub-Import
Nach erfolgreichem lokalen Test:
1. `GitHub-Deploy-Assistent.bat` starten.
2. Git-Status kontrollieren.
3. Erst danach exakt `PUSH` eingeben.
4. Draft Pull Request #14 prüfen.
@@ -0,0 +1,31 @@
# Ist- und Lückenanalyse Vendoo 1.40.1
## Geschlossene Lücke
Der bisherige Syntaxcheck prüfte einzelne Dateien, aber nicht, ob ein benannter ESM-Import im Zielmodul tatsächlich exportiert wird. Dadurch konnte der Quellcode syntaktisch korrekt sein und trotzdem bereits bei der Modulin­stanziierung abbrechen.
Diese Lücke ist mit dem neuen ESM-Export-Vertragsgate geschlossen.
## Weiterhin offene praktische Abnahmen
In der Erstellungsumgebung nicht real ausgeführt wurden:
- Windows-/PowerShell-End-to-End-Update auf dem Zielrechner,
- vollständiger Browser-End-to-End-Test,
- echter Docker-/NAS-/VPS-Livestart,
- echte ComfyUI-/FLUX-Generierung,
- GitHub-Actions-Lauf nach dem vollständigen Quellpush,
- native `better-sqlite3`-Kompilierung in der Sandbox.
Der konkret gemeldete Import-/Exportfehler wird jedoch durch ein eigenes Gate sowie die generische ESM-Vertragsprüfung reproduzierbar verhindert.
## Architekturstatus
Unverändert gegenüber 1.40.0:
- 16 registrierte Module,
- 14 native Module,
- 2 Legacy Bridges,
- sicherer Modulmanager,
- geschützte Kernmodule,
- quarantänisierte ausführbare Drittmodule.
@@ -0,0 +1,35 @@
# Abnahmebericht Vendoo 1.40.1
## Erfolgreich
- JavaScript-/MJS-/CJS-Syntaxprüfung
- generische ESM-Export-Vertragsprüfung
- FLUX-Loop-Hotfix-Gate
- `stopFluxPromptJobLoop` vorhanden und exportiert
- `clearInterval()` und Timerreset vorhanden
- idempotenter FLUX-Startvertrag
- Plattform-Architecture-Gate
- Theme-Manager-Gate
- Security-Foundation-Gate
- Identity-/Settings-Gate
- Catalog-/Media-Gate
- Modulmanager-Gate
- Deployment-Gate 1.40.1
- Git-Sicherheitsgate
- Git-Sicherheits-Regression
- Git-Staging-Regression
- persistenter Konfigurationsspeicher
- Docker-/NAS-/VPS-Installationssimulation
- 68 Migrationsblöcke auf frischer Datenbank
- 68 Migrationsblöcke auf bestehender Datenbank
- vorhandener Testdatensatz blieb erhalten
- PowerShell-Dateien mit UTF-8-BOM
- Paket-, Lockfile- und Update-Manifest-Version synchron auf 1.40.1
## Nicht als real ausgeführt ausgewiesen
- echter Start auf dem Windows-Zielsystem,
- Browser-E2E,
- Docker-/NAS-/VPS-Livestart,
- reale FLUX-Generierung,
- native `better-sqlite3`-Installation in der Sandbox.
@@ -0,0 +1,23 @@
# Roadmap nach Vendoo 1.40.1
## Unmittelbar
- lokalen Windows-Start testen,
- FLUX Studio deaktivieren und erneut aktivieren,
- GitHub-Quellstand auf Draft-PR #14 übertragen,
- CI vollständig ausführen.
## Nächster Architektur-Slice
**Vendoo 1.41.0 Isolated Extension Host, Signed Module Registry & Permissions UI**
Geplant:
- separater Prozess für ausführbare Erweiterungen,
- Capability-Tokens,
- signierte Publisher-Schlüssel,
- vertrauenswürdige Modulregistry,
- Berechtigungsdialog vor Aktivierung,
- Ressourcen- und Netzwerkbegrenzungen,
- Healthchecks und automatischer Crash-Neustart,
- Update- und Rollbackkanal für Erweiterungen.
@@ -0,0 +1,488 @@
9ca560562c993ceaada05921cea4065adbe5e885f57ac3482e2f7f657548d120 00_START_HIER.md
804252468d246865b79085c35b091cc98ff1acffd055da68d7cbef9f48b29d22 01_NEUE_FUNKTIONEN.md
37b03830954850f12bdc1fd3cdfc19a515f0d34142d769011db46660e73e9e90 02_INSTALLATION_UND_ABNAHME.md
380968cc9a5386e3f28062205c91a2d3fa35df63c93feec726139530b1cb2af5 03_IST_UND_LUECKENANALYSE.md
22b656fed74fa6910518332f6c67b48756b95c878c0ca3c69964ef9199ef907f 04_ABNAHMEBERICHT.md
155e458fd111e9deb71835090224598ede2d11c7fc1fb48a30795f3ed61a5240 05_ROADMAP.md
f344f75df655bc133e6c4abb2d215b2234fb22a4bb155c217317c36ee4f0f8fb vendoo/.dockerignore
e5cc1e85c80485ceda76fd6c69330e085ccc7bc1248be810fe4243712cf39118 vendoo/.env.example
58e3f4b76cc9398f32dcd5481b2080e7e5ba322aca04b8b8374446299c5d7dd6 vendoo/.github/CODEOWNERS
5bd335eb750d084ca12b6a3b3f35d0cd7bc454ba24ed280187c66acf75eaf396 vendoo/.github/dependabot.yml
f65684e98b01d0e0b6bfe1284b5de3354559e4cd51e634fe9e9e2e5473b890e5 vendoo/.github/pull_request_template.md
0127f541bd7a0a3373899750ba07588d057801dc65ff99875184e1268cfc5bcc vendoo/.github/workflows/ci.yml
21063fe4a8712751c469ad7d7e543bb03eeb771b1bd8cacabdf3f9bd45163bdb vendoo/.github/workflows/release.yml
5d19d5bdbfea6de033a8086d2689dd705a34b55ffbe5b873a097d6b322ced4fe vendoo/.gitignore
9bfa732952ad571d06527b32d96d79133fc23fa607df00de440b2802f543608c vendoo/.npmrc
1c5521e9dcae9a1914a0567b7c8a2ea8d1efd7a1c5e3e7cffa1c969036a70dd2 vendoo/CHANGELOG.md
61823fc9fdc036170cce6edeecbb612b442d1c65fc9f7a7eaba47e5016316ee5 vendoo/CLAUDE.md
2e0077cd6dd83d3a07fcef25b7e37ab5fc056dbe1ca034b33d55135234045882 vendoo/Dockerfile
367d8f879be543115a1060ece5beb1dcf2ac174c5dc4a53efdf54731e6bc4520 vendoo/FEATURES.md
3303677de24b92a7f8a8b187d39c1d765158760dc6f67a6599905e4cce25c57f vendoo/FILE_CHECKSUMS_SHA256.txt
7f78a0d512de717ba76c9a5e3e1bd2e52db9edf146e8eeb7297458fde5d92afa vendoo/GitHub-Deploy-Assistent.bat
302ab1609d08b3059ba6563b676c64f0709651f2e3c531857bfca3840c535a79 vendoo/MockupDesign/AdminDashboard.png
49f7625a1299a16576feabfd7824ec3511391bd9b7c53a1fba9232da7e8bd6c6 vendoo/MockupDesign/ChatGPT Image 7. Juli 2026, 10_05_19 (1).png
7b8cc9c5db8718b0b653ec6aa9d2a8bfa1bba03810248c3ba17745b6f15cc412 vendoo/MockupDesign/Dashboard.png
4e3e797ed5d3ed0b60d00d8e567fbe51543c08578b858ef71e77b274ae449fd0 vendoo/MockupDesign/Einstellungen.png
c78fd6f673c0e59789ea313396b12c2f21f75a2ee6c7ad2de81a6b89f6d90588 vendoo/MockupDesign/ExtensionDesignMockup.png
ed20bc04cab8e85245a855810a61b736a682f972eb85e23340edc9b558851a93 vendoo/MockupDesign/Heute StudioFlow.png
1ad88f45f377ab9b3f35f96a0ceaaa7f75cb0a996e83370d76c54f527392a08d vendoo/MockupDesign/IconLogoMockup.png
0e8b4a31d075f1f83ea62b5eeeb53e89859e395a696deb43155932a23e7cef86 vendoo/MockupDesign/Lager.png
b1c62e118d9be316274e966c558cdcccdd41afb3a9f05a60ec1e4a3433d2ca0c vendoo/MockupDesign/Listings.png
a52983b9ea2bf920d115485d10bc30226da88bc5cba8b00bebf801b21c096346 vendoo/MockupDesign/Publish.png
8c8bf278d0c6725e1dbb97b3c3d0c36a9bfc0753c3c86433fdc294bec70dbc0e vendoo/MockupDesign/Startseite.png
62f14221b1d71c9e631efdadd221397ff657adae4b737df52c8bff1610b90999 vendoo/MockupDesign/Vorlagen.png
f0214bf65967029afe7b44b1ac9855d409f22ccecd302cd6aca454044bfdecb0 vendoo/README.md
161b8976908f04890ae019e321ccb52f22a0f1c1d57e03f7e79785299d2ffa1f vendoo/SECURITY.md
2851c914a1b50a036cb265ddd32e5545cc7e8e34ba9d682445926acc23eb8f28 vendoo/THIRD_PARTY_NOTICES.md
9d7c2a587c12f2b12ba2923e367ade8cdd4601dcac800ca2ac34afb302e9a6e1 vendoo/app/architecture-boundaries.json
a6bdb9b6fdc97a0b2bbc052bd242a9885a75bcc46ee4f0414d8b7e215b6940de vendoo/app/contracts/module.schema.json
67fcafb51d5d17a83a04e55ecf877c8d9ac928d11a1951d0395f137ca6913401 vendoo/app/core/identity/identity-store.mjs
7cf2224714a10e337b4e8e6514de56d61200d27632440ce85c2ba20ccd7e9d7f vendoo/app/core/modules/module-package-contract.mjs
1ac6208b0cc85a3b5e2f86d61bb59a7a39fd46f51b4d8278c2abe236b53fdab5 vendoo/app/core/modules/module-package-store.mjs
8ccc5ab62329fcadc8bf42d0e9dc2bca967602295c677e027dd2d363d09f94f6 vendoo/app/core/modules/module-state-store.mjs
918cddaee5056cadddcff39d86744cf68ab409fbff46aa54b6b465b72b199c01 vendoo/app/core/security/secret-contract.mjs
7f38b3ac792e61e030c9f69355e2378f8f61e8e61c7b29c82cd0fa7ec930cfec vendoo/app/core/themes/theme-contract.mjs
d84a573699e413e0a0803459e0d05c5c4e6e35d3499eb634f95302d151e75c4b vendoo/app/kernel/errors.mjs
a34333cbc784d39b39a8071a437972c6175c551104dc2d82fc4c0e0506b18259 vendoo/app/kernel/event-bus.mjs
0e8f691f96e1ef0a7a86d32cae7b7e1db04325fe94a32b8c1f484a5b6950f3b4 vendoo/app/kernel/feature-flags.mjs
a4877c90f2c9040cb101b7fbb80385d4b1ea0814118a104873b891a580e88204 vendoo/app/kernel/input-schema.mjs
a0223a00691908862aaf1fd9383b6d86d67f26325c509280b8c2daa5cfcee28e vendoo/app/kernel/lifecycle.mjs
ba1f4f799a508ff113738cce7ac9f5af27739cb60d7f04d7a6c5878de3c5b7f4 vendoo/app/kernel/module-contract.mjs
d6efcd98ad26c1a822850de4b717539e5e5472b5ba379df7320f0e1ab6900163 vendoo/app/kernel/module-registry.mjs
3955b63ce7a17432bb70e7c6afb490f99639f70ded0c059875b87adfe1ab5e40 vendoo/app/kernel/platform-kernel.mjs
7944f68d995a5d70273f8a985973f668fc62a414d85636d92f3774e34d39a37f vendoo/app/kernel/policy-engine.mjs
f98e4cd58b051efdf311dafa73569b1ecebe2a29431cd763380c9663035c1c2b vendoo/app/kernel/route-registry.mjs
0ff879fb8cf392a3786c39f2541637b2d9f018fb03941066ed540a2880134f89 vendoo/app/modules/ai/index.mjs
98e93589109cb34c7af71215a581fe40e80691884459c2d42260f6b001065e6e vendoo/app/modules/ai/module.json
3ae563b7e6232ed89f5bc5dc49fe359ecfd696123aee2cb780032040c53f149e vendoo/app/modules/auth/index.mjs
cae01362c58adac32badb0b102ce76a748c7301aafa64818a49456665b4de29d vendoo/app/modules/auth/module.json
04a72689ecea04caf79eec9207116d1da374600150fe1966032fe972736f246f vendoo/app/modules/auth/routes.mjs
53917fe8aa4832cc62f35d4746af9bfdfd1132448de0ca750f073a0a27cdbebb vendoo/app/modules/auth/service.mjs
2b3e4d7d5acdbbe5c92e2dc4f94d5a783b97111852ac705b494d744d878ba318 vendoo/app/modules/catalog.mjs
99bde2c2871c48ff9e1d2895157197d9f1d5e194072a481abaa3495daaa683e0 vendoo/app/modules/flux-studio/index.mjs
5f28a104ef923c0f01cf71d765cb603e3c9bf7a30d087321f58161d701896024 vendoo/app/modules/flux-studio/module.json
fd798d294308dcb50d5ce90d3cfb969800cd1dfecf4805e69ec41f974e268829 vendoo/app/modules/inventory/index.mjs
febca770c3ee71c398bec9e6afc3aaaa8850ce8c9a2840c190d93b2e8d25f790 vendoo/app/modules/inventory/module.json
6925da30bd453695b82c8fcbc82c585b01cda71c410f59d62697a31c364954ae vendoo/app/modules/inventory/repository.mjs
b3d0c8a4643ff09091d48c4e1dfcd90ed0884fe9713a7bb44160c34761b59590 vendoo/app/modules/inventory/routes.mjs
94f3e5a3e6f3ed1120dad7c869b47978582717e231b57ae4c98e668d903f09bc vendoo/app/modules/inventory/service.mjs
fbf8db46e0ae7b483f898588c39a4f74d72717588d93d2058ab9250f9ada0c88 vendoo/app/modules/listings/index.mjs
79b21e2387b59eec5a23b3d547d954ddc1edf99e9ab691f6e410894811f1978c vendoo/app/modules/listings/module.json
a76054a2eca06d8412c211fc8b75f7fbd9cb1ed256f38360a7031b1f8ed7d73c vendoo/app/modules/listings/repository.mjs
d1e817f0c4251994bad0a7084e2e7dcd2873a0a099cb00a312f55aa2163c183d vendoo/app/modules/listings/routes.mjs
e7c722e449284d8ec9ade461e2b8fc94723e35ebec25c51113b40643d12f28ef vendoo/app/modules/listings/service.mjs
e12663a5b189660e34d72e034fa4b23b5bffdb0c8d5516b547020da11e70aefa vendoo/app/modules/media/index.mjs
4efc183346859a6786250d40a9762f7457e00f659a7b2408209d85f3ef75d1c2 vendoo/app/modules/media/module.json
67262d67fa85e5f2e09a51645432a2c7548a6dccdb0afbaaf63850e2fab67197 vendoo/app/modules/media/repository.mjs
9f8e54cabbb7271bac7253a26b6ffbf553f834147500141c9e7427a26c9dde81 vendoo/app/modules/media/routes.mjs
29a4e515e6ccc692b9cac78012e9571c4d6225f7e89bee2d4fefaf63f4d0fc3a vendoo/app/modules/media/service.mjs
9d2afb4ba28a144b7f75c6c409f43d2f7a34f2674c8a1f717c2ab631516b0cca vendoo/app/modules/module-manager/index.mjs
c4ab8673081ba03068cc5c76c1a0ea35c61771ad69de97cd1510dfc35f9bd93a vendoo/app/modules/module-manager/module.json
b4250e7028bc1ff041166f4099a05e71fd4e0f71abaeee09ffdd3678ce9c52c7 vendoo/app/modules/module-manager/routes.mjs
0ffb748b960653501c1bafcc660d7d604e9c5f7a323400d8bb024db5ea712356 vendoo/app/modules/module-manager/service.mjs
9723a9b12a9b472b2ed8c4635cdce663b2f0f65643d8ae0b6219715d853f740d vendoo/app/modules/operations/module.json
8a2805286def5d0521765319eddcd44e680e32bd7065d45749edd31406228463 vendoo/app/modules/publishing/index.mjs
53e1dcab6bb9c5046eba6daa17c0f1ffb193bed38ae248dd1702fee91bdd23bd vendoo/app/modules/publishing/module.json
306a2c3c119b82f6f972fa503099705bd3ede6c2061f532a00dc208f0584445c vendoo/app/modules/quality/index.mjs
61381a51b86b64d59dde8c1a749ae46b7990ec323adc71c7eb62f741eeb6f807 vendoo/app/modules/quality/module.json
747febc12aec7d81ccfdf6e9ea7158655ef5fdc536c519ce447de329314612a8 vendoo/app/modules/security/index.mjs
700be862cd70be6947919c1e1f0e25e7e88c313b1fcdddc104d54d88a74edbb2 vendoo/app/modules/security/module.json
08a6015cd3588f08070d341ad8cc5c9be8e34d217cf8770e154d4571225b3e2e vendoo/app/modules/sessions/index.mjs
da856dca2a4e2533a8a224806ccf10f792ed46e8266505a27339cf27e8a1edda vendoo/app/modules/sessions/module.json
c2ed5ccf36a0c5398f3113cd79172bed917dfb6c9668f025e806e38d74f8c83b vendoo/app/modules/sessions/routes.mjs
a33995a82e02beaaa820bebc2875d14d684b1d4baeeb79d27dc7237c899f3249 vendoo/app/modules/sessions/service.mjs
edc35b82678ef00e24fc6cb6a6d135bbca9acc980a17e59b15ba90b0a79490de vendoo/app/modules/settings/index.mjs
c1bdee45bd8ec80715e74d3e92ea238cd3e47a6e54fda4c5959a6de51d9d5163 vendoo/app/modules/settings/module.json
7b7ed59760da0338037b2d5038a9b422a62b4a818c62a74216d2fce215ac6490 vendoo/app/modules/settings/repository.mjs
3717914c11da56a54dd0a22d139830a064f4c842c0f718517570470ecb9ed551 vendoo/app/modules/settings/routes.mjs
07dcb652661f9c879877a5d0033f4388584b2c3a2eef58488c88cd7c5cadd78e vendoo/app/modules/settings/service.mjs
452a5262c418b393bdd8754fe90f9ea14edf61338f8dcfd6438f0852920f608c vendoo/app/modules/system/module.json
92d968c993ee5a2afc14df557b7cba552cae9a41722989007eb0b784514333ff vendoo/app/modules/themes/index.mjs
1e062db871f9bf13b487c972f6cd4dd9cfe1b3046cd9b53ed43e0a0babc9d285 vendoo/app/modules/themes/migrations/001_theme_profiles.sql
2af572390890e4d793aea9c1356c835917655c225a7848325d5a7c5ae3c08a09 vendoo/app/modules/themes/module.json
3c3dc5974976672cd0e9141867a8a1d78a0dfaa54582bafb8f360bea571bf11a vendoo/app/modules/themes/repository.mjs
4e2c348a184384739408894f26b02c56c6bfd4dd531eebb9c67d2fb7fbad3009 vendoo/app/modules/themes/service.mjs
68cf3325307263022cd5704fd77664f7269896b8aa0570033c84b7abfba993ed vendoo/app/modules/users/index.mjs
c6558b8a0cd9d7ef30d0e259747805e3d91a5359c2dbfbd79e6794bb403a9926 vendoo/app/modules/users/module.json
8640accd1550932459ecd14738139284cbcdd93f31a61ab6e7748791fc82933f vendoo/app/modules/users/routes.mjs
fc4af51a35fd08289ec4380a78c06b3236a2469041ecfc911b9e0d7d269afa19 vendoo/app/modules/users/service.mjs
c197ce417fbce6dab1d8ee157b0a105a099dd2021ece4dac3891d0b2022a0d58 vendoo/bootstrap.mjs
61199cecda2c84954de2b60c07eb9f3a2117fbaaa4c430319c461b2e76a10254 vendoo/compose.bind-mounts.example.yaml
21fa9a7c0d609928db4b3d1aa697a559b0245011ff63ea3a241b17b2182f2155 vendoo/compose.vps.yaml
3fb770edbc429c3e01a3a73d861033b2c425bdc9a0a1b27e969a8d0fc0cb14c8 vendoo/compose.yaml
6323f984f1e04ab135356a14ec151941638041f6b305ed68772d5e1812972075 vendoo/db/schema.sql
49690c4e4c8e84de8eb40ffe79823493b7be20fe46fa2ad9e6544f7f0afbfd2c vendoo/deploy/Caddyfile
cc794bca282d79a27d860d0bfef4641769f4e9f31172778a1d9d8205558d948e vendoo/docs/ABNAHMEBERICHT_1_32_0.md
de0d86f806a70195050613f5b56f6c4da1ee2eff02a9a991b6aacee229c46ca5 vendoo/docs/ABNAHMEBERICHT_1_33_0.md
947745174897470de0bebf4f7c2b29a0c0ef3f1a762f277374c2614d9e3dec4f vendoo/docs/ABNAHMEBERICHT_1_34_0.md
26c87fa38f804749a9363812127dc33ef69e201e4ef9b59206f6fe6e15c845b0 vendoo/docs/ABNAHMEBERICHT_1_34_1.md
f792d366c13c5a4a9b4e8d4054e26190d9c327a7a770005d74bbe2b31bb84ab3 vendoo/docs/ABNAHMEBERICHT_1_34_2.md
bc638fd21222ada7b15e40adff80a318aebec58139978109cbfd30040815a8d4 vendoo/docs/ABNAHMEBERICHT_1_34_3.md
c0ae5c4176ba6f7510be047d4feaf383cd646152131003ebccc6bfbf8c8056f5 vendoo/docs/ABNAHMEBERICHT_1_35_0.md
c050c8e11f2bdb0a742851423dcff864bafba9cc839c52b2f8d48b75f7b18633 vendoo/docs/ABNAHMEBERICHT_1_36_0.md
1f3e96ba13844a3f1cefecca99b3d6313aebf86faae914897db0404ea031c491 vendoo/docs/ABNAHMEBERICHT_1_37_0.md
361d19e6b7aeab3f22b337210f3a56221f2e42798c0fea75be978ebb7d72487f vendoo/docs/ABNAHMEBERICHT_1_38_0.md
2f6518fd50d9088f5580cfcc03e92543321ac7feb97dcdd570c23c51fd8c5391 vendoo/docs/ABNAHMEBERICHT_1_39_0.md
67a1be91b0c2d2797716f785f2f770c881cf88d7fd617722468df8d949d0638a vendoo/docs/AUDIT_1_31_0_IST_UND_LUECKENANALYSE.md
2acba8fcc5da42e5a808925a86628bc0c6fc817ddb082b0ead3857c6a43460f1 vendoo/docs/BRANDING.md
f23c643236c84b0e3715620598f358065748b6d090229003e23df8ad9320b54e vendoo/docs/FULL_LISTING_EDITOR_2026.md
ba9a9b93622fadc399cd9067d80b4ea339193eb19825106264a3b86b7128d107 vendoo/docs/GENERATOR_STUDIO_2026.md
54f45ae5c2f12b6314b3f1bc3e59e753c64ca7cfe39644725d765e9f02f637ef vendoo/docs/GITHUB_DEPLOYMENT_1_34_0.md
5a25e952d7d79b562bc19c990451830ea2ac3e730c9af399425ea18ffb8fd61d vendoo/docs/GITHUB_IMPORT_STATUS.md
e5c6ac33f5c0dc93099148d95af123a9aeb72298d885cabf0b1dc96a9cad31d7 vendoo/docs/GITHUB_IMPORT_STATUS_1_39_0.md
65d19c1576f4a6011008a7e447a3530222517752fb59ebc5bbb506b791e32605 vendoo/docs/HOTFIX_1_23_1_EDITOR_CACHE_VINTED_FIELDS.md
c9c8f934a0c4192dae29df913588188aab1321364d1c46b9c66da5c754e9df41 vendoo/docs/HOTFIX_1_23_2_FLUX_EDITOR_JOB_COLLAPSE.md
2306ff399000c07a9d7e260a58d92c748fa3219922a4dda25f6b2121a1ad2dbc vendoo/docs/HOTFIX_STUDIO_FLOW_DETAIL.md
0584257245a29de62a6374eb8b114bd19fc6a36306ed990d820ed2062514d6a6 vendoo/docs/INSTALLATION_1_32_0_WINDOWS_DOCKER_NAS.md
7c1afdefd1e3a75a5d6b49aedae80e266bab4e91cbfc657fb862ddfd737dc792 vendoo/docs/INSTALLATION_1_33_0_MULTIPLATFORM.md
1475e484cccb0db67e02abbb05f8b8e676c85536ec4f5bda7dd99d4563fbc049 vendoo/docs/INSTALLATION_1_34_0_ZERO_EDIT.md
1df2aed413865c03e541e66249c1df3eed6d3c3aea9f0ffdeaee40453665df14 vendoo/docs/LISTINGS_UI_2026.md
4f74fef6877126d2579356b9731955e29f05ea8b55b59abb91569e47730a1c3f vendoo/docs/PUBLISH_CENTER_2026.md
bae236366d6d2cb0139e4dbf8baf099599bbff27aacc9eeeba20fdff644f5fb0 vendoo/docs/RELEASE_1_24_0_RESPONSIVE_MEDIA_FLUX_ARCHIVE.md
5223408e51f35ba5f6ce86155544311dd13f60522a6d482f372d64788ab466ac vendoo/docs/RELEASE_1_24_0_VERIFICATION.json
b66524ffd19976f650c6b26b299898b182355950f545c131de16c89fcffe0ebe vendoo/docs/RELEASE_1_25_0_RESPONSIVE_GALLERY_SMARTCOPY_PROMPTLAB.md
1c5ebf1a496c9571fe9d941793371f9f0be89d85a587c8fa9532f9b25bba92bc vendoo/docs/RELEASE_1_25_0_VERIFICATION.json
1eef86e13d9429701e9d60894f36fe0eba82c974565b1a6687ed157ca6da680e vendoo/docs/RELEASE_1_25_1_ADAPTIVE_GALLERY.md
14475ae4169f4bde4a5b7ae5512867f972ede69dcb621d7cc6a208d4fdc6a331 vendoo/docs/RELEASE_1_25_1_VERIFICATION.json
f02b80194f434dd3d82b5c4c111e8cae65f1f053a267cec2793a1ff551daff9a vendoo/docs/RELEASE_1_26_0_ARTIKEL_EXTENSIONS_PUBLISH_GALLERY.md
570522a6513134227122da1b5f2f56a421c62d3b0b5adba703872e9026fa2b58 vendoo/docs/RELEASE_1_26_0_VERIFICATION.json
4cfc47f35765259cbd6a841f51a85fa86600991d1ca545b10756f15b6d332f7f vendoo/docs/RELEASE_1_26_1_STABILITY_GATE.md
9646b913994b1bf8ce03eab57e7a6a87061540e44fdde63ad5b7eee93ca9f475 vendoo/docs/RELEASE_1_26_1_VERIFICATION.json
7c6c3a2e4ce478f47e540a34a3505dbbe11b8f2175d0b274bec7643457997140 vendoo/docs/RELEASE_1_30_0_OPERATIONS_CENTER.md
6f9c206869ba94c461b1d9f8e40847792b8891bb27809a0c6fa3d1d68a4e8598 vendoo/docs/RELEASE_1_30_0_VERIFICATION.json
5da62e06d768ce832d18fb3ecb3ccca2f051a6218d2d3cb492d1e5aebbcccb52 vendoo/docs/RELEASE_1_31_0_MULTIUSER_SECURITY.md
6288a31dfa61f71d13f79d40ab64bb7ca475de07ada154c002cd4b0d44a284dc vendoo/docs/RELEASE_1_31_0_VERIFICATION.json
4ee88ff8c3c655cb31bc18192a37ffdd0eedf8e26039b252094d5ce169c1883c vendoo/docs/RELEASE_1_32_0_DOCKER_NAS_PRODUCTION.md
628d4d1a6c7d837a0c8c22958253193642ddfeaab5f425f418f9f32b46e84340 vendoo/docs/RELEASE_1_32_0_VERIFICATION.json
624919ea60969079f767068771800dbc04ea7a87eb1a53d7f0497447492c25cb vendoo/docs/RELEASE_1_33_0_MULTIPLATFORM_DEPLOYMENT_FLUX_ADMIN.md
3f9ae39792bec600ddd534284ae62cb2b4f9db01fb54c09cee8ae161551caa2a vendoo/docs/RELEASE_1_34_0_GITHUB_ZERO_EDIT.md
c724b699894d5ec3c050af0253c6de0c645a789219a344ad7ffe31e330d9921b vendoo/docs/RELEASE_1_34_0_VERIFICATION.json
7caa9e7b1e51af362332e9c50165b60c54c9219c7384c8313d3735c387df1c01 vendoo/docs/RELEASE_1_34_1_GIT_SAFETY_WINDOWS_HOTFIX.md
ac834ee57ab6bd8fe3dd0238837193e66e01d7e78590a289347b002591da3fb4 vendoo/docs/RELEASE_1_34_1_VERIFICATION.json
51057d17e2636ef1bdfc6751dfad29ebd34fbe7f41b870f8f2f756a5c97d1c4a vendoo/docs/RELEASE_1_34_2_GIT_SAFETY_DIAGNOSTICS_STAGING_FILTER.md
4c2c141ffc85b1d7517672abf2b28bb19fe4769505c0eb4d37e22bae06826cb3 vendoo/docs/RELEASE_1_34_2_VERIFICATION.json
d55eaec79e10800a930fa030367ffa34037755e5757bc532e72d25711c5ca09a vendoo/docs/RELEASE_1_34_3_UPDATE_ARCHIVE_EXCLUSION.md
4bb731af51e786a4827ec48bc7c4d4843c287456aedc09d8b74aa0eed3c0ec16 vendoo/docs/RELEASE_1_34_3_VERIFICATION.json
e7bb3bb950e3c5303746f43139ca8f7c985d2d73896b44f5b707dd46a9152529 vendoo/docs/RELEASE_1_35_0_PLATFORM_KERNEL.md
33eb9f0059a2ddc4b4debe5bf733720f2a5bb22f2710bab0a0cc9ac1b898ff11 vendoo/docs/RELEASE_1_35_0_VERIFICATION.json
5a9fcfa0ea6e9c5c13f6d943e1de4d31c21e21fcff9186e8a714d7a16ed1c18f vendoo/docs/RELEASE_1_36_0_SECURE_THEME_MANAGER.md
2dfe705857424865f101e861f4e633c8a7fb3c0e8dab874cb6620fd09b1ca902 vendoo/docs/RELEASE_1_36_0_VERIFICATION.json
527806c00fb51334457726a9a7e9f6fc13f4dacd985fa2d2b97d5eb21c543853 vendoo/docs/RELEASE_1_37_0_SECURITY_SECRETS_OBSERVABILITY.md
c3a8a21f5a3c3edb05ab1762a06d05b7f6eced3be84cb4f6f5e7f31bc627f06b vendoo/docs/RELEASE_1_38_0_AUTH_USERS_SESSIONS_SETTINGS.md
c17771f19c2dfd6629fb91b66dfd661eed3459f820b71a427f0f98b07b45c56d vendoo/docs/RELEASE_1_38_0_VERIFICATION.json
26355d15c188b1ce3bd03a539e1b27ee884352db48e5db423f60cdcd4d9d49f3 vendoo/docs/RELEASE_1_39_0_LISTINGS_INVENTORY_MEDIA.md
c016becfaa0c1ae5bcee255476dd2a09fd465308f5ec2fba6d3c6809b009538b vendoo/docs/RELEASE_1_39_0_VERIFICATION.json
837ac91a926330b800a027a61d4a2aa0386cfd61f9b7949231bbb09e1ca0e6c3 vendoo/docs/RELEASE_1_40_0_MODULE_MANAGER.md
e52467c05ad08a262ff812989f2be19bfad3038f35f61e9deabcbf61b81fa5df vendoo/docs/RELEASE_1_40_0_VERIFICATION.json
1908713d7458ecacc833faced77984ef5c0155cd61b0eac13a4f874e3f3a5676 vendoo/docs/ROADMAP_1_38_0.md
185b1007c90273126ebe92bffe69f88ae4ec4a3f04451cb9d5d4b772a0482391 vendoo/docs/ROADMAP_1_39_0.md
b581d7d949139f37798dded557235a679621172f444a6271e7fc7ade3020299a vendoo/docs/ROADMAP_1_40_0.md
fe5756f788b2ab131f0832504d90d46d1ed744bfe470fd040803985234afa3cf vendoo/docs/SLICE_02_ACCEPTANCE.md
05614ecf41becc399acfa6a3b2f681f37a8c80f5ce0130b98c578b2c8c60713c vendoo/docs/SLICE_05_ACCEPTANCE.md
0838bcc6464a6beff39f0b4b056e513c1a390193521d9a8fc5d440d38034e9d0 vendoo/docs/SLICE_06_ACCEPTANCE.md
ae0f7c6f6e614ec77e362db1076288596ec48d11b78f33f26908fbc40ae5dd18 vendoo/docs/SLICE_07_EXTENSIONS_RESPONSIVE_MOBILE.md
b561983736639a08146d3642b718651907853d589ee32e5f421fc090f2c75a20 vendoo/docs/SLICE_08_EXTENSION_AUTOFILL_UX.md
c5bf7a0c9f787f100e422d0deb27bffc2c8c86b0e7c1ce1f35d2de8d7d8ea774 vendoo/docs/SLICE_11_DASHBOARD_RESPONSIVE_HOTFIX.md
876675bc3015838f568a6970ef6c01c9fcafe1d8d138c4379bc0f2ee1fd7445b vendoo/docs/SLICE_22_1_SETUP_AUTO_RECOVERY.md
223f50d05096b3bfa3ac3a9f0880a2055fc2029b7d70fabd086612c3348cb34a vendoo/docs/SLICE_22_2_DOWNLOAD_RECOVERY.md
95e1d560378120d7ccb0f363720ba832505631aa65616abd4df01baba5ecc269 vendoo/docs/SLICE_22_3_POWERSHELL_51_PARSER_FIX.md
88f5a2d021874764b6a7f56c690a1e2112155b83cdf0d4d964b2c6e00ca756de vendoo/docs/SLICE_22_3_SHA256.json
791a5d30f0d6ff9664722a2d00dff0db0bbdf2207e83ab391a40d6c4ab913bba vendoo/docs/SLICE_22_4_SHA256.json
d14c938c6c9397290f654406d4b995b63db0f22586e78fc97fb5fef575748807 vendoo/docs/SLICE_22_4_UTF8_BOM_FIX.md
f00c325ec3c879b47908dd5410cc943febb923200e9b9bd7d18197b1570a26fe vendoo/docs/SLICE_22_4_VERIFICATION.json
e140f3ee3298b3894126e37900b04ff1073ed400e6414e35897815b3f674d93e vendoo/docs/SLICE_23_FLUX_REFERENCE_PROGRESS_SETTINGS.md
b4b01b9f3751940d184d6fff269108798c7ec62ca7796b923cf82abbc142ff3b vendoo/docs/SLICE_23_VERIFICATION.json
05e3fcf5aa9a0d8d53175a3d24c5feb36e55f73edfeadf05384e87a5de73353a vendoo/docs/SLICE_28_1_FLUX_RUNTIME_HEALTHCHECK.md
43d867bb8b455f7450e5146648b28c759e50ebab45855d75a36dbc9f91d3f654 vendoo/docs/SLICE_28_FLUX_STUDIO_VTO_CLEANUP.md
0bdbeed4b57767427afbebeddc30ea58a211f851663939d6301af38820cf098f vendoo/docs/SLICE_28_VERIFICATION.json
1e20fd1abea3ce61f7f9cc88c6e8e4ddb0fe3513c5600e41b8f7c3f8d38e3ae9 vendoo/docs/SLICE_29_FLUX_QUALITY_SETTINGS_TABS.md
1df7305e6a43212a582d5f83630e0ba04fbdd3da0d673d9dcb8f1c5f7ca37731 vendoo/docs/SLICE_29_VERIFICATION.json
07d1ad0c19567cbdb05623567816f1506197a31e86fbcd1742f4ffa300335ae4 vendoo/docs/SLICE_30_FLUX_STUDIO_PRO.md
008237388c4816d3cd67f3f0abfd0512f4ebf2dce75ab6790de41b0481ae1d97 vendoo/docs/SLICE_30_VERIFICATION.json
db1674505e2ca7eb36c8752ea9b2d6fe2f2c12a5e6a1584e2722e20445b05e34 vendoo/docs/SLICE_31_ADVANCED_IMAGE_EDITOR.md
3133a06e68cd98e615797665956f1bc401c0427045298b46c48ca590be3ef9da vendoo/docs/SLICE_31_VERIFICATION.json
d425fc1724ac55853bf3433348486de8f8aab111f53fefee3c532beb1deb82af vendoo/docs/SLICE_32_BATCH_IMAGE_FACTORY.md
0a8917412d000168956f7ac55e60ab79b54a8834deef0386a681bb8f920514cd vendoo/docs/SLICE_32_VERIFICATION.json
25ff8492360d473e99c75c308be5f75cf84e0c11574d42aa6553d44f8bb35582 vendoo/docs/SLICE_33_ARTICLE_QUALITY_CENTER.md
1d5411f69c62222d3155f0e89f2b4b5a3effe317ea1e59347efa7730a8e1b0e9 vendoo/docs/SLICE_33_VERIFICATION.json
1161decfabd73c40ff1d2ffbc7d1b9b5168a8fb5fa392187c1b431e9a7f3a78f vendoo/docs/SLICE_34_PUBLISHING_HARDENING.md
aa7ebc90470071566749c61b0dece4169f87666dcca4b88922f7fbafcfdd5a84 vendoo/docs/SLICE_34_VERIFICATION.json
4b66a14b4515e38477f10325ab9d03d9782ad0d426845aefe2d508986ed2cd81 vendoo/docs/UI_FOUNDATION_2026.md
5e655fcf3bb1182f8850b4104b56697ea952b01d2698af6d3d40b05e338b3506 vendoo/docs/UI_UX_FIXES_SLICE_03.md
b39d2d892068e1313fc00c9345d54240b6d50caf8a940261a088e67d8778ac63 vendoo/docs/architecture/CATALOG_MEDIA_MODULES_1_39_0.md
e5f065ba8d516a5ebd47e7e6859d0aab40ef69797413e358d969ef27c454fcdd vendoo/docs/architecture/DESIGN_SYSTEM_1_35_0.md
732ef23db1ef50862a423841f58e4628ad3b2a2ef2744ed7c5ef1fe01e3e38d1 vendoo/docs/architecture/IDENTITY_SETTINGS_MODULES_1_38_0.md
cc0edf92756a51414563b4407dedb21d1e3b36682f4bfbbc334aeb33a22ae1b4 vendoo/docs/architecture/MIGRATION_ROADMAP_1_35_0.md
db659979dfd6e08f36a7aa9b4de42750ac39c536b11fad694a1846c902ea65bf vendoo/docs/architecture/MODULE_MANAGER_1_40_0.md
eb47b055dd336e8360ec7c4712dee4ae37f109f3820e3f185969e2327d790cf8 vendoo/docs/architecture/MODULE_SYSTEM_1_35_0.md
d7773faac0e93510a5a51c91de997df03547b51f3124267dcf137d4e99299562 vendoo/docs/architecture/SECURITY_ARCHITECTURE_1_35_0.md
58cd43938b06e29520b92516a1e816d17d2c08d4847b99c1ee700b2185f46f20 vendoo/docs/architecture/SECURITY_FOUNDATION_1_37_0.md
771c4771c4d7335750c5a2d976c765b4ed66ed936d8550d7af69de14a16705bb vendoo/docs/architecture/THEME_MANAGER_1_36_0.md
cc77a92ca268d3c444c6113a9cfaa38d3c805a579f6b1b21b7dd43a6ada58551 vendoo/docs/superpowers/specs/2026-07-06-autolister-features-design.md
c7db96df5fed3c8336062204322d62b4870f5c8ab1d30ea48cc6e7e38ed3513b vendoo/extension/README.txt
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extension/background.js
b86f00c7afa1dc921dd66f5cfea8c817eebc8876b9daca6a55dfd03680156c79 vendoo/extension/content.css
8ee8d1a94bbf83e5d09aee3c7d8c4ea5f216b2a51e73b6dbc74f7e6b99017a1c vendoo/extension/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extension/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extension/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extension/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extension/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extension/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b vendoo/extension/manifest.json
e61fd8e1264995fd633bd76e71329813dd02f361286329832a18dfd5a8bdd372 vendoo/extension/popup.css
bdf5b794473cae818789cf95a28a9c9a9d50f81529d72fdf45a536247a783922 vendoo/extension/popup.html
d7893cfdd686d4a6a1bea333468d4ba72cfff0e7166687181a2d37ba1faf3332 vendoo/extension/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extension/vinted-categories.js
48b5f9f4ecc1c1c42f37321e9bb2fc857c646b9c16c34520fc7d4ca59a1036ac vendoo/extensions/README.md
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extensions/background.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extensions/chrome/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e vendoo/extensions/chrome/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 vendoo/extensions/chrome/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extensions/chrome/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extensions/chrome/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extensions/chrome/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extensions/chrome/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extensions/chrome/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b vendoo/extensions/chrome/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 vendoo/extensions/chrome/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a vendoo/extensions/chrome/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 vendoo/extensions/chrome/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extensions/chrome/vinted-categories.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e vendoo/extensions/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 vendoo/extensions/content.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extensions/edge/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e vendoo/extensions/edge/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 vendoo/extensions/edge/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extensions/edge/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extensions/edge/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extensions/edge/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extensions/edge/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extensions/edge/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b vendoo/extensions/edge/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 vendoo/extensions/edge/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a vendoo/extensions/edge/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 vendoo/extensions/edge/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extensions/edge/vinted-categories.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extensions/firefox/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e vendoo/extensions/firefox/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 vendoo/extensions/firefox/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extensions/firefox/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extensions/firefox/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extensions/firefox/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extensions/firefox/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extensions/firefox/icon.svg
1954ca9f34b3afe109935173f685482f06bb685a9b8f0d4c344f0c6133ccfaaf vendoo/extensions/firefox/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 vendoo/extensions/firefox/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a vendoo/extensions/firefox/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 vendoo/extensions/firefox/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extensions/firefox/vinted-categories.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extensions/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extensions/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extensions/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extensions/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extensions/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b vendoo/extensions/manifest.chromium.json
1954ca9f34b3afe109935173f685482f06bb685a9b8f0d4c344f0c6133ccfaaf vendoo/extensions/manifest.firefox.json
e4ea31f91a4c8df18901bfc77fc351a8808d19d690243b80bc4faa140e18f851 vendoo/extensions/packages/vendoo-link-chrome-1.9.0.zip
e4ea31f91a4c8df18901bfc77fc351a8808d19d690243b80bc4faa140e18f851 vendoo/extensions/packages/vendoo-link-edge-1.9.0.zip
74c219587cf0f827a1a1e2b8adacac55477be717fd4ae80e2ae027a9ffb0744d vendoo/extensions/packages/vendoo-link-firefox-1.9.0.zip
9e828844f41154c87ccfc5d8f3a19476396e2782fbd0f956465b42fb508cb098 vendoo/extensions/packages/vendoo-link-safari-1.9.0.zip
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 vendoo/extensions/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a vendoo/extensions/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 vendoo/extensions/popup.js
afd76deccd8bcf26d39f8c86deb1de578873ddd8b09ac18eebacae33169bb420 vendoo/extensions/safari/README_SAFARI.md
0b2a03d06faae7aaebeee8ec9fe1864422c8651f17ae90b185fd31474ac5eeb0 vendoo/extensions/safari/build-safari-extension.command
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e vendoo/extensions/safari/web-extension/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e vendoo/extensions/safari/web-extension/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 vendoo/extensions/safari/web-extension/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/extensions/safari/web-extension/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/extensions/safari/web-extension/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/extensions/safari/web-extension/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/extensions/safari/web-extension/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 vendoo/extensions/safari/web-extension/icon.svg
772f1e2e33f4d6d882fa0af663e315fd3b8208141227bb5beb9baaf1f4e08397 vendoo/extensions/safari/web-extension/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 vendoo/extensions/safari/web-extension/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a vendoo/extensions/safari/web-extension/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 vendoo/extensions/safari/web-extension/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extensions/safari/web-extension/vinted-categories.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 vendoo/extensions/vinted-categories.js
9a5bfcafdce53130d7bc36695090a8f87096b4ead9dd5ccc3d46d1d80c07a0fa vendoo/lib/ai-claude.mjs
ad6ba4ef521557d5c06bc546cda70db57e710e8173daadae74e8f15f99836c1c vendoo/lib/ai-flux-prompt-jobs.mjs
347778ce521a1919ec0679918171dc625d7f04d6dec26c8a4700e702bc78de67 vendoo/lib/ai-local-images.mjs
aeb5103c0179232b9954b7854be8099cf4bb0f3ef1ee908eb5e4faf6a8f1205f vendoo/lib/ai-local.mjs
29fbe09982b0b327b773bd119f57f50363424161815ac894ca4d677759e93e83 vendoo/lib/ai-model-jobs.mjs
9f474f665d6d610fe00d9e707e85314a854abb906e31db2bb9a3a7c76785ff4f vendoo/lib/ai-model-photos.mjs
3fb484456b9e6374f14b53a2276eea8533642b7c9073bb73a1bb0dbed7048bbd vendoo/lib/ai-openai.mjs
581c10b8346d0aa10169ed23ed49c038951ecd5cac014722c1080bbd5aec1c5b vendoo/lib/ai-openrouter.mjs
271696d7cbef3581b667a8ce3b07d0b17b1e8b467fbede4d8aa512ecc5225515 vendoo/lib/ai-router.mjs
76a2f1fdf60053739d82962264219060807022dfc9a2b3a644946fddff02a8d9 vendoo/lib/archive.mjs
2015974b9ceced554ecf0cfbdbf50a7d1db57459d50fb0241b8e9277559e70f4 vendoo/lib/auth.mjs
3e2b75c0758703e590233cbcc9b589e3177134accecf5ed921791891cbfc8522 vendoo/lib/categories.mjs
86793fb57a1dad32f4d93e34c27ffe9e77a95785dd30b2b55ffb67d0ad5e14fb vendoo/lib/config-store.mjs
8c203e70e9ab07b996d4a53031892bbf37b10efd024f9e0013266cf2af0244a4 vendoo/lib/db.mjs
54722d3f76ad9ee4fbe731d3a65c2a03d343eb82d98f8ea5a5996b1bec24d57f vendoo/lib/ebay-api.mjs
524f1b48d467998da819f0b947f2551ad45784e588eb442304c5f6e925dffaee vendoo/lib/etsy-api.mjs
5b2c566ff14fa502ba2cd4d4c918fe238a8e93c3283d521144093a897f9d8018 vendoo/lib/fees.mjs
7dcb2fb5606140afb7a019094d20ef88e9b4e2c70041f77b06d67d8992fd25ce vendoo/lib/html-templates.mjs
e41a13284429ac01652d979efd0734d5a2b29945e7e93a910b44eaefab9c00b6 vendoo/lib/image-batch-jobs.mjs
5ca5fc65a7de7c27243646d291dc42c0b5267a47705a09b306cd2c2eae2a77c8 vendoo/lib/image-editor.mjs
5e7aa66faddd3d19bc6ebb9ddc13abfc4ab4f17d8c51bb39b2c4e0279385d788 vendoo/lib/images.mjs
606f4cb1013c711d971dd201ab06df84ecb128bf5d5277095ce2e2ea56029e45 vendoo/lib/mailer.mjs
493895deb08e51ef1f47b55c88e3225bb267ade9fe305a7ed2c59a3f417fab16 vendoo/lib/operations-center.mjs
f10c3951bc604392e9fdaef7ba51b227893266baaa93981aa480409fed722062 vendoo/lib/publishing-jobs.mjs
3a728417dd668d60fd1526ec738cb9b302f86c01d62b2227f12b2e44b7d389c7 vendoo/lib/quality-center.mjs
74c783c1e06e9cc2da0165261a49511aaf374dab3159cbc24c0d69b6b467dcb9 vendoo/lib/runtime-paths.mjs
d3d862ab32fd276ecffb54c0307976ca680135d92f24d024c95d365a50257643 vendoo/lib/secret-store.mjs
f6bf70cd77a973daba47f6ab73b21413874055f1a71525ac0ed80a631aea16eb vendoo/lib/security.mjs
2fd970a6a357a26211f0b9bcf432e59e79f73dc9a4cd35f88cca939655eefdff vendoo/lib/structured-logger.mjs
ddb9c7677600795a4adf8a19a7525b7551455459d16eed4cdfbe751ef9ddf0eb vendoo/lib/zip.mjs
2924f4e8abe5ebbd099fe1ceb2bc6ceb4bdda55fa3e57dd299cfc05d310a9246 vendoo/local-ai/start-local-flux.ps1
7c6176d8311b1ba9d511beb40edd41b8248e61c298528bbec3f9ef1171856c05 vendoo/local-ai/stop-local-flux.ps1
5f220a2dca02cc0764f6d0157677611b26c88860b48367eb661b6e47a1b92265 vendoo/local-ai/workflows/vendoo_flux_schnell_api.json
95cf27f33fc83f1b74ba4a8c0a0688e3f3ab83f6194b030709adadeff2550ed0 vendoo/package-lock.json
531673457db5e06958561c2cc5fa2aa2f32837157936ceb406fd3d907d744529 vendoo/package.json
3da71dd28cb25c7c7317b9061855d40c6a3ab8bc39391963b49ee1e707f838e5 vendoo/platforms/ebay-de.mjs
cc1ca2b4384c8c548bf755dc33101d248541bf893c3d5f35369961f904afcc00 vendoo/platforms/ebay-ka.mjs
fa52b247dd758aeee06120499bd1ae6c53e9f460f8bd7762b8f06141b201e32b vendoo/platforms/etsy.mjs
5c925e3934a4c9e2f26dc15b3449a249f5ce20ecebbd459b15365a34804824d6 vendoo/platforms/vinted.mjs
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 vendoo/public/android-chrome-192x192.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f vendoo/public/android-chrome-512x512.png
0748df67926d63afb7d3fba9c1a451491631f9682477ee2c24f3a3e69120c066 vendoo/public/app.js
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 vendoo/public/apple-touch-icon.png
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 vendoo/public/brand/favicons/android-chrome-192x192.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f vendoo/public/brand/favicons/android-chrome-512x512.png
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 vendoo/public/brand/favicons/apple-touch-icon.png
a0f1e01de4e8215e690c1ce869fecaae9d7ba3cc95883340a53ff38f6be52ce0 vendoo/public/brand/favicons/browserconfig.xml
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/public/brand/favicons/favicon-16x16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/public/brand/favicons/favicon-32x32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/public/brand/favicons/favicon-48x48.png
15bf8dd655b34a8015447e834d387af12685238ede598f5f0e7927eea2933483 vendoo/public/brand/favicons/favicon.ico
2daa93cca0ad2c0cab90a9e8ad4ea0ae4b64feeb68c422954020d17e2376a381 vendoo/public/brand/favicons/html-snippet.txt
3798313cc939d9fa582a92638356abfcfc8f8b4f143d9434b7012446195e6937 vendoo/public/brand/favicons/mstile-150x150.png
c372675942caa5010340f21fe521adc72af537d909008731976820fd84604d42 vendoo/public/brand/favicons/site.webmanifest
b2dc767e7a01395d23a7f3f5915324db1a7d1912bac60470d2f7c10815895173 vendoo/public/brand/icons/vendoo-icon-120x120.png
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf vendoo/public/brand/icons/vendoo-icon-128x128.png
d276f50b298e4dfcbba9147550463aee498531280399167d1e9774aa8e5f7e21 vendoo/public/brand/icons/vendoo-icon-144x144.png
3798313cc939d9fa582a92638356abfcfc8f8b4f143d9434b7012446195e6937 vendoo/public/brand/icons/vendoo-icon-152x152.png
47122dc91010721e2692d11986f0b91d9b76634130a95723e92b2a070268d16f vendoo/public/brand/icons/vendoo-icon-167x167.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b vendoo/public/brand/icons/vendoo-icon-16x16.png
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 vendoo/public/brand/icons/vendoo-icon-180x180.png
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 vendoo/public/brand/icons/vendoo-icon-192x192.png
3f2517cfd215cb624ed639d60b064dfa5e88ce71eb7bbebbbfaa70b3d62556db vendoo/public/brand/icons/vendoo-icon-256x256.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 vendoo/public/brand/icons/vendoo-icon-32x32.png
cae3eb737c8ad3a82a679b09d33d991b501bf482e0132e99aa1b8ad064e472b4 vendoo/public/brand/icons/vendoo-icon-384x384.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 vendoo/public/brand/icons/vendoo-icon-48x48.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f vendoo/public/brand/icons/vendoo-icon-512x512.png
bc85af557be532dcce6beb82cf9bd61af683666b00fb61e4b2069f78e60a9a33 vendoo/public/brand/icons/vendoo-icon-64x64.png
01d59b665bc90dddbd34221e3a2ec3af11bff6fb328aab2c9947c03d74b0465d vendoo/public/brand/icons/vendoo-icon-72x72.png
ed3dfa59e989b154fac88a3c72ac840290ee3e1565d44aa75596bf0055c74020 vendoo/public/brand/icons/vendoo-icon-96x96.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f vendoo/public/brand/icons/vendoo-icon-original-1254.png
8fd9901e07dc9172d162706511ac8dcce220a4c907cb3efa9940c9c13fa32526 vendoo/public/brand/logo/vendoo-logo-cropped.png
3f39371abd1efa6cc8366aac9a6d067f3339b8f2a2da77ab8a26c6bdcf8c4fce vendoo/public/brand/logo/vendoo-logo-original.png
b56d07515f6220de7fd0cb149fed598a7361c985ae6ca7cb14329a99e8947aee vendoo/public/brand/logo/vendoo-logo-transparent.png
e83921d2af9930ab27df1abe64374cb9311189bfaaa951068109177443571a07 vendoo/public/brand/logo/vendoo-wordmark-transparent.png
1711a9387f2d6e75797b77c8daa92b94d7a15e128476e4b8aa9d54ccb0692a0e vendoo/public/core/api-client.js
f30395399a5c6d7e0a884b22f28f7648e6343695cee9960d6ff13b34de7b48f1 vendoo/public/core/frontend-module-registry.js
fb3dbcd03f7ed15b773b582c2a2b785c3040d3319aba5b7c682a7e74e1cf3b4e vendoo/public/core/safe-dom.js
38aa57d13aeb3ab70babcb903bfee71e47d80932ed24a73267c13ff81c24e3ba vendoo/public/design-system/theme-contract.json
308f1c0e2ed1de34aa11545a1a660aab02631e422d6c6945e3203d11666784fc vendoo/public/design-system/theme-runtime.js
4d69e2cb6b7f9f63b54d708a5d8b1ebefcdcb9f88a977053db5031c05b098464 vendoo/public/design-system/tokens/source.json
4a9e65edeaee3421edc3dd4831230062494f1a42f8495f4cb979fde8664d06c4 vendoo/public/design-system/tokens.css
15bf8dd655b34a8015447e834d387af12685238ede598f5f0e7927eea2933483 vendoo/public/favicon.ico
5b14c728ef81ca4554510f29ab5050a6e4da0b61db670f0745847e2670d22524 vendoo/public/index.html
f7e763f28b1ecf17919752081d94b169e499bba27b421c2276704945f91562db vendoo/public/login.html
e37558ee9612a36db8a19999fbb320f1c249a8e155f94c83a82926bec920f989 vendoo/public/login.js
59291f75eca405e3856bafea76cc601d681060eb6b36bf82a4be3c3ab7eac290 vendoo/public/mobile-upload-expired.html
f046f166d89fc32774b87deb02e6d144fd2f40c0925aac67487e5b7c489a0ec1 vendoo/public/mobile-upload.css
6152e4fe715efbf8fd6a7c4286f23172bc3cf15dde085e5e4f7389ad5e65ad73 vendoo/public/mobile-upload.html
f13846801a8493aa43df6ec3d78b826b21b59e8f21d47735f68fd0b278e440c7 vendoo/public/mobile-upload.js
01f2bd124257220005032bf234d122b9942fdd8fd57ed8195748b2fb1f5a5cfb vendoo/public/modules/README.md
3132436d52caba719a3460c29a807e6f0703cb2118a80c9fae6c30360498d249 vendoo/public/modules/module-manager/module-manager.css
bf10d5ccc53f287a8b61d488af50c3151c764f36a29ee5d4fe9ee321fa0eda06 vendoo/public/modules/module-manager/module-manager.js
2d7a004db3e22b30ad3a682ba445bcee3fc1c5f0ed5e8fee45b5892c5b335e51 vendoo/public/modules/theme-manager/theme-manager.css
0edc61f0c2bb604c3adc40813b18fe5ca8d9b846ec2a3d9f406ae26ae313d3ee vendoo/public/modules/theme-manager/theme-manager.js
e0a6c981d4231eab26d981be62647d0e6f89e05e8371baad121348202ad54f49 vendoo/public/style.css
ff525e0af963e6f54636cfdc1bd2d045aaf82e7b0199755eb5cdf4c52110be2e vendoo/public/vendoo-icons.js
f397e46da92394d34c2fc01715f037cca380703ecfa1d4a451de8ec7342e05b3 vendoo/scripts/docker-backup.sh
86a411ae1fa5e36a11b0a8cb61e6c0169e0b80d3cedc9b7b82c3cfff23dd7390 vendoo/scripts/docker-entrypoint.sh
1b58c1e5f762c4928d42605c01872f38f6d6bca92342260f3cd88a132e6af095 vendoo/scripts/docker-restore.sh
781c48e182149dbdfdcaa0ad505d92fd6f68998c9df2269c1ff46088359ce3d2 vendoo/scripts/github-deploy.ps1
f9fcdc69bd0b8c63c0dd6ecbb3fc35a55246e62a0db127f36687c3cc4cc1751b vendoo/scripts/github-deploy.sh
0a9bafc79c1c5d59fb9b51ebc34c00eec4a4e9a5e873ce1818f50f3ab983da70 vendoo/scripts/install-local-flux.ps1
2924f4e8abe5ebbd099fe1ceb2bc6ceb4bdda55fa3e57dd299cfc05d310a9246 vendoo/scripts/runtime-start-local-flux.ps1
7c6176d8311b1ba9d511beb40edd41b8248e61c298528bbec3f9ef1171856c05 vendoo/scripts/runtime-stop-local-flux.ps1
1a5736cf5fccc991df122163977c2eac80281bd99a54a5680b3d7eae99e4b79d vendoo/scripts/start-local-flux.bat
3bf3aa74f5cc1f2946bb2da637eb30fe8daec783a32f9721ebb0468e20df90bd vendoo/scripts/uninstall-local-flux.ps1
87d95670742b567e646fabe09460f97272bf984316150804e83099059574d266 vendoo/server.mjs
e74d70244e676d1955443ea61ba68cc44a83c35db1a298a71e67dbdf4892d313 vendoo/setup-gui.ps1
cf4519ce5adc01f05458e3286e86f3a419cceaff5fcdd869a1d07f1c1d1a0d8c vendoo/setup.bat
80baa880c86b9a3b4209990038685770665e059f2d43d7f827ca5e326230f5e4 vendoo/setup.ps1
e1b6b956c164e16d0151501f78d4928b775027bddd28c2c2eb1c038ab592fe84 vendoo/setup.sh
90485a16e3468cb9a6750646700fbb036cb9ac410e9b8bd5c582f7b923bf3c31 vendoo/tools/build-release.mjs
94f4ced84834fceeb4f797bf8aab0703c873b57fd5d4a5b3fb02fee12e42bd2e vendoo/tools/check-syntax.mjs
ac8440bce2659a035302609722f1dfed5d125223376cd575ffc0636397c94b54 vendoo/tools/generate-design-tokens.mjs
ae80c11b7a76f9c397f47f11dd1df940d546aa120eb55852535b867091c39ff4 vendoo/tools/prepare-git-staging.mjs
85114eff887ba65ca7df00f43333414c44b3aadc16fbc2fe10dc4dd4f9aa7aed vendoo/tools/verify-catalog-media-1.39.0.mjs
7940884a0456bc7561c5e54bee14d11e2c9ad8edf3888af6a980ca7d495adb3f vendoo/tools/verify-catalog-media-1.40.0.mjs
93d8fdee3feaf6e82ef15e7ac84bfd7e43ad13192f94655ccfce37f5a87b21ef vendoo/tools/verify-catalog-services-1.39.0.mjs
97b311f8245eb9a8ab34387ef2608a664bbb6e313350f6da6c5e8b2a5f36e57c vendoo/tools/verify-catalog-services-1.40.0.mjs
8f9ede5f112ee03323db3a6c73aee00b7037f5139dad241b11baf5f0e9cee4e0 vendoo/tools/verify-config-store.mjs
5752f6edb956696781da8bddb1c1848d26941fbed5a524691653c84c88c34bff vendoo/tools/verify-db-migrations.py
3745de55a110d8254983b096c6afab196ddaec7f1153cd2f34c1e480b15aa33e vendoo/tools/verify-deployment-1.32.0.mjs
44f6b349b722e5a83d4725c4879fa1a9383f59ab5634c49d3d7d9d7aa0cd5e12 vendoo/tools/verify-deployment-1.33.0.mjs
cbd91b45d97e11bd4f5ca2f9d2edf2b5931cb2aa336cb71afc30aad9cffbe1e0 vendoo/tools/verify-deployment-1.34.0.mjs
01a43040a95cdac40703f49031acd9267cdba99d9027a51718f35ffb643237fc vendoo/tools/verify-deployment-1.34.2.mjs
906767e574c06aedebb2d7797150bda2f1e4c4536e8f82f4c7de2e3cc8398c8e vendoo/tools/verify-deployment-1.34.3.mjs
71d00227a59592cc0ad8ba321c63350ec25748ef965d8cd0eff1317738c7fba8 vendoo/tools/verify-deployment-1.35.0.mjs
b65eec7fd54e1459b363d99d20f9438ae5bc4b518e775de8b97e33e89a382e42 vendoo/tools/verify-deployment-1.36.0.mjs
22a5ba1951b2e8dbc924e60aaff8be7c41189ae7b30de9ecf50d0b741e84e13a vendoo/tools/verify-deployment-1.37.0.mjs
84961aed097ee00496dd853677895614263baf425b00218cc0e1f3ced1b5b7b9 vendoo/tools/verify-deployment-1.38.0.mjs
2ecf465073b7ec9e8ba38bf83364f681886d50440fbdd579a5df14df5d1bb3af vendoo/tools/verify-deployment-1.39.0.mjs
4b37972998d87c1336590e2550895a826d63b47e4828d5bb3ba619376c287271 vendoo/tools/verify-deployment-1.40.0.mjs
947942c84416b126f29281a8bef7b8230ecde09ea8b3bf3304cfacb0f9623fff vendoo/tools/verify-deployment-1.40.1.mjs
ee2bb20f860d7238f767b181be1ed543214cc80230036389037d405e67c913bc vendoo/tools/verify-esm-export-contracts.mjs
edfd749dfd685844043ee7cb47aa8567259356f85735bc8018d12b2b1e700649 vendoo/tools/verify-flux-loop-hotfix-1.40.1.mjs
d835975a24c188f9f2b7b82e4a8a21cc2104d7f4c9aca56f532bc14dee6e4429 vendoo/tools/verify-git-safety-regression.mjs
195af91a936d6d809967acaa18b230fc0a1723b94b4e21a22276e5c06af85ef5 vendoo/tools/verify-git-safety.mjs
86a852edf45a0c6067f950eeadbcd599ae46d929c79cffd3a1ece82c3d554493 vendoo/tools/verify-git-staging.mjs
1d4351e4a827e718766a1677ddfbc3771a91942d0d5a93753e39f1b99c68a4dd vendoo/tools/verify-hotfix-1.23.2.mjs
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 vendoo/tools/verify-identity-db-1.38.0.py
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 vendoo/tools/verify-identity-db-1.39.0.py
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 vendoo/tools/verify-identity-db-1.40.0.py
1b5c21eb5688bc15895541968fa1ab69a2384ed611b01d23901abc040dcc3255 vendoo/tools/verify-identity-settings-1.38.0.mjs
a1dddb35f4b6eeafe47ff3f40e5565bdb4477c8f63101d3c0d7f84c7393abe4c vendoo/tools/verify-identity-settings-1.39.0.mjs
763bc084a0fd850ad35fb9bccd49f0ccd310eae77adc8573969cce1b7f9b5d3d vendoo/tools/verify-identity-settings-1.40.0.mjs
44c95844422be3deaad6054ee3f0cced9c25986815d976e0c64b042d0c2c5e1e vendoo/tools/verify-installer-shell.sh
a8760388717a464d532ceb5dfaa55ae327384631b6edd3fdd91387c952ec114c vendoo/tools/verify-module-manager-1.40.0.mjs
cab03e98687af87f359f6424d440fc0b644da97b3c614509b8c7d008d4b18a8d vendoo/tools/verify-platform-architecture-1.35.0.mjs
732bb15431746a829e45ae55c695360cbf1dd21d4fc3be26a98f35708d571e84 vendoo/tools/verify-platform-architecture-1.36.0.mjs
ee8ae7bed4e93a2ef278662552a4ae5d751306aad7133a93f380bbf2a5d5a28c vendoo/tools/verify-platform-architecture-1.37.0.mjs
584ea4735937238b4c3bffa70364d0f45cf1f3d41bf34adde64c7cbb7b729efa vendoo/tools/verify-platform-architecture-1.38.0.mjs
f8590c6986786cbbce95e58af1d1d3fec61d163c19fcf4c22aff57f5954c398e vendoo/tools/verify-platform-architecture-1.39.0.mjs
c9e704c372cf6a973fcdb887b337ead6509fd03e78570e6d1c9e24b1d879fe6b vendoo/tools/verify-platform-architecture-1.40.0.mjs
36e35fedb08923c22fd8551389d33432b66dbd4215d95c594ef29bfc790c98e0 vendoo/tools/verify-release-1.25.0.mjs
89621694b7bad18b6f3f1ac1956032f64112c40d3edc069ca581dc813d57d628 vendoo/tools/verify-release-1.25.1-static.mjs
c908f5186cf2d71ef83d5e649327ae19965568933acfb32057ca00d29cf890bc vendoo/tools/verify-release-1.25.1.mjs
e31a055d2ebb8e439f5b0e0235a71dacecb891e299377cfbbcfa8a32f53a85b0 vendoo/tools/verify-release-1.26.0-static.mjs
7e107b5f9a1b4ee381ff31105feb6d38dda5c40e4afe105a955badc36e6b8d10 vendoo/tools/verify-release-1.26.1-static.mjs
d9a75c45f40d857c84790d51dca2fd088c3851ca250405871a7e32773918c66e vendoo/tools/verify-release-1.27.0.mjs
3989e3ec236c1aa4c387b26cc15e04cf200a018e29c095321acf826c6bae4d66 vendoo/tools/verify-release-1.28.0.mjs
7d196d913a697248ab1233907fed56c10329cf201e3bdc173bca73cb02755369 vendoo/tools/verify-release-1.29.0.mjs
3f30260dabbdf0fa7b042381cb9e24f840d0c3ddbc44fe309763789a7d14afb7 vendoo/tools/verify-release-1.30.0.mjs
b1ceed5dfc17dbd3b038b7168e61076e4d39a0f1d67e2b87677a91c4dbb2daff vendoo/tools/verify-release-1.31.0.mjs
a372258b97aa68d59a1fe0fd3f380d019c59412d5c408a6064f437d5cfc6e709 vendoo/tools/verify-security-1.31.0.py
08820d9bb7be1dec496c04e9ea4a39b2ebb84d373a9481136610d16dea0edde3 vendoo/tools/verify-security-foundation-1.37.0.mjs
a415d294679adab8ea76b86235a522e73ad9dd9ea0e2348691b1de3191255b81 vendoo/tools/verify-security-foundation-1.38.0.mjs
805aa61d7f9cba8c20afda0dd871189108b02f3751f8a75963784cc12fd6cf76 vendoo/tools/verify-security-foundation-1.39.0.mjs
23cb2414515011e8c3b277a50a9090593aa176fc9c9435c74cdd6d8117bac63f vendoo/tools/verify-security-foundation-1.40.0.mjs
31a120622ce8bb8451014f2662366f81abd28d0f3be59adfe35d17e0ada1838f vendoo/tools/verify-slice30-mock.mjs
20957a4a038b9afdb01a8c98b881644daf793d2a6bb778a4c8e04780687d00e4 vendoo/tools/verify-slice31-image-editor.mjs
21061ed5dc88feef48e80efffd9a1054d38598dce5a5d3f9f6bde39b539b83f0 vendoo/tools/verify-slice32-batch.mjs
0f05b1ac3b686cf535bcfb3e6f6df24a29c3429ade1b3c666c1b99abb1a7311b vendoo/tools/verify-slice32-image-render.mjs
c9aa6693aa93ff1f220a2ce3bc35ef714a0b18a53eae0f907879fc92c66c1e38 vendoo/tools/verify-theme-manager-1.36.0.mjs
1e61c4b180aa09de3dae9e72aef313b09a6f422229f180984b69a8d226e7cd8d vendoo/tools/verify-theme-manager-1.37.0.mjs
3257b31d80034c077b25d3f1b13f8378378772bc6512445aa5ac8e882e4be109 vendoo/tools/verify-theme-manager-1.38.0.mjs
41033ba36a11a14ab74a80d65c1124848eddee21a5f3fef8bd5ab001699e2e4b vendoo/tools/verify-theme-manager-1.39.0.mjs
233070db91925520dc31131a55579bc83fdcd340e4d19e90510f089c060f0c43 vendoo/tools/verify-theme-manager-1.40.0.mjs
0f3f684019763a14f5fbaec42e42c680cf748d930d46cd607fc61eb413ca4553 vendoo/tools/verify-ui-contracts-1.26.1.mjs
0be781fa922c6c915b10730db1e3a01676cce4e65fd8cd216da5a9444f237f3c vendoo/update-manifest.json
@@ -0,0 +1,27 @@
.git
.gitignore
.env
.env.*
!.env.example
node_modules
npm-debug.log*
*.log
*.db
*.db-*
*.sqlite
*.sqlite3
backups
operations
logs
uploads
runtime
data
local-ai/comfyui
local-ai/downloads
local-ai/.env.local-flux
MockupDesign
*.zip
FILE_CHECKSUMS_SHA256.txt
release-output
.vendoo-github-state.json
operations/first-admin-code.txt
@@ -0,0 +1 @@
* @Masterluke77
@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: '05:00'
timezone: Europe/Berlin
open-pull-requests-limit: 5
groups:
npm-production:
dependency-type: production
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
time: '05:30'
timezone: Europe/Berlin
open-pull-requests-limit: 5
- package-ecosystem: docker
directory: /
schedule:
interval: monthly
time: '06:00'
timezone: Europe/Berlin
open-pull-requests-limit: 5
@@ -0,0 +1,20 @@
## Änderung
<!-- Was wurde geändert und warum? -->
## Sicherheit und Daten
- [ ] Keine `.env`, Tokens, Datenbanken, Uploads, Backups, Logs oder Modelle enthalten
- [ ] Bestehende Benutzer- und Artikeldaten bleiben erhalten
- [ ] Originalbilder werden nicht überschrieben
- [ ] FASHN VTON / Virtual Try-on wurde nicht wieder eingeführt
## Prüfung
- [ ] `npm ci`
- [ ] `npm run verify:git`
- [ ] `npm run check`
- [ ] `npm run verify:architecture`
- [ ] `npm run verify:deployment`
- [ ] `npm run verify:db`
- [ ] Windows-/Docker-/Browser-Abnahme dokumentiert oder ausdrücklich als offen markiert
@@ -0,0 +1,101 @@
name: Vendoo CI
on:
push:
branches: [main, develop, 'feature/**', 'release/**', 'hotfix/**']
pull_request:
branches: [main, develop]
permissions:
contents: read
concurrency:
group: vendoo-ci-${{ github.ref }}
cancel-in-progress: true
jobs:
quality:
name: Syntax, Sicherheit und Release-Gates
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Repository auschecken
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Node.js 22 aktivieren
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: npm
- name: Abhängigkeiten reproduzierbar installieren
run: npm ci
- name: Git-Sicherheitsgate
run: npm run verify:git
- name: Git-Sicherheitsgate Regressionstest
run: npm run verify:git-regression
- name: Git-Staging-Filter Regressionstest
run: npm run verify:git-staging
- name: Syntaxprüfung
run: npm run check
- name: ESM-Exportverträge prüfen
run: npm run verify:esm-exports
- name: FLUX-Loop-Hotfix prüfen
run: npm run verify:flux-loop
- name: Plattformarchitektur und Design Tokens prüfen
run: npm run verify:architecture
- name: Theme Manager, Accessibility und Komponenten-Tokens prüfen
run: npm run verify:themes
- name: Security, Secrets und Observability prüfen
run: npm run verify:security
- name: Auth, Benutzer, Sitzungen und Einstellungen prüfen
run: npm run verify:identity
- name: Artikel, Lager und Medien prüfen
run: npm run verify:catalog
- name: Modulmanager, Pakete und Aktivierungsgrenzen prüfen
run: npm run verify:modules
- name: Deployment-Gate
run: npm run verify:deployment
- name: Persistenten Konfigurationsspeicher prüfen
run: npm run verify:config
- name: Geführte Shell-Installer simulieren
run: npm run verify:installer-shell
- name: Datenbankmigrationen prüfen
run: npm run verify:db
- name: Docker-Compose-Dateien validieren
run: |
cp .env.example .env
python - <<'PY'
from pathlib import Path
p=Path('.env')
s=p.read_text()
s=s.replace('VENDOO_SETUP_TOKEN=', 'VENDOO_SETUP_TOKEN=ci-only-not-a-production-secret-1234567890')
s=s.replace('VENDOO_DOMAIN=', 'VENDOO_DOMAIN=vendoo.example.invalid')
p.write_text(s)
PY
docker compose -f compose.yaml config -q
docker compose -f compose.yaml -f compose.bind-mounts.example.yaml config -q
docker compose -f compose.vps.yaml config -q
rm -f .env
- name: Docker-Image testweise bauen
run: docker build --pull --tag vendoo:ci .
@@ -0,0 +1,149 @@
name: Vendoo Release
on:
release:
types: [published]
permissions:
contents: read
concurrency:
group: vendoo-release-${{ github.event.release.tag_name }}
cancel-in-progress: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: masterluke77/vendoo
jobs:
release-assets:
name: Release-Paket und Prüfsummen
permissions:
contents: write
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Repository auschecken
uses: actions/checkout@v6
- name: Node.js 22 aktivieren
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: npm
- name: Abhängigkeiten installieren
run: npm ci
- name: Release-Tag gegen Paketversion prüfen
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
EXPECTED="v$(node -p "require('./package.json').version")"
test "$RELEASE_TAG" = "$EXPECTED" || { echo "Release-Tag $RELEASE_TAG passt nicht zu $EXPECTED." >&2; exit 1; }
- name: Vollständige Prüfung
run: |
npm run verify:git
npm run verify:git-regression
npm run verify:git-staging
npm run check
npm run verify:esm-exports
npm run verify:flux-loop
npm run verify:architecture
npm run verify:themes
npm run verify:security
npm run verify:identity
npm run verify:catalog
npm run verify:modules
npm run verify:deployment
npm run verify:config
npm run verify:installer-shell
npm run verify:db
- name: Release-Staging erzeugen
run: node tools/build-release.mjs
- name: ZIP und SHA-256 erzeugen
id: package
shell: bash
run: |
PACKAGE_NAME="$(cat release-output/RELEASE_NAME.txt)"
cd release-output
zip -r -9 "${PACKAGE_NAME}.zip" "${PACKAGE_NAME}"
sha256sum "${PACKAGE_NAME}.zip" > "${PACKAGE_NAME}.zip.sha256.txt"
echo "package_name=${PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
- name: Assets an GitHub Release anhängen
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
PACKAGE_NAME: ${{ steps.package.outputs.package_name }}
run: |
gh release upload "$TAG" \
"release-output/${PACKAGE_NAME}.zip" \
"release-output/${PACKAGE_NAME}.zip.sha256.txt" \
--clobber
- name: Build-Artefakte sichern
uses: actions/upload-artifact@v4
with:
name: ${{ steps.package.outputs.package_name }}
path: |
release-output/${{ steps.package.outputs.package_name }}.zip
release-output/${{ steps.package.outputs.package_name }}.zip.sha256.txt
if-no-files-found: error
retention-days: 30
container:
name: GHCR-Container veröffentlichen
permissions:
contents: read
packages: write
attestations: write
id-token: write
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- name: Repository auschecken
uses: actions/checkout@v6
- name: Docker Buildx aktivieren
uses: docker/setup-buildx-action@v3
- name: Bei GHCR anmelden
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Container-Metadaten erzeugen
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ github.event.release.tag_name }}
type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }}
type=raw,value=latest,enable=${{ !github.event.release.prerelease }}
- name: Container bauen und veröffentlichen
id: push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
provenance: true
sbom: true
- name: Container-Provenienz attestieren
uses: actions/attest@v4
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
@@ -0,0 +1,91 @@
# Secrets and local configuration
.env
.env.*
!.env.example
!.env.docker.example
*.pem
*.key
*.p12
*.pfx
*.crt
# Dependencies
node_modules/
# SQLite runtime data
db/*.db
db/*.db-shm
db/*.db-wal
db/*.sqlite
db/*.sqlite3
# User and runtime data
uploads/*
!uploads/.gitkeep
backups/
logs/
tmp/
temp/
sessions/
data/
docker-data/
*.log
# OS and editor files
.DS_Store
Thumbs.db
desktop.ini
.vscode/
.idea/
# Local overrides
compose.override.yaml
docker-compose.override.yml
# Local AI runtimes and downloaded model data
local-ai/comfyui/
local-ai/downloads/
local-ai/extract-temp/
local-ai/fashn-vton/.venv/
local-ai/fashn-vton/engine/
local-ai/fashn-vton/weights/
local-ai/fashn-vton/outputs/
local-ai/fashn-vton/runtime/
local-ai/fashn-vton/hf-cache/
local-ai/fashn-vton/fashn-vton-*.zip
local-ai/fashn-vton/python311/
local-ai/fashn-vton/uv/
local-ai/fashn-vton/uv-cache/
local-ai/fashn-vton/downloads/
# Local update, rollback and slice archives
updates/
# Operations Center runtime
operations/staging/
operations/updates/
operations/rollback/
operations/apply-*/
operations/pending-operation.json
operations/last-operation.json
# Deployment assistant state
.vendoo-install-mode
runtime/
# Generated deployment and release output
release-output/
*.release.zip
*.release.sha256.txt
.vendoo-github-state.json
# First-run and local installer state
operations/first-admin-code.txt
config/local/
# Installed Vendoo module packages (runtime)
modules/
# Python cache
__pycache__/
*.pyc
@@ -0,0 +1,9 @@
registry=https://registry.npmjs.org/
audit=false
fund=false
strict-ssl=true
prefer-offline=true
fetch-retries=5
fetch-retry-factor=2
fetch-retry-mintimeout=10000
fetch-retry-maxtimeout=120000
@@ -0,0 +1,796 @@
# Changelog
## 1.40.1 FLUX Worker Lifecycle & ESM Export Contract Hotfix
### Behoben
- `server.mjs` konnte wegen des fehlenden Exports `stopFluxPromptJobLoop` nicht instanziiert werden.
- FLUX-Prompt-Job-Worker besitzt jetzt einen idempotenten Stop-Lifecycle mit `clearInterval()` und Zustandsreset.
### Qualitätssicherung
- neues generisches ESM-Export-Vertragsgate für lokale benannte Imports.
- separates FLUX-Loop-Hotfix-Gate in lokaler Prüfung, GitHub CI und Release-Workflow.
- keine Datenbankmigration, kein Reset und keine Änderung an Nutzdaten.
## 1.40.0 Native Publishing, AI, FLUX, Quality & Secure Module Manager
### Neu
- `vendoo.ai`, `vendoo.flux-studio`, `vendoo.quality`, `vendoo.publishing` und `vendoo.module-manager` als native Module.
- 16 registrierte Module: 14 nativ, 2 Legacy Bridges.
- administrative Modulmanager-Oberfläche für Aktivieren, Deaktivieren, Exportieren, Installieren und Entfernen.
- persistenter Modulstatus und separater Modulpaketspeicher.
- `.vmod`-Paketformat mit SHA-256-Integrität, sicherer Pfadprüfung und optionaler Ed25519-Signatur.
- deklarative Fremdmodule ohne ausführbaren Code; ausführbare Pakete bleiben bis zum isolierten Extension-Host in Quarantäne.
- Modulabhängigkeiten werden beim Aktivieren automatisch gestartet und beim Deaktivieren kontrolliert behandelt.
- Modulrouten werden bei deaktiviertem Besitzer mit `MODULE_DISABLED` gesperrt.
- Windows-, Docker-, NAS- und VPS-Backups enthalten Modulpakete und Aktivierungszustand.
- GitHub Draft Pull Request #13 für `release/1.40.0-module-manager`.
### Sicherheit
- geschützte Kernmodule können weder deaktiviert noch gelöscht werden.
- eingebaute Module können exportiert, aber nicht als Fremdmodule installiert werden.
- Fremdmodule werden nicht durch bloßes Kopieren aktiviert.
- der lokale Laufzeitordner `modules/` wird von Git- und Release-Staging ausgeschlossen.
- keine ungeprüfte Ausführung von Drittcode im Vendoo-Hauptprozess.
## 1.39.0 Listings, Inventory & Media Native Module Migration
### Neu
- `vendoo.listings`, `vendoo.inventory` und `vendoo.media` als native Plattformmodule.
- fünfzehn registrierte Module: neun nativ, sechs Legacy Bridges.
- öffentliche Artikel-, Papierkorb-, Lager- und Medienrouten aus `server.mjs` entfernt und über Modulverträge registriert.
- Repository-Injektion verhindert Datenbankzugriffe als Import-Seiteneffekt.
- eigenes `verify:catalog`-Gate mit Service-Regressionstests.
- GitHub Draft Pull Request #12 für `release/1.39.0-catalog-media`.
### Sicherheit und Datenintegrität
- Artikel-Payload-Allowlist blockiert unbekannte Felder, ungültige Preise, überlange Texte und Listen.
- Rich-HTML wird weiterhin serverseitig bereinigt.
- bestehende Bearbeitungssperren bleiben für Artikelupdates verbindlich.
- endgültiges Löschen ist ausschließlich für Artikel im Papierkorb möglich.
- Lager-Bulk-Aktionen sind auf 500 eindeutige positive IDs begrenzt.
- Medienpfade blockieren Traversal, Nullbytes und Zeilenumbrüche.
- Bilder, die von aktiven Artikeln referenziert werden, werden nicht gelöscht.
- unbekannte Medien- und Lagerfelder werden serverseitig abgewiesen.
### Kompatibilität
- keine destruktive Datenbankmigration und kein Reset.
- bestehende Artikel, Bilder, Uploads, Favoriten, Lagerorte und Publishing-Verknüpfungen bleiben erhalten.
- API-Pfade und bestehendes Frontend bleiben kompatibel.
- `lib/db.mjs` bleibt vorübergehend Kompatibilitätsschicht für AI, Publishing, Quality und Dashboard.
## 1.37.0 Security, Secrets & Observability Foundation
### Neu
- `vendoo.security` als natives Kernmodul.
- AES-256-GCM-verschlüsselter Secret-Speicher mit separatem Master-Key.
- Automatische Migration vorhandener Runtime- und SMTP-Secrets mit Sicherungskopie.
- Strikte Script-CSP ohne Inline-Skripte und Inline-Eventhandler.
- Request- und Correlation-IDs sowie strukturierte JSON-Telemetrie.
- Zentrale Input-Schema-Validierung für neue Kernel-Routen.
- Erweitertes Security-Dashboard für Secret-Provider, CSP und Requeststatus.
- SMTP-Zertifikatsprüfung standardmäßig aktiv.
- GitHub Draft Pull Request #10 für `release/1.37.0-security-foundation`.
### Kompatibilität
- Keine Datenbankablösung und keine destruktive Migration.
- Windows, Docker, NAS und VPS bleiben unterstützt.
- Theme Manager und vorhandene Daten bleiben erhalten.
## 1.36.0 Secure Theme Manager, Accessibility & Component Token Foundation
### Neu
- `vendoo.themes` als erstes natives Fachmodul auf dem Plattformkernel.
- Persönliche Theme-Präferenzen pro Benutzer mit Theme, UI-Dichte und reduzierter Bewegung.
- Sichere Theme-Profile für Administratoren mit Basis-Theme, Token-Overrides, Import, Export und Systemstandard.
- Live-Vorschau im Browser; Speichern erst nach expliziter Bestätigung.
- Serverseitige Validierung aller Theme-Werte und WCAG-orientierte Kontrastprüfung zentraler Text-/Oberflächenpaare.
- Light, Dark, System und High Contrast als integrierte Modi.
- 42 typisierte Design Tokens, darunter erste Komponenten-, Fokus- und Touch-Target-Tokens.
- Tokenisierte Buttons, Eingabefelder, Karten, Dialoge und Fokuszustände.
- Deny-by-default API-Verträge für Theme-Routen sowie getrennte Benutzer- und Administrator-Policies.
- Audit-Protokoll für persönliche Präferenzen, Theme-Profile und Systemstandard.
- Eigenes `verify:themes`-Gate in lokaler Prüfung, GitHub CI und Release-Workflow.
- GitHub Draft Pull Request #9 für `release/1.36.0-theme-manager`.
### Sicherheit und Kompatibilität
- Keine freie CSS-, JavaScript-, URL- oder Dateipfad-Eingabe.
- Unbekannte Tokens und Theme-IDs werden abgewiesen.
- Normale Benutzer dürfen ausschließlich ihre eigene Darstellung ändern.
- Systemstandard und benutzerdefinierte Profile erfordern administrative Berechtigung.
- Bestehende Daten, Benutzer, Artikel, Uploads, Backups und FLUX-Daten bleiben erhalten.
- Kein Reset, keine Framework-Migration und keine Datenbankablösung.
## 1.35.0 Modular Platform Kernel, Design-System Contracts & Security Architecture Foundation
### Neu
- Modularer Plattformkernel mit Lifecycle, Event Bus, Feature Flags, Modul- und Policy-Registry.
- Zwölf bestehende Fachbereiche als validierte `legacy-bridge`-Module mit expliziten Abhängigkeiten, Capabilities und Ownership.
- Deny-by-default Route Registry: neue Kernel-Routen benötigen Besitzer und explizite Policy.
- Administrativ geschützte Plattform-, Modul- und Theme-Vertragsendpunkte.
- Kernel-Healthcheck in `/readyz` und geordneter Kernel-Shutdown.
- Versionierte Design-Token-Quelle mit 33 Tokens für Light, Dark und High Contrast.
- Deterministischer Token-Generator und browserseitige Theme Runtime.
- Sichere Theme-Definitionen: nur freigegebene Farb- und Dimensionswerte, kein freies CSS/JS.
- Modul-JSON-Schema, Architekturgrenzen, Migrationsroadmap und Security-Architekturdokumentation.
- Neues `npm run verify:architecture` mit Zyklus-, Policy-, Event-, Theme- und Token-Regressionstests.
- GitHub Draft Pull Request #7 für `release/1.35.0-platform-kernel`.
### Kompatibilität
- Kein Reset, keine Framework-Migration, keine Datenbankablösung.
- Windows-Lokalbetrieb, Docker, NAS, VPS, Zero-Edit-Installer und Git-Sicherheitsgate bleiben erhalten.
- Bestehende CSS-Variablen bleiben über eine Token-Kompatibilitätsbrücke funktionsfähig.
- Bestehende Routen werden in 1.35.0 noch nicht massenhaft verschoben; die Migration erfolgt fachmodulweise.
## 1.34.3 Git-Staging Update-Archiv-Ausschluss Hotfix
### Behoben
- Der lokale Ordner `updates/` wird als Update-, Rollback- und Slice-Artefaktspeicher behandelt und nicht nach GitHub oder in Release-Staging-Verzeichnisse übernommen.
- Alte Sicherungskopien wie `updates/backups/.../setup.bat`, `setup.ps1` oder `scripts/install-local-flux.ps1` lösen das Git-Sicherheitsgate nicht mehr aus, weil sie bereits vor dem Scan ausgeschlossen werden.
- Die aktiven Installationsdateien im Projektroot und unter `scripts/` bleiben Teil des Quellimports.
- Das Git-Sicherheitsgate blockiert `updates/` weiterhin, falls ein fremder Kopierweg den Ordner dennoch in das Staging einschleust.
- `.gitignore` schützt den lokalen Updateverlauf zusätzlich vor versehentlichen Commits.
### Qualitätssicherung
- Regressionstest mit den drei konkret gemeldeten Pfaden aus `slice22_1_20260707-194953`.
- Release-Builder und GitHub-Deploy-Assistent verwenden weiterhin dieselbe Filterfunktion.
- Neuer Importbranch `release/1.34.3-initial-import` und Draft Pull Request #6.
## 1.34.2 Git-Sicherheitsdiagnose & gemeinsamer Staging-Builder
### Behoben
- Die Meldung `Git-Sicherheitsgate fehlgeschlagen (4)` wird nicht mehr ohne Detailzeilen ausgegeben. Der Windows-Assistent fängt stdout und stderr getrennt ab und zeigt jeden konkreten Treffer an.
- Der vollständige Fehlerbericht wird unter `logs/github-deploy-safety-report.txt` gespeichert und unter Windows automatisch im Editor geöffnet.
- Windows, Linux und macOS verwenden denselben Node-basierten Staging-Builder statt unterschiedlicher Robocopy-/rsync-Regeln.
- Lokale `.env.*`-Dateien, Operations-Daten, Uploads, Backups, Logs, Datenbanken, Schlüsseldateien und FLUX-/ComfyUI-Laufzeitdaten werden vor dem Sicherheitsgate automatisch aus dem temporären Git-Staging ausgeschlossen.
- `.env.example` und `.env.docker.example` bleiben als sichere Vorlagen enthalten.
- Der Staging-Builder leert nur den Arbeitsbaum des temporären Klons und erhält dessen `.git`-Verzeichnis vollständig.
### Qualitätssicherung
- Neuer plattformübergreifender Git-Staging-Regressionstest.
- Der Test belegt, dass lokale Secrets und Laufzeitdaten ausgeschlossen, öffentliche Vorlagen übernommen und `.git` nicht verändert werden.
- CI und Release-Workflow führen den Staging-Regressionstest zusätzlich zum Secret-Regressionstest aus.
- Neuer Importbranch `release/1.34.2-initial-import` und Draft Pull Request #5.
## 1.34.1 Git-Sicherheitsgate Windows Hotfix
### Behoben
- Windows-Pfade werden im Git-Sicherheitsgate mit `fileURLToPath(import.meta.url)` in echte Dateisystempfade umgewandelt.
- Der Sicherheitscheck scannt den vollständigen Import-Arbeitsbaum und nicht nur bereits von Git verfolgte Dateien.
- Noch unversionierte `.env.local`, `.env.production`, Token-Dateien und sonstige Secrets werden vor `git add` erkannt.
- Node.js ist für den sicheren Import verpflichtend; ein stilles Überspringen des erweiterten Scans ist nicht möglich.
## 1.34.0 GitHub CI/CD & Zero-Edit Installation Foundation
### Installation
- Grafischer Windows-Installationsassistent für lokalen Node.js-Betrieb und Docker Desktop.
- Geführte Linux-/NAS-/VPS-Konfiguration ohne manuelles Bearbeiten von `.env` oder Compose-Dateien.
- Automatische Erzeugung und sichere Ablage des Erst-Admin-Setup-Codes.
- VPS-Modus mit integriertem Caddy-Reverse-Proxy und automatischem HTTPS.
- Konfiguration kann später über den Assistenten geändert werden, ohne bestehende Daten zu löschen.
- Persistenter Runtime-Konfigurationsspeicher für Eingabemasken im gehärteten read-only Container.
- Simulierbares Shell-Installer-Gate für Docker-, NAS- und VPS-Modus; dabei wurde die Standardwert-Abfrage gegen Prompt-Vermischung gehärtet.
### GitHub und Releases
- Git-Sicherheitsgate gegen Secrets, Datenbanken, Uploads, Backups, Logs, Runtime- und Modellordner.
- GitHub Actions für CI, Docker-Build, Release-Pakete, SHA-256 und GHCR-Images.
- Windows- und Shell-GitHub-Deploy-Assistent für kontrollierten Erstimport auf einen Release-Branch.
- Privater Branch `release/1.34.0-initial-import` und Draft Pull Request #3 real vorbereitet.
- Release-Pakete werden aus einem bereinigten Staging-Verzeichnis erzeugt und nicht als Binärdateien in die Git-Historie aufgenommen.
### Sicherheit
- GitHub Actions besitzen jobbezogen minimale Berechtigungen.
- GHCR-Images erhalten eine Provenienz-Attestierung auf Basis des tatsächlich veröffentlichten Image-Digests.
- Container-Registry-Veröffentlichung erfolgt nur bei veröffentlichten GitHub Releases und passendem Versionstag.
- Produktions-Secrets bleiben in `.env` beziehungsweise GitHub Environments und niemals im Repository.
## 1.33.0 Multiplatform Deployment Wizard & Flux/Admin Fixes
- Installationsziel-Assistent für Windows lokal, Docker Desktop, NAS/Portainer und VPS/Linux
- neues `setup.sh` für Linux-, NAS- und VPS-Zielsysteme
- Installationsmodus wird für Start, Update, Reparatur, Status und Deinstallation gespeichert
- Docker-Host-Gateway für einen getrennten FLUX/ComfyUI-Dienst
- FLUX Studio startet ohne automatische Bildauswahl
- Reset-Button leert den Arbeitsbereich, ohne Verlauf, Bilder oder Jobs zu löschen
- Benutzerbearbeitung auf stabile Event-Listener und Cachelogik umgestellt
- Passwortvalidierung vor dem Update und sanitisierte Benutzerantwort
## 1.32.0 Docker, NAS & Production Deployment Foundation
- produktionsgeeignetes, mehrstufiges Dockerfile mit Lockfile-Installation
- Compose mit getrennten persistenten Volumes, non-root, read-only und Healthcheck
- zentrale, konfigurierbare DB-/Upload-/Backup-/Operations-/Log-Pfade bei voller Windows-Kompatibilität
- `/readyz` mit SQLite- und Schreibpfadprüfung
- geordneter SIGTERM-/SIGINT-Shutdown mit WAL-Checkpoint
- geschütztes Erst-Admin-Setup über `VENDOO_SETUP_TOKEN`; übrige API bleibt bis zum Setup gesperrt
- konfigurierbare Proxy- und Cookie-Regeln
- produktive Allowlist für Browser-Extension-Origins
- Uploads nur angemeldet abrufbar und strengere Dateitypprüfung
- NAS-, Portainer-, Backup-, Restore-, Update- und Rollback-Dokumentation
- FLUX/ComfyUI bleibt getrennt und ist im Hauptcontainer standardmäßig deaktiviert
## 1.31.0 Mehrbenutzer- und Server-Sicherheitsgrundlage
- Fünf feste Rollen mit serverseitig erzwungenen Berechtigungen: Administrator, Manager, Editor, Publisher und Leser.
- Sichere Sitzungen mit absoluter und inaktiver Laufzeit, Widerruf, Benutzer-Sitzungsverwaltung und Login-Sperre.
- Bearbeitungssperren für Artikel mit automatischer Verlängerung und kontrollierter Freigabe.
- Filterbares und exportierbares Audit-Protokoll.
- Rate Limits, Host-/Origin-Freigaben, Request-IDs, CSP/Helmet und standardmäßige Bindung an localhost.
- Benutzer- und Sicherheitsoberfläche mit Rollenmatrix, aktiven Sperren und Sicherheitsstatus.
- Additive Migrationen; bestehende Artikel, Datenbank, Bilder und Einstellungen bleiben erhalten.
## 1.30.0 Operations Center: Backup, Restore, Updates & Extension-Diagnose
- Neue Betriebszentrale unter Admin → System mit Backup-, Update- und Extension-Diagnose-Tabs.
- Konsistente SQLite-Backups über die Backup-API statt Kopieren der geöffneten Datenbank.
- Vollbackups mit Uploads, optionaler `.env`, Manifest, SHA-256-Dateiprüfsummen und SQLite-Integritätsprüfung.
- Tägliche rotierende automatische Backups mit konfigurierbarer Uhrzeit, Aufbewahrung und Upload-Option.
- Verifizierte Wiederherstellung mit automatischem Sicherheitsbackup und bewusstem Offline-Anwenden.
- Update Center prüft Version, Pflichtdateien und verbotene Laufzeitdaten, bevor ein Paket vorbereitet wird.
- Setup-Menüpunkt 11 wendet vorbereitete Update-/Restore-Operationen an; Menüpunkt 12 führt den Rollback aus.
- Migrationsstatus und letzte Systemoperation sind in der Oberfläche sichtbar.
- Vendoo Link 1.9.0 sendet Diagnose-Heartbeats; Chrome, Edge, Firefox und Safari werden getrennt ausgewertet.
- Keine Datenbank, Uploads, `.env`, API-Schlüssel oder Modelle werden durch ein Update-Paket gelöscht.
## 1.29.0 Slice 34: Publishing Hardening
- plattformübergreifende persistente Publishing-Queue
- Doppelveröffentlichungsschutz und Idempotenzprüfung
- automatische Retry-Strategie und Neustart-Wiederaufnahme
- Fehlerzentrale, Ereignisprotokoll, externe IDs und Links
- eBay Sync, Update und Beenden über offizielle Inventory API
- Etsy Statusabgleich
- Extension-Aufträge für Vinted und Kleinanzeigen
- Scheduler an die gehärtete Queue angebunden
- Vendoo Link 1.8.0
## 1.28.0 Slice 33: Artikel Quality Center
- Neuer Hauptmenüpunkt **Qualitätscenter** mit Score, Noten AE, Blockern, Warnungen und Empfehlungen.
- Serverseitige Prüfung von Titel, Beschreibung, Pflichtfeldern, Preis, Organisation, Suchbegriffen und plattformbezogenen Vendoo-Profilen.
- Vollständige Bildprüfung mit Dateiexistenz, Lesbarkeit, Abmessungen, Format und Auflösungswarnungen.
- Erkennung möglicher Duplikate über gleiche SKU und Titelähnlichkeit.
- Plattformbereitschaft, Gebühren und geschätzter Erlös gemeinsam im Prüfbericht.
- Persistenter Score-Verlauf je Artikel mit Vergleich zur vorherigen Analyse.
- Filter, Suche und Pagination für bereite, blockierte und zu prüfende Artikel.
- AI-Verbesserungen für Titel, Beschreibung und Tags über den aktuell aktiven Text-AI-Provider.
- AI erzeugt ausschließlich Vorschläge; Änderungen werden erst nach sichtbarem Vorher-/Nachher-Vergleich und ausdrücklicher Bestätigung gespeichert.
- Keine automatische Erfindung von Produktmerkmalen, Marken, Schäden oder Lieferumfang.
## 1.27.0 Slice 32: Batch Image Factory
- Neuer Hauptmenüpunkt **Bildproduktion** als persistente Batch Image Factory.
- Mehrere Quellbilder direkt aus der zentralen Bildergalerie auswählen oder aus der Galerie übergeben.
- Acht integrierte Produktionsprofile für eBay, Vinted, Kleinanzeigen, Etsy, Instagram, Webshop und optimierte Originale.
- Eigene Produktionsprofile mit Zielgröße, Anpassung, Hintergrund, Format, Qualität und Dateinamensschema anlegen, bearbeiten und löschen.
- Mehrere Profile pro Auftrag erzeugen mehrere Ausgaben je Originalbild.
- Optionale Hintergrundentfernung mit Intensität sowie Wasserzeichen mit Text, Position und Deckkraft.
- Persistentes Job-Center mit 5/10/15 Aufträgen pro Seite, Pause, Fortsetzen, Abbruch, Gesamt-Retry und Einzel-Retry.
- Neustart-Wiederaufnahme für wartende und laufende Aufträge; pausierte Aufträge bleiben pausiert.
- Ergebnisse werden nicht destruktiv als neue Bildversionen unter `uploads/batch/` gespeichert und erscheinen automatisch in der Bildergalerie.
- Fertige Ergebnisse eines Auftrags können gesammelt als ZIP heruntergeladen werden.
- Bildrenderer um `contain`, `cover`, exakte Ziel-Canvas, Ausgabeordner und kontrollierte Dateinamen erweitert.
## 1.26.1 Stabilitäts-, Responsive- und Regression-Gate
- Zentrale Systemprüfung im Adminbereich ergänzt: SQLite-Integrität, Schreibrechte, UI-Dateien, FLUX-Workflow, Browser-Extensions, AI-Konfiguration und optionale ComfyUI-Erreichbarkeit.
- Öffentlichen, geheimnisfreien `/healthz`-Endpunkt für lokale Verbindungsüberwachung ergänzt.
- API-Client um Request-IDs, definierte Zeitlimits, einmaligen GET-Retry bei Netzwerk-/Serverfehlern und strukturierte Fehlerprotokollierung erweitert.
- Sichtbare Verbindungsleiste bei Serverausfall mit automatischer Wiederholungsprüfung ergänzt.
- Unbehandelte JavaScript- und Promise-Fehler werden lokal mit Build, Seite und Request-ID für die Diagnose erfasst.
- Responsive-Verhalten auf die tatsächlich verfügbare Workspace-Breite umgestellt; `ResizeObserver` vergibt Breitenklassen unabhängig von der Browserbreite.
- Globale Schutzregeln gegen horizontales Überlaufen von Formularen, Bildern, Vorschauen, Werkzeugleisten und langen Inhalten ergänzt.
- Neue statische Release- und UI-Vertragsprüfungen verhindern doppelte IDs, tote Navigation, fehlende Diagnoseelemente und veraltete Buildmarker.
- Keine Datenbankstruktur, Nutzerdaten, API-Schlüssel, Extensions oder FLUX-Modelle verändert.
## 1.26.0 Artikel-Navigation, Publish-Reparatur, Zoom-Galerie & Extension Center
- „Neues Listing“ konsequent in „Neuer Artikel“ und „Listing generieren“ in „Artikel generieren“ umbenannt.
- „Neuer Artikel“ als eigener Hauptmenüpunkt direkt unter dem Dashboard ergänzt; „Listings“ heißt in der Navigation jetzt „Artikel“.
- Publish-Datenaufbereitung gegen fehlerhafte ältere JSON-Felder gehärtet und einen Scope-Fehler im direkten Publish-Workspace behoben.
- Smart Copy öffnet wieder zuverlässig als Popup; die mittlere Publish-Fläche zeigt Titel, Beschreibung, Tags, Metadaten und Fotos.
- Medienvorschau um Fit-, 100-%-, Stufen- und Mausrad-Zoom sowie Verschieben bei Vergrößerung erweitert.
- Galerie-Auswahl und Favoriten auf kleine, konsistente Lucide-basierte SVG-Icons umgestellt.
- Gebührenrechner für private Verkäufer aktualisiert: eBay.de, Vinted und normaler Kleinanzeigen-Privatverkauf ohne Verkäuferprovision; Etsy separat als Shop-Kalkulation.
- Neuer Menüpunkt „Extensions“ mit Browsererkennung, Ein-Klick-Vorbereitung, Pfadkopie und Downloadpaketen für Chrome, Edge, Firefox und Safari.
- Safari-WebExtension-Quelle samt Xcode-Konvertierungsskript ergänzt.
- Doppelte Settings-ID und doppelten Galerie-Event-Listener bereinigt.
## 1.25.1 Adaptive Bildergalerie
- Galerie-Raster vollständig auf automatische Kartenbreiten mit `auto-fit` und Container Queries umgestellt.
- Die gesamte Bildfläche öffnet jetzt die Lightbox; die übergroße Vorschau-/Öffnen-Schaltfläche wurde entfernt.
- Auswahl und Favorit skalieren mit der Kartenbreite und bleiben sauber in den Bildecken ausgerichtet.
- Aktionsleiste auf vier kompakte, adaptive Bildaktionen umgestellt; auf sehr schmalen Karten werden nur Symbole gezeigt.
- Auswahlstatus wird zusätzlich an Karte und Bildfläche sichtbar, ohne das Motiv zu verdecken.
- Seitennavigation mit direkter Seitenauswahl und Bildbereich wird oberhalb und unterhalb der Galerie angezeigt.
- Listenansicht und schmale Bildschirmbreiten wurden im selben Komponentenmodell neu gehärtet.
## 1.25.0 Responsive Detail Editor, Gallery UX, Smart Copy Modal & FLUX Prompt Lab
- Listing-Bearbeiten reagiert jetzt auf die tatsächlich verfügbare Inhaltsbreite per Container Queries und bleibt auch mit Sidebar, Quill, Vorschau und Kontextkarten ohne horizontalen Überlauf bedienbar.
- Die zentrale Bildergalerie erhielt sauber ausgerichtete Auswahlfelder, Favoriten-Overlay, eine eindeutige Vorschauaktion, zweizeilige Titel und ein stabiles 2×2-Aktionsraster.
- Publish-Aktualisieren rotiert nicht mehr; während des Ladens werden ruhige Textzustände und `aria-busy` verwendet.
- Smart Copy öffnet wieder als eigenes responsives Arbeitsfenster mit Kopierfeldern, Fotos, Plattformstart und Veröffentlichungsstatus.
- FLUX Ergebnisse & Favoriten besitzen Pagination mit 5, 10 oder 15 Bildern pro Seite.
- Das FLUX Job-Center ist auf 5, 10 oder 15 Aufträge pro Seite begrenzt.
- Neues FLUX Prompt Lab: lokale Strukturierung oder AI-Veredelung über den aktuell aktiven Claude-, OpenAI-, OpenRouter- oder Ollama-Provider.
- Prompt Lab schützt auf Wunsch Motivmerkmale und vermeidet erfundene Texte, Logos und Wasserzeichen.
- Zusätzliche Breitenhärtung für Publish, Medienbibliothek, FLUX, Einstellungen und Generator.
## 1.24.0 Responsive UI, FLUX-Auftragsarchiv & zentrale Bildergalerie
- Listing-Seite auf schmalen Breiten von einer starren Mindestbreite auf echte responsive Kartenzeilen umgestellt.
- Responsive Härtung für Filter, Batch-Aktionen, FLUX-Job-Center, Formulare, Aktionsleisten und Medienverwaltung ergänzt.
- Hintergrundentfernung im Advanced Editor um eine regelbare Intensität von 0 bis 100 erweitert.
- FLUX-Aufträge können einzeln oder gesammelt archiviert und aus dem Archiv wiederhergestellt werden.
- Im FLUX-Archiv können einzelne, mehrere oder alle Aufträge endgültig gelöscht werden; erzeugte Bilder bleiben erhalten.
- Serverseitige Pagination und Seitengröße für aktive und archivierte FLUX-Aufträge ergänzt.
- Neuer Navigationsbereich „Bilder“ als zentrale Galerie für FLUX-, bearbeitete, AI- und Listing-Bilder.
- Galerie mit Raster-/Listenansicht, Suche, Quellenfiltern, Favoriten, Sortierung, Pagination, Mehrfachauswahl, ZIP-Download, Lightbox, Editor-Übergabe und geschützter Löschung aktiver Listing-Bilder.
- Vinted-Titelfeldschutz aus Vendoo Link 1.6.1 unverändert beibehalten.
## 1.23.2 Slice 31.2 Hotfix: FLUX-Layout, Editor-Werkzeuge & kompakte Aufträge
- „System & ComfyUI“ aus der angehefteten FLUX-Seitenspalte entfernt und direkt unter „Prompt & Auftrag“ eingeordnet.
- FLUX Job-Center als Ganzes ein- und ausklappbar gemacht.
- Einzelne FLUX-Aufträge kompakt auf- und zuklappbar; aktive Aufträge sind standardmäßig geöffnet, abgeschlossene kompakt geschlossen.
- „Alle einklappen“ ergänzt, damit lange Verläufe die Seite nicht unnötig vergrößern.
- Separate Buttons für Hintergrundentfernung und Wasserzeichen aus Generator und Bildleisten entfernt.
- Hintergrundentfernung in den Advanced Image Editor integriert und als nicht destruktive Bildversion gespeichert.
- Wasserzeichen mit eigenem Text, fünf Positionen und einstellbarer Deckkraft in den Advanced Image Editor integriert.
- Editor-Werkzeuge gelten einheitlich für Generator-, Listing- und FLUX-Bilder.
- Vendoo Link 1.6.1 und der Vinted-Titelfeldschutz bleiben unverändert erhalten.
## 1.23.1 Slice 31.1 Hotfix: Editor-Sichtbarkeit & Vinted-Feldschutz
- Advanced Image Editor erhält im Generator einen deutlich sichtbaren eigenen Einstieg.
- `app.js` und `style.css` werden versionsgebunden geladen; HTML/JS/CSS werden vom Vendoo-Server nicht mehr aus veraltetem Browser-Cache ausgeliefert.
- Der Windows-Starter öffnet Vendoo mit Build-Kennung.
- Vinted-Auto-Fill ordnet Felder nur noch über eindeutige Selektoren bzw. tatsächlich zugeordnete Labels zu.
- Zustands-, Marken-, Größen- und Farbauswahl dürfen das Titelfeld nicht mehr als Fallback verwenden.
- Vendoo Link auf Version 1.6.1 angehoben.
# Changelog
## 1.23.0 Slice 31: Advanced Image Editor
- Bestehenden einfachen Fotoeditor durch einen nicht destruktiven Produkt- und FLUX-Bildeditor ersetzt.
- Undo/Redo und eine vollständige Bearbeitungshistorie innerhalb der aktuellen Sitzung ergänzt.
- Persistente Bildversionen in `image_edit_versions` eingeführt; das Original bleibt unverändert und jederzeit wiederherstellbar.
- Vorher-/Nachher-Ansicht und Auswahl älterer Bearbeitungsversionen integriert.
- Freien Zuschnitt sowie 1:1, 4:5, 3:4, 16:9 und Original-Seitenverhältnis ergänzt.
- Drehen, horizontales/vertikales Spiegeln und stufenloses Begradigen umgesetzt.
- Belichtung, Helligkeit, Kontrast, Lichter, Schatten, Temperatur, Sättigung und Schärfe ergänzt.
- Export als JPEG, WebP oder PNG mit Qualitätsregler und Zielgröße umgesetzt.
- Bearbeitungen werden serverseitig mit `sharp` in voller Auflösung gerendert und immer als neue Datei gespeichert.
- Hintergrundentfernung, Inpainting, Outpainting und Maskeneditor bleiben bewusst außerhalb dieses Slices; es gibt keine Platzhalterbuttons.
## 1.22.0 Slice 30: FLUX Studio Pro
- Persistentes FLUX-Job-Center mit SQLite-Aufträgen und einzelnen Varianten eingeführt.
- 1, 2 oder 4 Varianten, eindeutige Seeds und reproduzierbarer Seed Lock ergänzt.
- „Ähnlich erneut erzeugen“, Favoriten und vollständige Prompt-/Parameterhistorie umgesetzt.
- Abbruch, Wiederholen, Queue-Bereinigung und Neustart-Wiederaufnahme ergänzt.
- ComfyUI-Warteschlange, Historie, System-, GPU- und VRAM-Daten angebunden.
- Fortschrittsanzeige des FLUX Studios auf reale Phasen ohne geschätzte Prozentwerte umgestellt.
- Freier FLUX-Promptworkflow bleibt ohne Produktreferenz und ohne `LoadImage`.
- FASHN VTON und Virtual Try-on bleiben vollständig entfernt.
## 1.21.0 Slice 29: FLUX Quality & Settings Tabs
- Einstellungsbereiche als horizontale Top-Tabs neu gestaltet.
- FLUX Studio mit Prompt-Check, lokalem Prompt-Assistenten und Qualitätsprofilen erweitert.
- FLUX.1-schnell standardmäßig auf vier Schritte optimiert; Detailprofil mit sechs Schritten.
- Negative Prompt im reinen FLUX-Promptmodus entfernt.
- Startprofile Auto, Schnell, Ausgewogen und Wenig VRAM ergänzt.
- ComfyUI-Start verwendet je nach Profil Cache-/VRAM- und optionale Fast-Flags.
- Laufzeit und final strukturierter Prompt werden je Bild gespeichert.
- Vorschau und Bearbeitungsaktionen visuell aufgewertet.
## 1.20.1 FLUX Runtime Startdiagnose und Health-Check
- FLUX/ComfyUI-Start wartet jetzt bis zu 180 Sekunden auf den echten `/system_stats`-Health-Check statt nach 2,55 Sekunden vorschnell „gestoppt“ zu melden.
- Eigene Runtime-Statusdatei mit PID, Laufzeit, Startphase sowie bereinigten stdout-/stderr-Auszügen.
- ANSI-Farbcodes werden aus den angezeigten Runtime-Logs entfernt.
- Prozessabbruch während des Starts wird sofort erkannt und mit den letzten relevanten Logzeilen gemeldet.
- Das reine Vendoo-FLUX-Studio startet ComfyUI ohne benutzerdefinierte Nodes; der verwendete Workflow benötigt ausschließlich eingebaute Standard-Nodes.
- Start- und Stopp-Skripte liegen jetzt als feste Paketdateien vor und werden beim Drüberkopieren sofort aktualisiert.
- FLUX Studio und Einstellungen zeigen während des Starts laufend „Wird gestartet“ statt einen falschen Stoppstatus.
## 1.20.0 FASHN/VTO entfernt und eigenständiges FLUX Studio
- FASHN VTON, Modelbibliothek, lokale VTO-Dienste, API-Routen, UI, Installationsskripte und Einstellungen vollständig aus dem aktiven Produkt entfernt.
- Bestehende VTO-Runtime, Autostarts, Logs und alte VTO-Einstellungen werden beim ersten Setup-Lauf entfernt; eigene alte Modelbilder werden nach `uploads/ai-generated/legacy-models` gesichert.
- Neuer Hauptmenüpunkt **FLUX Studio** mit freiem Prompt, Stil, Format, Seed und Schritten.
- Live-Status und Start/Stopp-Steuerung für das lokale ComfyUI/FLUX.
- Vorschau, Download, Bildbibliothek, Löschen und Übernahme in den Listing-Generator.
- Nachträglicher Bildeditor für Zuschneiden, Drehen, Spiegeln, Helligkeit, Kontrast und Sättigung. Bearbeitungen werden als neue Version gespeichert.
- Neue Tabelle `flux_images`; aufgegebene VTO-Tabelle und `ai_vto_*`-Einstellungen werden aus bestehenden Datenbanken entfernt.
- FLUX bleibt ein reiner Prompt-Bildgenerator; Ghost Mannequin und Flatlay bleiben als separate Produktbild-Werkzeuge bestehen.
## [1.15.0] - 2026-07-07
### Neu
- Komplett neu strukturierte Einstellungszentrale mit Bereichen für Allgemein, AI & APIs, Marktplätze und lokales FLUX.
- Großer FLUX-Live-Status mit klarer Anzeige für Aktiv, Gestoppt, Deaktiviert und Nicht installiert.
- Lokales FLUX kann direkt aktiviert, deaktiviert, gestartet, gestoppt, repariert, aktualisiert und sicher deinstalliert werden.
- Sichere FLUX-Deinstallation entfernt ComfyUI und das Modell, behält standardmäßig aber die Installationsarchive für eine schnelle Neuinstallation.
- Einstellbare Produktreferenz-Treue für AI-Model-Fotos.
- Neuer Geschwindigkeitsmodus mit 768 × 768 Pixeln als Standard; 1024 × 1024 bleibt als Qualitätsoption verfügbar.
### Behoben
- Produktfotos werden bei lokalem FLUX jetzt tatsächlich an ComfyUI übertragen und als Image-to-Image-Referenz in den Workflow eingebunden.
- Hoodie, Farbe, Kapuze, Reißverschluss, Aufdrucke, Logos und Schnitt werden im Prompt zusätzlich als verbindliche Produktmerkmale geschützt.
- AI-Bildjobs aktualisieren ihren Fortschritt jetzt während Vorbereitung, Upload, Rendering, Sicherheitsprüfung und Speicherung statt dauerhaft bei 10 % zu stehen.
- Alte oder beschädigte Installationsstatusdateien können nicht mehr zu `unknown · Bereitschaft 100%` führen, wenn die reale Installation vollständig vorhanden ist.
- Der konfigurierte Installationspfad `local-ai/comfyui` wird korrekt auf den enthaltenen Portable-Ordner aufgelöst.
### Technik
- Neue ComfyUI-Referenzpipeline: UploadImage → LoadImage → ImageScale → VAEEncode → KSampler.
- Neue Datenbankspalte `ai_model_jobs.progress_message` als additive Migration.
- BOM-sicheres Lesen des FLUX-Installationsstatus.
- Neuer PowerShell-5.1-kompatibler Uninstaller `scripts/uninstall-local-flux.ps1`.
## [1.14.6] - 2026-07-07
### Behoben
- Lokaler FLUX-Workflow wird unter Windows PowerShell 5.1 als UTF-8 ohne BOM geschrieben.
- Bereits vorhandene Workflow-Dateien mit UTF-8-BOM werden beim Einlesen robust bereinigt.
- `Unexpected token '' ... is not valid JSON` bei der lokalen AI-Bildgenerierung behoben.
- Installer-Status-JSON wird ebenfalls ohne BOM geschrieben, damit Node.js und andere JSON-Parser es zuverlässig lesen können.
# 1.14.5 Slice 22.3 PowerShell 5.1 Parser Fix
- Behebt den PowerShell-5.1-Parserfehler `InvalidVariableReferenceWithDrive` im sichtbaren FLUX-Downloadstatus.
- Ersetzt die beiden ungültigen Zeichenfolgen `$Label:` durch die eindeutig begrenzte Form `${Label}:`.
- Der bestehende Resume-Download, die `.part`-Datei und der automatische Setup-Ablauf bleiben unverändert erhalten.
- Keine Datenbank-, Konfigurations-, Upload- oder Listing-Daten werden verändert.
# 1.14.4 Slice 22.2 Download Recovery
- Fortsetzbarer HTTP-Streaming-Download statt BITS/Invoke-WebRequest.
- Sichtbare Fortschrittsanzeige mit Prozent, MB, Geschwindigkeit und Restzeit.
- Automatische Wiederaufnahme über setup.bat.
# Changelog
## Slice 22.1 / 1.14.3 Setup-integrated PowerShell 5.1 recovery
- Fixed the false 7-Zip failure when `Process.ExitCode` is empty under Windows PowerShell 5.1 despite a successful extraction.
- A missing exit code is accepted only when `Everything is Ok` is present, stderr is empty and the extracted result passes file-count and size checks.
- Complete `local-ai\extract-temp` results are reused instead of being deleted and extracted again.
- `setup.bat` now starts with UTF-8 console handling, `-NoProfile` and explicit exit-code reporting.
- Normal `setup.bat` startup detects the exact confirmed Slice-22 false-failure state and offers automatic continuation.
- Automatic continuation installs ComfyUI, downloads the FLUX.1-schnell model and starts the local image server without a separate patch command.
- Installer intent flags are persisted in `install-state.json` for future resumable runs.
- No reset, database change or feature removal is performed.
## Slice 22 / 1.14.2 7-Zip extraction watchdog and real FLUX install telemetry
- Replaced the blocking 7-Zip invocation with a supervised process and explicit path quoting.
- Live extraction status now includes elapsed time, extracted file count, extracted MB, process ID and heartbeat.
- Added 7-Zip stdout/stderr logs and a visible UI panel for extraction details.
- Detects stalled installers instead of showing an endless running state.
- Reuses complete downloads and safely restarts only the failed extraction/install step.
- Handles nested ComfyUI portable archive layouts more robustly.
- Setup status now shows live extraction counters and stale heartbeat detection.
## Slice 21 FLUX Installer 7-Zip Hotfix & Detailed Status
- Fixed PowerShell 5.1 scalar-string bug where a single 7-Zip path such as `C:\Program Files\7-Zip\7z.exe` was indexed as the single character `C`.
- 7-Zip discovery now uses a real string list, refreshes PATH after winget installation and validates the final executable path.
- Partial ComfyUI and FLUX downloads now use `.part` files and are validated before being promoted to complete files.
- BITS downloads now report actual transfer percentage, bytes transferred and total bytes into `local-ai/install-state.json`.
- Installer failures preserve the last real progress value and include source position plus resumable-state metadata.
- Settings UI now shows detailed checks for 7-Zip, archive, Python runtime, ComfyUI, FLUX model, workflow and start/stop scripts.
- Install log tail, error details, readiness score and a resume-aware install button were added.
- Setup option 8 now prints phase, progress, file checks, runtime reachability and recent install log lines.
## Slice 20 Vollautomatischer lokaler FLUX-Installer
- Automatischer Download der aktuellen offiziellen ComfyUI-Windows-Portable-Version über die GitHub-Releases-API
- GPU-Erkennung für NVIDIA, AMD, Intel und CPU-Fallback
- Automatische 7-Zip-Installation über winget, falls erforderlich
- Optionaler Download von FLUX.1-schnell FP8 aus dem offiziellen Comfy-Org-Hugging-Face-Repository
- Fortschritts- und Statusdatei unter `local-ai/install-state.json`
- Fortsetzbare Downloads über BITS mit WebRequest-Fallback
- Sichere Startparameter: Bindung an `127.0.0.1`, kein Browser-Autostart, eigener Port 8188
- Optionale Windows-Autostart-Aufgabe `Vendoo Local FLUX`
- UI-Aktionen für Installieren, Aktualisieren, Starten, Stoppen und Status prüfen
- Setup-Menü schützt weiterhin vor versehentlicher Neuinstallation von Vendoo und erkennt vorhandene FLUX-Installationen
- Provider-Reihenfolge im Auto-Modus: lokal FLUX → OpenRouter Free → OpenAI
## Slice 19 Local FLUX / ComfyUI Bootstrap, safer setup install flow
- Setup hardened: Install checks whether Vendoo is already installed and suggests Start / Update / Repair instead of blindly reinstalling.
- New setup options: local FLUX / ComfyUI bootstrap and status checks.
- New local image provider architecture for AI model photos: Auto now supports Local FLUX -> OpenRouter Free -> OpenAI.
- New server routes for local image status, bootstrap install and token regeneration.
- Settings UI expanded with local FLUX URL, token, workflow path and install path.
- Added local workflow bootstrap template and helper scripts under `scripts/` and `local-ai/workflows/`.
## Vendoo 1.12.0 OpenRouter Diagnostics & Mobile Mediathek
- Mobiler QR-Upload besitzt jetzt getrennte Aktionen für **Kamera** und **Mediathek**
- Mehrfachauswahl aus der Smartphone-Mediathek ohne `capture`-Zwang
- HEIC/HEIF werden beim mobilen Upload nach Möglichkeit automatisch in JPG konvertiert
- OpenRouter-Free-Erkennung bewertet nur bildrelevante Preisfelder
- OpenRouter versucht je Modell mehrere kompatible Chat-Request-Varianten und danach die Images API
- Referenzbilder werden nur an Modelle gesendet, die Bildinput unterstützen
- Klare Diagnose, wenn aktuell **0 kostenlose Bildmodelle** verfügbar sind
- Bei Fehlern werden weiterhin alle passenden Free-Modelle nacheinander versucht; Auto fällt anschließend auf OpenAI zurück
## Vendoo 1.11.0 LAN QR Upload, OpenRouter Fallback & Mobile Nav Fix
- QR-Handy-Upload verwendet automatisch eine erreichbare LAN-IP statt localhost
- Vendoo lauscht für lokale Netzwerkzugriffe auf `0.0.0.0` und zeigt erkannte LAN-Adressen beim Start an
- Neue Einstellung für `PUBLIC_BASE_URL` inklusive automatischer LAN-IP-Erkennung
- OpenRouter probiert bei Fehlern automatisch weitere passende Free-Bildmodelle und danach im Auto-Modus OpenAI
- OpenRouter-Bildgenerierung unterstützt Chat-Completions und Images-API als zweistufigen Fallback
- Mobile Navigation vollständig gehärtet: Overlay, Close-Button, Fokus, Escape, Scroll-Lock und responsive Labels
## Vendoo 1.10.0 AI Jobs, 13 Varianten & History
- AI-Bildgenerierung läuft jetzt über eine Job-Queue statt nur synchron
- Mindestanzahl auf **1 Bild** gesenkt, Maximum bleibt **3 Bilder**
- Neue Modi: **Model**, **Ghost Mannequin**, **Flatlay**
- Listing-Editor zeigt jetzt eine **AI-Bild-Historie** zum schnellen Übernehmen früherer Generierungen
- Settings erweitert um Standard-Modus für AI-Bilder
## Vendoo 1.9.0 AI Provider Settings Center
- Neuer Settings-Bereich für AI-Model-Fotos mit Provider-Steuerung
- Admin kann jetzt `auto`, `openrouter` oder `openai` für Bildgenerierung wählen
- OpenRouter-Free-Modelle können direkt aus der UI geladen und geprüft werden
- Safety-Flags, Standard-Preset, Variantenanzahl und Fallback-Modell sind in der UI konfigurierbar
## Vendoo 1.8.0 OpenRouter Free Image Discovery
- AI-Model-Fotos unterstützen jetzt einen Provider-Modus `auto`
- OpenRouter Free-Bildmodelle werden dynamisch über die Models-API abgefragt und bei Verfügbarkeit bevorzugt genutzt
- Fallback auf OpenAI (`gpt-image-1` oder konfiguriertes Modell), wenn keine freien OpenRouter-Modelle verfügbar sind
- Neue API-Route für verfügbare OpenRouter-Bildmodelle sowie Persistenz von Provider und Modell je Generierung
## Vendoo 1.7.0 AI-Model-Fotos & Safety Layer
- Neuer sicherer AI-Model-Foto-Workflow für Kleidung ohne Person auf dem Originalfoto
- 23 KI-generierte Zusatzbilder mit fiktiven erwachsenen Models in Studio-, Indoor- oder Outdoor-Looks
- Precheck & Output-Safety: blockiert Unterwäsche, Bademode, transparente Erotik-Looks, Kinderkleidung und Quellen mit Personen
- Neue Backend-Routen, Datenbanktabellen und Listing-Integration für Generator und Detailansicht
# Changelog
## [Unreleased]
## [1.6.2] - 2026-07-07
### Branding
- neues Vendoo-Hauptlogo in die App-Sidebar integriert
- neues Branding auf Login und mobilem QR-Fotoupload integriert
- vollständiges Favicon-Paket mit ICO, PNG, Apple Touch Icon und Webmanifest eingebunden
- mobile App-Icon-Größen von 16 bis 512 Pixel ergänzt
- Chrome-, Edge- und Firefox-Erweiterungen auf die neue Vendoo-Icon-Familie aktualisiert
- Vinted Assistant und minimierter Assistant verwenden das neue Logo
## [1.6.1] - 2026-07-07
### Verbessert
- Dashboard ist jetzt der erste Menüpunkt und die Standard-Startseite.
- Dashboard-KPI-Karten verwenden eine fließende Auto-Fit-Struktur statt starrer Sechserspalten.
- Sparklines besitzen eine reservierte Diagrammfläche und überlagern keine Texte mehr.
- Umsatzdiagramme werden bei Größenänderungen automatisch neu berechnet.
- Dashboard-Charts passen sich an Notebook-, Tablet- und Mobilbreiten an.
- Studio-Flow-Karten verwenden proportionale Bildflächen mit vollständiger `contain`-Darstellung.
- Produktbilder werden nicht mehr abgeschnitten und erhalten einen sauberen Fehlerzustand.
- Ready-Karten verteilen sich automatisch auf die verfügbare Breite.
## [1.6.0] - 2026-07-07
### Hinzugefügt
- neuer Sidebar-Menüpunkt **Dashboard** mit interaktiven Kennzahlen, Umsatzverlauf, Plattform- und Kategorieauswertung
- Dashboard-Bereiche für Fokusaufgaben, Top Seller, Aktivität, Benachrichtigungen, AI-Qualität und Systemstatus
- Fotoarchiv-Endpunkt: mehrere Fotos werden serverseitig als gültiges ZIP erzeugt
- Foto-Download im Generator und vollständigen Listing-Editor
### Geändert
- Studio Flow vollständig neu strukturiert: Bereit, Geplant, Veröffentlicht, Verkauft und Benötigt Aufmerksamkeit
- die fachlich unpassenden sichtbaren Stufen „Neu erfasst“ und „AI-Prüfung“ wurden entfernt
- Studio Flow zeigt nur priorisierte Artikel statt einer überfüllten Spaltenwand
- geplante Listings, Probleme und Aktivitäten sind in klar getrennten Arbeitsbereichen organisiert
- Dashboard und Studio Flow für Notebook, iPad, Tablet und Smartphone neu priorisiert
### Behoben
- Publish-Center lädt Listings beim ersten Öffnen mit Wiederholungslogik und verhindert veraltete parallele Renderings
- Publish-Ladefehler zeigt jetzt eine konkrete Wiederholen-Aktion statt einer Sackgasse
- bei einem Foto erfolgt ein normaler Download, bei mehreren Fotos automatisch ein ZIP-Download
## [1.5.0] - 2026-07-07
### Hinzugefügt
- Browser-Erweiterungen in getrennten Ordnern für Chrome, Edge und Firefox
- vollständiger Design-Relaunch von Popup und Vinted Assistant
- neues Vendoo-Link-Icon in 16, 32, 48 und 128 Pixel
- QR-basierter Handy-Fotoupload für Generator und Listing-Editor
- sichere, zeitlich begrenzte Mobile-Upload-Sitzungen
- responsive Layout-Gates für Desktop, Notebook, iPad und Smartphone
- umschaltbare Plattformvorschau und HTML-Codeansicht
### Verbessert
- Produktbilder der Extension werden vollständig dargestellt
- CSRF-Unterstützung für schreibende Extension-Requests
- öffentliche Serveradresse statt festem localhost für Extension-Bilder
- Plattformvorschau und HTML-Code sind in Generator und Listing-Editor als Umschalter zusammengeführt
- Layouts für Desktop, Notebook, iPad und Smartphone neu priorisiert
- freigegebene Extension- und Icon-Mockups als verbindliche Designreferenz archiviert
### Behoben
- Studio Flow: „Prüfen & bearbeiten“ wechselt jetzt zuverlässig zur sichtbaren Listing-Detailansicht.
- Detailaufrufe aus Attention Queue und anderen Bereichen verwenden denselben sicheren Navigationspfad.
- Ungültige Listing-IDs werden abgefangen und als Hinweis angezeigt.
- Windows-Installer behandelt npm `ENOTEMPTY`/`EPERM` robust, bereinigt unvollstaendige `node_modules`, protokolliert npm-Ausgaben und wiederholt die Installation einmal.
- Installation nutzt mit vorhandenem Lockfile reproduzierbar `npm ci` statt eines stillen `npm install`.
### Geplant
- Lager, Vorlagen, Einstellungen und Admin gemäß Design-Freeze
- Docker- und Online-Readiness
## [1.4.0-full-listing-editor] - 2026-07-07
### Hinzugefügt
- Listings lassen sich jetzt vollständig in einem eigenen Arbeitsbereich bearbeiten
- Fotoverwaltung mit Hinzufügen, Entfernen, Cover-Auswahl, Drag-to-Sort und vollständigem Bildeditor ergänzt
- WYSIWYG-Editor und HTML-Code sind im Listing-Editor bidirektional und live synchronisiert
- Generator zeigt HTML-Code und Plattformvorschau gleichzeitig; Änderungen werden ohne Umschalten übernommen
- Plattform-HTML wird während der Bearbeitung live neu gerendert
- neue Datenbankspalte `description_html` mit Migration und Rückwärtskompatibilität
- neuer API-Endpunkt `POST /api/html-render` für nicht persistierende Live-Vorschauen
- Editor-HTML und vollständiges Plattform-HTML können getrennt kopiert werden
### Sicherheit
- Rich-Text-HTML wird client- und serverseitig auf eine begrenzte Tag- und Attributmenge reduziert
- Plattformvorschauen laufen in sandboxed iframes
- Listing-Updates verwenden jetzt eine feste Feld-Allowlist statt beliebiger SQL-Spaltennamen
### Behoben
- `photos` werden bei Listing-Updates korrekt als JSON gespeichert
- Bildbearbeitung funktioniert nun auch für bereits gespeicherte Listings
- formatierte Beschreibungen bleiben nach Speichern und erneutem Öffnen erhalten
## [1.3.0-publish-center] - 2026-07-07
### Geändert
- Publish-Bereich als durchgängiges operatives Publish-Center neu aufgebaut
- Smart Copy, Direkt-Publishing, eBay Queue und Zeitplanung in einer gemeinsamen Oberfläche zusammengeführt
- bildorientierte Listing-Auswahl mit Suche, Plattform-/Statusfilter, Sortierung und Mehrfachauswahl ergänzt
- internes Workspace-Modell statt separater Queue- und Smart-Copy-Modale eingeführt
- direkte Listing-Bearbeitung vor Etsy-/eBay-Veröffentlichung integriert
- Publish-Bereitschaft, Pflichtfelder, Integrationsstatus und Fotoprüfung sichtbar gemacht
- Queue-Status, Schnellaktionen und Publish-Aktivität in einer festen Statusleiste gebündelt
- eBay-Fehler, Wiederholungen und geplante Veröffentlichungen inline bedienbar gemacht
- responsive Darstellung und Dark Mode für das komplette Publish-Center ergänzt
### Behoben
- Batch-Smart-Copy öffnete denselben Vorgang teilweise doppelt
- nicht passende Etsy-Batch-Auswahl wird jetzt gefiltert statt blind veröffentlicht
- Produktbilder im Publish-Center werden vollständig und ohne Beschnitt dargestellt
- Queue- und Planungsaktionen bleiben im Vendoo-Kontext und verlieren nicht den aktuellen Arbeitsstand
## [1.2.0-listing-studio] - 2026-07-07
### Geändert
- Listing-Generator als dreigeteilter Studio-Arbeitsplatz neu aufgebaut
- Foto-Cover, Sortierung, Qualitätscheck und vollständige Bildanpassung integriert
- AI-Konfiguration mit Plattform, Provider, Modell, Sprache, Varianten und Vorlagen neu strukturiert
- artikelspezifische Verkäufernotizen mit Zeichenzähler ergänzt
- Ergebnisbereich mit Live-Zählern, Qualitätswert, Attributen, Gebühren und HTML-Vorschau modernisiert
- responsive Darstellung und Dark Mode für den Generator vollständig ergänzt
### API
- `POST /api/generate` akzeptiert `template_id` und `seller_notes`
- globale Hinweise, Vorlagenhinweise und Artikelhinweise werden dedupliziert kombiniert
- Standard-Tags aus Vorlagen werden mit AI-Tags zusammengeführt
### Behoben
- Upload begrenzt neue Bilder clientseitig auf die verbleibenden Plätze bis maximal zehn
- Upload-Fehler werden mit HTTP-Status und Servermeldung korrekt angezeigt
- Dateinamen in Vorschaubildern werden URL-sicher ausgegeben
## [1.0.1-ui-foundation.1] - 2026-07-07
### Hinzugefügt
- zentrale Vendoo-Design-Tokens für Light und Dark Mode
- neue kompakte App-Shell und Hauptnavigation
- Command-Search-Einstieg mit `Ctrl/⌘ + K`
- neue Startseite `Studio Flow`
- Flow-Stufen: Neu erfasst, AI-Prüfung, Bereit, Geplant, Veröffentlicht, Verkauft
- Attention Queue und Activity Stream
- kontextueller Artikel-Inspector
- neuer Endpunkt `GET /api/dashboard/workflow`
- Dokumentation `docs/UI_FOUNDATION_2026.md`
- sicherer `.gitignore`
### Sicherheit
- `.env`, SQLite-Laufzeitdateien, Uploads und `node_modules` aus dem Übergabepaket entfernt
- keine produktiven Zugangsdaten in der bereinigten Version
## [1.1.1-ui-polish] - 2026-07-07
### Geändert
- Etiketten und Artikeldatenblätter öffnen jetzt im internen Vendoo Print Studio statt in einem neuen Browserfenster
- maßstabsgetreue A4-Vorschau mit zwei Etikettenformaten, Exemplaren und Preisoption
- Druck erfolgt im aktuellen Vendoo-Fenster über den normalen Systemdruckdialog
- Studio-Flow-Produktbilder verwenden vollständige automatische Anpassung (`object-fit: contain`)
- Inspector- und Attention-Bilder werden ebenfalls ohne Beschnitt dargestellt
- Vinted-Extension auf die freigegebene Vendoo-Designsprache 2026 umgestellt
- Extension-Popup und eingeblendetes Vinted-Panel modernisiert
- Produktbilder der Extension werden sicher über den Background-Service-Worker als Data-URL geladen
- Pfade von Upload-Bildern werden korrekt URL-codiert und Bildfehler erhalten einen sichtbaren Zustand
- fehlerhaft doppelt codierte deutsche Texte in der Extension repariert
### Behoben
- Produktvorschaubilder in der Vinted-Extension wurden durch Seiten-CSP/Mixed-Content-Konstellationen teilweise nicht angezeigt
- große oder hochformatige Produktbilder wurden im Studio Flow abgeschnitten
## [1.1.0-ui-listings] - 2026-07-07
### Geändert
- Listings-/Historie-Seite vollständig an die freigegebene Vendoo-Designrichtung 2026 angepasst
- neue Filterleiste mit Suche, Plattform, Status und Zeitraum
- benutzerdefinierbare sichtbare Tabellenspalten mit lokaler Speicherung
- dichte, bildorientierte Listing-Tabelle mit SKU, Plattform, AI-Provider, Preis, Status, Lagerort und Publish-Status
- neue Batch-Aktionsleiste für Publish, Nachbearbeitung, Preis, Status, Duplizieren, Etiketten und Löschen
- moderne Seitennavigation und Seitengrößensteuerung
- neue Exportauswahl für CSV und JSON
- verbesserter leerer Zustand und responsive Darstellung
- bestehende CRUD-, Export-, Druck-, Status- und Papierkorb-Funktionen erhalten
## [1.6.1] - 2026-07-07
### Geändert
- Vendoo Assistant für Chrome, Edge und Firefox vollständig verdichtet und visuell neu strukturiert.
- Queue-Karten zeigen Bild, Status, SKU, Preis und direkte Aktionen ohne große Leerflächen.
- „Nur ausfüllen“ ist jetzt die primäre und sichere Einzelaktion.
- Daten können in Vinted eingetragen werden, ohne automatisch einen Entwurf anzulegen oder zu veröffentlichen.
- „Daten + Bilder ausfüllen“ überträgt Bilder und Felder, führt aber keinen Abschluss aus.
- Entwurf und Veröffentlichung liegen bewusst in einem getrennten, aufklappbaren Abschlussbereich.
- Popup öffnet Vinted mit einem vorgemerkten Listing und füllt es nach dem Laden aus.
- Extension-Version auf 1.4.0 angehoben.
@@ -0,0 +1,96 @@
# Vendoo — Projekt-Kontext
Du arbeitest am Projekt "Vendoo" — ein lokaler Multi-Plattform Listing-Generator mit AI, Lagerverwaltung und Publishing-System.
Lies zuerst `FEATURES.md` im Projektroot — das ist die vollstaendige Feature-Dokumentation mit Tech Stack, Projektstruktur, DB-Schema, allen 80+ API-Endpunkten und 17 Feature-Beschreibungen.
## Tech Stack
- **Backend:** Node.js + Express (ESM, `"type": "module"`)
- **Frontend:** Vanilla HTML/CSS/JS — kein Framework, kein Build-Step, kein TypeScript
- **Datenbank:** SQLite via `better-sqlite3` (WAL-Modus)
- **AI:** Anthropic Claude, OpenAI, OpenRouter, Ollama (lokal)
- **Bilder:** `sharp` (Resize, BG-Remove, Watermark)
- **Rich-Text:** Quill Editor
- **E-Mail:** Nodemailer (SMTP)
- **Extension:** Chrome Manifest v3
## Dateistruktur (wo was hingehoert)
| Aenderung | Datei(en) |
|---|---|
| Neue API-Route | `server.mjs` — Route hinzufuegen + Import erweitern |
| Neue DB-Funktion | `lib/db.mjs` — Funktion exportieren |
| Neue DB-Spalte | `lib/db.mjs` — MIGRATIONS-Array erweitern (try/catch ALTER TABLE Pattern) |
| Neues UI-Tab | `public/index.html` (Sidebar-Button + Section), `public/app.js` (TAB_TITLES + switchToTab + Logik), `public/style.css` |
| Neuer AI-Provider | `lib/ai-*.mjs` + `lib/ai-router.mjs` erweitern |
| Neue Plattform | `platforms/*.mjs` + `lib/categories.mjs` + `lib/fees.mjs` + `lib/html-templates.mjs` |
| Styling | `public/style.css` — CSS Custom Properties fuer Theming |
## Konventionen
- **Sprache:** UI ist komplett Deutsch
- **SKU-Format:** `VD-XXXX` (auto-generiert, 4-stellig aufsteigend)
- **Navigation:** Sidebar mit `data-tab` Attributen, Tab-Inhalte als `<section id="..." class="tab-content">`
- **Topbar-Titel:** `TAB_TITLES` Map in `app.js` muss fuer neue Tabs erweitert werden
- **Dark Mode:** CSS-Variablen unter `[data-theme="dark"]`, niemals hardcoded Farben
- **Auth:** Session-basiert, Rollen `admin`/`editor`, CSRF-Token bei state-changing Requests
- **DB-Migrationen:** Neue Spalten als Eintrag in `MIGRATIONS`-Array (Zeile ~17-21 in db.mjs):
```js
const MIGRATIONS = [
['spaltenname', 'TEXT'], // oder 'REAL', "TEXT DEFAULT 'wert'"
];
// Wird automatisch per try/catch ALTER TABLE ausgefuehrt
```
- **API-Pattern:** REST, JSON-Body, Fehler als `{ error: 'message' }`
- **Frontend-API-Aufrufe:** `api(method, path, body)` Helper in app.js (fuegt Auth + CSRF automatisch hinzu)
- **Toast-Benachrichtigungen:** `toast('Nachricht')` in app.js
- **Quill-Editor:** `initQuill(selector, placeholder)` — gibt Editor-Instanz zurueck
## Server starten
```bash
npm install # Dependencies installieren
npm run dev # Dev-Server mit --watch (Port 8124)
npm start # Produktiv-Server
```
Oder: `setup.bat` fuer gefuehrte Installation.
## Wichtige Dateien nach Groesse
| Datei | Zeilen | Inhalt |
|---|---|---|
| `public/app.js` | ~3240 | Gesamte Frontend-Logik |
| `server.mjs` | ~1250 | Alle API-Routen + Middleware |
| `public/style.css` | ~1200 | Komplettes Styling + Dark Mode + Responsive |
| `public/index.html` | ~845 | HTML-Struktur (Sidebar, Tabs, Modals, Forms) |
| `lib/db.mjs` | ~390 | Datenbank-Zugriff (alle CRUD-Funktionen) |
| `lib/categories.mjs` | ~360 | Kategorie-Baeume pro Plattform |
| `lib/auth.mjs` | ~290 | Auth-System (Users, Sessions, Audit) |
| `lib/ebay-api.mjs` | ~270 | eBay REST API + OAuth2 |
| `lib/mailer.mjs` | ~210 | SMTP E-Mail-Versand |
| `lib/etsy-api.mjs` | ~185 | Etsy REST API v3 + OAuth2 PKCE |
| `extension/content.js` | ~1170 | Chrome Extension Content Script |
## Aktueller UI-Stand
- Version `1.3.0`
- UI 2026 Slice 05: Publish-Center
- Smart Copy, direkte Veröffentlichung, eBay Queue und Scheduling arbeiten in einer gemeinsamen Oberfläche.
- Interne Publish-Arbeitsschritte dürfen keine separaten Browserfenster oder redundanten Modale öffnen.
## Bildarchitektur ab 1.23.0
- FLUX/ComfyUI ist der einzige lokale generative Bilddienst.
- Das FLUX Studio arbeitet textbasiert und getrennt von Produktbild-Werkzeugen.
- Keine VTO-, Python-, Torch- oder ONNX-Laufzeit wieder einführen, solange kein neuer ausdrücklicher Architekturentscheid dokumentiert ist.
- FLUX-Studio-Aufträge und Varianten sind in `flux_prompt_jobs` und `flux_prompt_job_variants` persistent.
- Fortschritt im FLUX Studio wird als reale Phase dargestellt; keine aus Laufzeit geschätzten Prozentwerte ergänzen.
- ComfyUI-Prompt-IDs müssen für Abbruch, Historie und Neustart-Wiederaufnahme erhalten bleiben.
- Der Advanced Image Editor arbeitet nicht destruktiv: Originaldateien niemals überschreiben oder löschen.
- Jede gespeicherte Bearbeitung muss eine neue Datei und einen Eintrag in `image_edit_versions` erzeugen.
- Bildpfade müssen strikt auf `uploads/` begrenzt und gegen Traversal geschützt bleiben.
- Hintergrundentfernung, Inpainting, Outpainting und Maskeneditor nicht als Platzhalter ergänzen; diese Funktionen benötigen eigene spätere Slices.
@@ -0,0 +1,33 @@
# syntax=docker/dockerfile:1.7
FROM node:22-bookworm-slim AS dependencies
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 make g++ ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY package.json package-lock.json .npmrc ./
RUN npm ci --omit=dev --no-audit --no-fund \
&& npm cache clean --force
FROM node:22-bookworm-slim AS runtime
ENV NODE_ENV=production \
PORT=8124 \
VENDOO_BIND_HOST=0.0.0.0 \
VENDOO_DATA_DIR=/app/data \
VENDOO_DB_PATH=/app/data/db/vendoo.db \
VENDOO_UPLOADS_DIR=/app/data/uploads \
VENDOO_BACKUP_DIR=/app/data/backups \
VENDOO_OPERATIONS_DIR=/app/data/operations \
VENDOO_LOG_DIR=/app/data/logs \
VENDOO_CONFIG_PATH=/app/data/config/vendoo.env
WORKDIR /app
COPY --from=dependencies --chown=node:node /app/node_modules ./node_modules
COPY --chown=node:node . .
RUN mkdir -p /app/data/db /app/data/uploads /app/data/backups /app/data/operations /app/data/logs /app/data/config \
&& chown -R node:node /app/data \
&& chmod +x /app/scripts/docker-entrypoint.sh
USER node
EXPOSE 8124
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:8124/readyz').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
CMD ["node", "bootstrap.mjs"]
@@ -0,0 +1,481 @@
f344f75df655bc133e6c4abb2d215b2234fb22a4bb155c217317c36ee4f0f8fb .dockerignore
e5cc1e85c80485ceda76fd6c69330e085ccc7bc1248be810fe4243712cf39118 .env.example
58e3f4b76cc9398f32dcd5481b2080e7e5ba322aca04b8b8374446299c5d7dd6 .github/CODEOWNERS
5bd335eb750d084ca12b6a3b3f35d0cd7bc454ba24ed280187c66acf75eaf396 .github/dependabot.yml
f65684e98b01d0e0b6bfe1284b5de3354559e4cd51e634fe9e9e2e5473b890e5 .github/pull_request_template.md
0127f541bd7a0a3373899750ba07588d057801dc65ff99875184e1268cfc5bcc .github/workflows/ci.yml
21063fe4a8712751c469ad7d7e543bb03eeb771b1bd8cacabdf3f9bd45163bdb .github/workflows/release.yml
5d19d5bdbfea6de033a8086d2689dd705a34b55ffbe5b873a097d6b322ced4fe .gitignore
9bfa732952ad571d06527b32d96d79133fc23fa607df00de440b2802f543608c .npmrc
9d7c2a587c12f2b12ba2923e367ade8cdd4601dcac800ca2ac34afb302e9a6e1 app/architecture-boundaries.json
a6bdb9b6fdc97a0b2bbc052bd242a9885a75bcc46ee4f0414d8b7e215b6940de app/contracts/module.schema.json
67fcafb51d5d17a83a04e55ecf877c8d9ac928d11a1951d0395f137ca6913401 app/core/identity/identity-store.mjs
7cf2224714a10e337b4e8e6514de56d61200d27632440ce85c2ba20ccd7e9d7f app/core/modules/module-package-contract.mjs
1ac6208b0cc85a3b5e2f86d61bb59a7a39fd46f51b4d8278c2abe236b53fdab5 app/core/modules/module-package-store.mjs
8ccc5ab62329fcadc8bf42d0e9dc2bca967602295c677e027dd2d363d09f94f6 app/core/modules/module-state-store.mjs
918cddaee5056cadddcff39d86744cf68ab409fbff46aa54b6b465b72b199c01 app/core/security/secret-contract.mjs
7f38b3ac792e61e030c9f69355e2378f8f61e8e61c7b29c82cd0fa7ec930cfec app/core/themes/theme-contract.mjs
d84a573699e413e0a0803459e0d05c5c4e6e35d3499eb634f95302d151e75c4b app/kernel/errors.mjs
a34333cbc784d39b39a8071a437972c6175c551104dc2d82fc4c0e0506b18259 app/kernel/event-bus.mjs
0e8f691f96e1ef0a7a86d32cae7b7e1db04325fe94a32b8c1f484a5b6950f3b4 app/kernel/feature-flags.mjs
a4877c90f2c9040cb101b7fbb80385d4b1ea0814118a104873b891a580e88204 app/kernel/input-schema.mjs
a0223a00691908862aaf1fd9383b6d86d67f26325c509280b8c2daa5cfcee28e app/kernel/lifecycle.mjs
ba1f4f799a508ff113738cce7ac9f5af27739cb60d7f04d7a6c5878de3c5b7f4 app/kernel/module-contract.mjs
d6efcd98ad26c1a822850de4b717539e5e5472b5ba379df7320f0e1ab6900163 app/kernel/module-registry.mjs
3955b63ce7a17432bb70e7c6afb490f99639f70ded0c059875b87adfe1ab5e40 app/kernel/platform-kernel.mjs
7944f68d995a5d70273f8a985973f668fc62a414d85636d92f3774e34d39a37f app/kernel/policy-engine.mjs
f98e4cd58b051efdf311dafa73569b1ecebe2a29431cd763380c9663035c1c2b app/kernel/route-registry.mjs
0ff879fb8cf392a3786c39f2541637b2d9f018fb03941066ed540a2880134f89 app/modules/ai/index.mjs
98e93589109cb34c7af71215a581fe40e80691884459c2d42260f6b001065e6e app/modules/ai/module.json
3ae563b7e6232ed89f5bc5dc49fe359ecfd696123aee2cb780032040c53f149e app/modules/auth/index.mjs
cae01362c58adac32badb0b102ce76a748c7301aafa64818a49456665b4de29d app/modules/auth/module.json
04a72689ecea04caf79eec9207116d1da374600150fe1966032fe972736f246f app/modules/auth/routes.mjs
53917fe8aa4832cc62f35d4746af9bfdfd1132448de0ca750f073a0a27cdbebb app/modules/auth/service.mjs
2b3e4d7d5acdbbe5c92e2dc4f94d5a783b97111852ac705b494d744d878ba318 app/modules/catalog.mjs
99bde2c2871c48ff9e1d2895157197d9f1d5e194072a481abaa3495daaa683e0 app/modules/flux-studio/index.mjs
5f28a104ef923c0f01cf71d765cb603e3c9bf7a30d087321f58161d701896024 app/modules/flux-studio/module.json
fd798d294308dcb50d5ce90d3cfb969800cd1dfecf4805e69ec41f974e268829 app/modules/inventory/index.mjs
febca770c3ee71c398bec9e6afc3aaaa8850ce8c9a2840c190d93b2e8d25f790 app/modules/inventory/module.json
6925da30bd453695b82c8fcbc82c585b01cda71c410f59d62697a31c364954ae app/modules/inventory/repository.mjs
b3d0c8a4643ff09091d48c4e1dfcd90ed0884fe9713a7bb44160c34761b59590 app/modules/inventory/routes.mjs
94f3e5a3e6f3ed1120dad7c869b47978582717e231b57ae4c98e668d903f09bc app/modules/inventory/service.mjs
fbf8db46e0ae7b483f898588c39a4f74d72717588d93d2058ab9250f9ada0c88 app/modules/listings/index.mjs
79b21e2387b59eec5a23b3d547d954ddc1edf99e9ab691f6e410894811f1978c app/modules/listings/module.json
a76054a2eca06d8412c211fc8b75f7fbd9cb1ed256f38360a7031b1f8ed7d73c app/modules/listings/repository.mjs
d1e817f0c4251994bad0a7084e2e7dcd2873a0a099cb00a312f55aa2163c183d app/modules/listings/routes.mjs
e7c722e449284d8ec9ade461e2b8fc94723e35ebec25c51113b40643d12f28ef app/modules/listings/service.mjs
e12663a5b189660e34d72e034fa4b23b5bffdb0c8d5516b547020da11e70aefa app/modules/media/index.mjs
4efc183346859a6786250d40a9762f7457e00f659a7b2408209d85f3ef75d1c2 app/modules/media/module.json
67262d67fa85e5f2e09a51645432a2c7548a6dccdb0afbaaf63850e2fab67197 app/modules/media/repository.mjs
9f8e54cabbb7271bac7253a26b6ffbf553f834147500141c9e7427a26c9dde81 app/modules/media/routes.mjs
29a4e515e6ccc692b9cac78012e9571c4d6225f7e89bee2d4fefaf63f4d0fc3a app/modules/media/service.mjs
9d2afb4ba28a144b7f75c6c409f43d2f7a34f2674c8a1f717c2ab631516b0cca app/modules/module-manager/index.mjs
c4ab8673081ba03068cc5c76c1a0ea35c61771ad69de97cd1510dfc35f9bd93a app/modules/module-manager/module.json
b4250e7028bc1ff041166f4099a05e71fd4e0f71abaeee09ffdd3678ce9c52c7 app/modules/module-manager/routes.mjs
0ffb748b960653501c1bafcc660d7d604e9c5f7a323400d8bb024db5ea712356 app/modules/module-manager/service.mjs
9723a9b12a9b472b2ed8c4635cdce663b2f0f65643d8ae0b6219715d853f740d app/modules/operations/module.json
8a2805286def5d0521765319eddcd44e680e32bd7065d45749edd31406228463 app/modules/publishing/index.mjs
53e1dcab6bb9c5046eba6daa17c0f1ffb193bed38ae248dd1702fee91bdd23bd app/modules/publishing/module.json
306a2c3c119b82f6f972fa503099705bd3ede6c2061f532a00dc208f0584445c app/modules/quality/index.mjs
61381a51b86b64d59dde8c1a749ae46b7990ec323adc71c7eb62f741eeb6f807 app/modules/quality/module.json
747febc12aec7d81ccfdf6e9ea7158655ef5fdc536c519ce447de329314612a8 app/modules/security/index.mjs
700be862cd70be6947919c1e1f0e25e7e88c313b1fcdddc104d54d88a74edbb2 app/modules/security/module.json
08a6015cd3588f08070d341ad8cc5c9be8e34d217cf8770e154d4571225b3e2e app/modules/sessions/index.mjs
da856dca2a4e2533a8a224806ccf10f792ed46e8266505a27339cf27e8a1edda app/modules/sessions/module.json
c2ed5ccf36a0c5398f3113cd79172bed917dfb6c9668f025e806e38d74f8c83b app/modules/sessions/routes.mjs
a33995a82e02beaaa820bebc2875d14d684b1d4baeeb79d27dc7237c899f3249 app/modules/sessions/service.mjs
edc35b82678ef00e24fc6cb6a6d135bbca9acc980a17e59b15ba90b0a79490de app/modules/settings/index.mjs
c1bdee45bd8ec80715e74d3e92ea238cd3e47a6e54fda4c5959a6de51d9d5163 app/modules/settings/module.json
7b7ed59760da0338037b2d5038a9b422a62b4a818c62a74216d2fce215ac6490 app/modules/settings/repository.mjs
3717914c11da56a54dd0a22d139830a064f4c842c0f718517570470ecb9ed551 app/modules/settings/routes.mjs
07dcb652661f9c879877a5d0033f4388584b2c3a2eef58488c88cd7c5cadd78e app/modules/settings/service.mjs
452a5262c418b393bdd8754fe90f9ea14edf61338f8dcfd6438f0852920f608c app/modules/system/module.json
92d968c993ee5a2afc14df557b7cba552cae9a41722989007eb0b784514333ff app/modules/themes/index.mjs
1e062db871f9bf13b487c972f6cd4dd9cfe1b3046cd9b53ed43e0a0babc9d285 app/modules/themes/migrations/001_theme_profiles.sql
2af572390890e4d793aea9c1356c835917655c225a7848325d5a7c5ae3c08a09 app/modules/themes/module.json
3c3dc5974976672cd0e9141867a8a1d78a0dfaa54582bafb8f360bea571bf11a app/modules/themes/repository.mjs
4e2c348a184384739408894f26b02c56c6bfd4dd531eebb9c67d2fb7fbad3009 app/modules/themes/service.mjs
68cf3325307263022cd5704fd77664f7269896b8aa0570033c84b7abfba993ed app/modules/users/index.mjs
c6558b8a0cd9d7ef30d0e259747805e3d91a5359c2dbfbd79e6794bb403a9926 app/modules/users/module.json
8640accd1550932459ecd14738139284cbcdd93f31a61ab6e7748791fc82933f app/modules/users/routes.mjs
fc4af51a35fd08289ec4380a78c06b3236a2469041ecfc911b9e0d7d269afa19 app/modules/users/service.mjs
c197ce417fbce6dab1d8ee157b0a105a099dd2021ece4dac3891d0b2022a0d58 bootstrap.mjs
1c5521e9dcae9a1914a0567b7c8a2ea8d1efd7a1c5e3e7cffa1c969036a70dd2 CHANGELOG.md
61823fc9fdc036170cce6edeecbb612b442d1c65fc9f7a7eaba47e5016316ee5 CLAUDE.md
61199cecda2c84954de2b60c07eb9f3a2117fbaaa4c430319c461b2e76a10254 compose.bind-mounts.example.yaml
21fa9a7c0d609928db4b3d1aa697a559b0245011ff63ea3a241b17b2182f2155 compose.vps.yaml
3fb770edbc429c3e01a3a73d861033b2c425bdc9a0a1b27e969a8d0fc0cb14c8 compose.yaml
6323f984f1e04ab135356a14ec151941638041f6b305ed68772d5e1812972075 db/schema.sql
49690c4e4c8e84de8eb40ffe79823493b7be20fe46fa2ad9e6544f7f0afbfd2c deploy/Caddyfile
2e0077cd6dd83d3a07fcef25b7e37ab5fc056dbe1ca034b33d55135234045882 Dockerfile
cc794bca282d79a27d860d0bfef4641769f4e9f31172778a1d9d8205558d948e docs/ABNAHMEBERICHT_1_32_0.md
de0d86f806a70195050613f5b56f6c4da1ee2eff02a9a991b6aacee229c46ca5 docs/ABNAHMEBERICHT_1_33_0.md
947745174897470de0bebf4f7c2b29a0c0ef3f1a762f277374c2614d9e3dec4f docs/ABNAHMEBERICHT_1_34_0.md
26c87fa38f804749a9363812127dc33ef69e201e4ef9b59206f6fe6e15c845b0 docs/ABNAHMEBERICHT_1_34_1.md
f792d366c13c5a4a9b4e8d4054e26190d9c327a7a770005d74bbe2b31bb84ab3 docs/ABNAHMEBERICHT_1_34_2.md
bc638fd21222ada7b15e40adff80a318aebec58139978109cbfd30040815a8d4 docs/ABNAHMEBERICHT_1_34_3.md
c0ae5c4176ba6f7510be047d4feaf383cd646152131003ebccc6bfbf8c8056f5 docs/ABNAHMEBERICHT_1_35_0.md
c050c8e11f2bdb0a742851423dcff864bafba9cc839c52b2f8d48b75f7b18633 docs/ABNAHMEBERICHT_1_36_0.md
1f3e96ba13844a3f1cefecca99b3d6313aebf86faae914897db0404ea031c491 docs/ABNAHMEBERICHT_1_37_0.md
361d19e6b7aeab3f22b337210f3a56221f2e42798c0fea75be978ebb7d72487f docs/ABNAHMEBERICHT_1_38_0.md
2f6518fd50d9088f5580cfcc03e92543321ac7feb97dcdd570c23c51fd8c5391 docs/ABNAHMEBERICHT_1_39_0.md
b39d2d892068e1313fc00c9345d54240b6d50caf8a940261a088e67d8778ac63 docs/architecture/CATALOG_MEDIA_MODULES_1_39_0.md
e5f065ba8d516a5ebd47e7e6859d0aab40ef69797413e358d969ef27c454fcdd docs/architecture/DESIGN_SYSTEM_1_35_0.md
732ef23db1ef50862a423841f58e4628ad3b2a2ef2744ed7c5ef1fe01e3e38d1 docs/architecture/IDENTITY_SETTINGS_MODULES_1_38_0.md
cc0edf92756a51414563b4407dedb21d1e3b36682f4bfbbc334aeb33a22ae1b4 docs/architecture/MIGRATION_ROADMAP_1_35_0.md
db659979dfd6e08f36a7aa9b4de42750ac39c536b11fad694a1846c902ea65bf docs/architecture/MODULE_MANAGER_1_40_0.md
eb47b055dd336e8360ec7c4712dee4ae37f109f3820e3f185969e2327d790cf8 docs/architecture/MODULE_SYSTEM_1_35_0.md
d7773faac0e93510a5a51c91de997df03547b51f3124267dcf137d4e99299562 docs/architecture/SECURITY_ARCHITECTURE_1_35_0.md
58cd43938b06e29520b92516a1e816d17d2c08d4847b99c1ee700b2185f46f20 docs/architecture/SECURITY_FOUNDATION_1_37_0.md
771c4771c4d7335750c5a2d976c765b4ed66ed936d8550d7af69de14a16705bb docs/architecture/THEME_MANAGER_1_36_0.md
67a1be91b0c2d2797716f785f2f770c881cf88d7fd617722468df8d949d0638a docs/AUDIT_1_31_0_IST_UND_LUECKENANALYSE.md
2acba8fcc5da42e5a808925a86628bc0c6fc817ddb082b0ead3857c6a43460f1 docs/BRANDING.md
f23c643236c84b0e3715620598f358065748b6d090229003e23df8ad9320b54e docs/FULL_LISTING_EDITOR_2026.md
ba9a9b93622fadc399cd9067d80b4ea339193eb19825106264a3b86b7128d107 docs/GENERATOR_STUDIO_2026.md
54f45ae5c2f12b6314b3f1bc3e59e753c64ca7cfe39644725d765e9f02f637ef docs/GITHUB_DEPLOYMENT_1_34_0.md
e5c6ac33f5c0dc93099148d95af123a9aeb72298d885cabf0b1dc96a9cad31d7 docs/GITHUB_IMPORT_STATUS_1_39_0.md
5a25e952d7d79b562bc19c990451830ea2ac3e730c9af399425ea18ffb8fd61d docs/GITHUB_IMPORT_STATUS.md
65d19c1576f4a6011008a7e447a3530222517752fb59ebc5bbb506b791e32605 docs/HOTFIX_1_23_1_EDITOR_CACHE_VINTED_FIELDS.md
c9c8f934a0c4192dae29df913588188aab1321364d1c46b9c66da5c754e9df41 docs/HOTFIX_1_23_2_FLUX_EDITOR_JOB_COLLAPSE.md
2306ff399000c07a9d7e260a58d92c748fa3219922a4dda25f6b2121a1ad2dbc docs/HOTFIX_STUDIO_FLOW_DETAIL.md
0584257245a29de62a6374eb8b114bd19fc6a36306ed990d820ed2062514d6a6 docs/INSTALLATION_1_32_0_WINDOWS_DOCKER_NAS.md
7c1afdefd1e3a75a5d6b49aedae80e266bab4e91cbfc657fb862ddfd737dc792 docs/INSTALLATION_1_33_0_MULTIPLATFORM.md
1475e484cccb0db67e02abbb05f8b8e676c85536ec4f5bda7dd99d4563fbc049 docs/INSTALLATION_1_34_0_ZERO_EDIT.md
1df2aed413865c03e541e66249c1df3eed6d3c3aea9f0ffdeaee40453665df14 docs/LISTINGS_UI_2026.md
4f74fef6877126d2579356b9731955e29f05ea8b55b59abb91569e47730a1c3f docs/PUBLISH_CENTER_2026.md
bae236366d6d2cb0139e4dbf8baf099599bbff27aacc9eeeba20fdff644f5fb0 docs/RELEASE_1_24_0_RESPONSIVE_MEDIA_FLUX_ARCHIVE.md
5223408e51f35ba5f6ce86155544311dd13f60522a6d482f372d64788ab466ac docs/RELEASE_1_24_0_VERIFICATION.json
b66524ffd19976f650c6b26b299898b182355950f545c131de16c89fcffe0ebe docs/RELEASE_1_25_0_RESPONSIVE_GALLERY_SMARTCOPY_PROMPTLAB.md
1c5ebf1a496c9571fe9d941793371f9f0be89d85a587c8fa9532f9b25bba92bc docs/RELEASE_1_25_0_VERIFICATION.json
1eef86e13d9429701e9d60894f36fe0eba82c974565b1a6687ed157ca6da680e docs/RELEASE_1_25_1_ADAPTIVE_GALLERY.md
14475ae4169f4bde4a5b7ae5512867f972ede69dcb621d7cc6a208d4fdc6a331 docs/RELEASE_1_25_1_VERIFICATION.json
f02b80194f434dd3d82b5c4c111e8cae65f1f053a267cec2793a1ff551daff9a docs/RELEASE_1_26_0_ARTIKEL_EXTENSIONS_PUBLISH_GALLERY.md
570522a6513134227122da1b5f2f56a421c62d3b0b5adba703872e9026fa2b58 docs/RELEASE_1_26_0_VERIFICATION.json
4cfc47f35765259cbd6a841f51a85fa86600991d1ca545b10756f15b6d332f7f docs/RELEASE_1_26_1_STABILITY_GATE.md
9646b913994b1bf8ce03eab57e7a6a87061540e44fdde63ad5b7eee93ca9f475 docs/RELEASE_1_26_1_VERIFICATION.json
7c6c3a2e4ce478f47e540a34a3505dbbe11b8f2175d0b274bec7643457997140 docs/RELEASE_1_30_0_OPERATIONS_CENTER.md
6f9c206869ba94c461b1d9f8e40847792b8891bb27809a0c6fa3d1d68a4e8598 docs/RELEASE_1_30_0_VERIFICATION.json
5da62e06d768ce832d18fb3ecb3ccca2f051a6218d2d3cb492d1e5aebbcccb52 docs/RELEASE_1_31_0_MULTIUSER_SECURITY.md
6288a31dfa61f71d13f79d40ab64bb7ca475de07ada154c002cd4b0d44a284dc docs/RELEASE_1_31_0_VERIFICATION.json
4ee88ff8c3c655cb31bc18192a37ffdd0eedf8e26039b252094d5ce169c1883c docs/RELEASE_1_32_0_DOCKER_NAS_PRODUCTION.md
628d4d1a6c7d837a0c8c22958253193642ddfeaab5f425f418f9f32b46e84340 docs/RELEASE_1_32_0_VERIFICATION.json
624919ea60969079f767068771800dbc04ea7a87eb1a53d7f0497447492c25cb docs/RELEASE_1_33_0_MULTIPLATFORM_DEPLOYMENT_FLUX_ADMIN.md
3f9ae39792bec600ddd534284ae62cb2b4f9db01fb54c09cee8ae161551caa2a docs/RELEASE_1_34_0_GITHUB_ZERO_EDIT.md
c724b699894d5ec3c050af0253c6de0c645a789219a344ad7ffe31e330d9921b docs/RELEASE_1_34_0_VERIFICATION.json
7caa9e7b1e51af362332e9c50165b60c54c9219c7384c8313d3735c387df1c01 docs/RELEASE_1_34_1_GIT_SAFETY_WINDOWS_HOTFIX.md
ac834ee57ab6bd8fe3dd0238837193e66e01d7e78590a289347b002591da3fb4 docs/RELEASE_1_34_1_VERIFICATION.json
51057d17e2636ef1bdfc6751dfad29ebd34fbe7f41b870f8f2f756a5c97d1c4a docs/RELEASE_1_34_2_GIT_SAFETY_DIAGNOSTICS_STAGING_FILTER.md
4c2c141ffc85b1d7517672abf2b28bb19fe4769505c0eb4d37e22bae06826cb3 docs/RELEASE_1_34_2_VERIFICATION.json
d55eaec79e10800a930fa030367ffa34037755e5757bc532e72d25711c5ca09a docs/RELEASE_1_34_3_UPDATE_ARCHIVE_EXCLUSION.md
4bb731af51e786a4827ec48bc7c4d4843c287456aedc09d8b74aa0eed3c0ec16 docs/RELEASE_1_34_3_VERIFICATION.json
e7bb3bb950e3c5303746f43139ca8f7c985d2d73896b44f5b707dd46a9152529 docs/RELEASE_1_35_0_PLATFORM_KERNEL.md
33eb9f0059a2ddc4b4debe5bf733720f2a5bb22f2710bab0a0cc9ac1b898ff11 docs/RELEASE_1_35_0_VERIFICATION.json
5a9fcfa0ea6e9c5c13f6d943e1de4d31c21e21fcff9186e8a714d7a16ed1c18f docs/RELEASE_1_36_0_SECURE_THEME_MANAGER.md
2dfe705857424865f101e861f4e633c8a7fb3c0e8dab874cb6620fd09b1ca902 docs/RELEASE_1_36_0_VERIFICATION.json
527806c00fb51334457726a9a7e9f6fc13f4dacd985fa2d2b97d5eb21c543853 docs/RELEASE_1_37_0_SECURITY_SECRETS_OBSERVABILITY.md
c3a8a21f5a3c3edb05ab1762a06d05b7f6eced3be84cb4f6f5e7f31bc627f06b docs/RELEASE_1_38_0_AUTH_USERS_SESSIONS_SETTINGS.md
c17771f19c2dfd6629fb91b66dfd661eed3459f820b71a427f0f98b07b45c56d docs/RELEASE_1_38_0_VERIFICATION.json
26355d15c188b1ce3bd03a539e1b27ee884352db48e5db423f60cdcd4d9d49f3 docs/RELEASE_1_39_0_LISTINGS_INVENTORY_MEDIA.md
c016becfaa0c1ae5bcee255476dd2a09fd465308f5ec2fba6d3c6809b009538b docs/RELEASE_1_39_0_VERIFICATION.json
837ac91a926330b800a027a61d4a2aa0386cfd61f9b7949231bbb09e1ca0e6c3 docs/RELEASE_1_40_0_MODULE_MANAGER.md
e52467c05ad08a262ff812989f2be19bfad3038f35f61e9deabcbf61b81fa5df docs/RELEASE_1_40_0_VERIFICATION.json
1908713d7458ecacc833faced77984ef5c0155cd61b0eac13a4f874e3f3a5676 docs/ROADMAP_1_38_0.md
185b1007c90273126ebe92bffe69f88ae4ec4a3f04451cb9d5d4b772a0482391 docs/ROADMAP_1_39_0.md
b581d7d949139f37798dded557235a679621172f444a6271e7fc7ade3020299a docs/ROADMAP_1_40_0.md
fe5756f788b2ab131f0832504d90d46d1ed744bfe470fd040803985234afa3cf docs/SLICE_02_ACCEPTANCE.md
05614ecf41becc399acfa6a3b2f681f37a8c80f5ce0130b98c578b2c8c60713c docs/SLICE_05_ACCEPTANCE.md
0838bcc6464a6beff39f0b4b056e513c1a390193521d9a8fc5d440d38034e9d0 docs/SLICE_06_ACCEPTANCE.md
ae0f7c6f6e614ec77e362db1076288596ec48d11b78f33f26908fbc40ae5dd18 docs/SLICE_07_EXTENSIONS_RESPONSIVE_MOBILE.md
b561983736639a08146d3642b718651907853d589ee32e5f421fc090f2c75a20 docs/SLICE_08_EXTENSION_AUTOFILL_UX.md
c5bf7a0c9f787f100e422d0deb27bffc2c8c86b0e7c1ce1f35d2de8d7d8ea774 docs/SLICE_11_DASHBOARD_RESPONSIVE_HOTFIX.md
876675bc3015838f568a6970ef6c01c9fcafe1d8d138c4379bc0f2ee1fd7445b docs/SLICE_22_1_SETUP_AUTO_RECOVERY.md
223f50d05096b3bfa3ac3a9f0880a2055fc2029b7d70fabd086612c3348cb34a docs/SLICE_22_2_DOWNLOAD_RECOVERY.md
95e1d560378120d7ccb0f363720ba832505631aa65616abd4df01baba5ecc269 docs/SLICE_22_3_POWERSHELL_51_PARSER_FIX.md
88f5a2d021874764b6a7f56c690a1e2112155b83cdf0d4d964b2c6e00ca756de docs/SLICE_22_3_SHA256.json
791a5d30f0d6ff9664722a2d00dff0db0bbdf2207e83ab391a40d6c4ab913bba docs/SLICE_22_4_SHA256.json
d14c938c6c9397290f654406d4b995b63db0f22586e78fc97fb5fef575748807 docs/SLICE_22_4_UTF8_BOM_FIX.md
f00c325ec3c879b47908dd5410cc943febb923200e9b9bd7d18197b1570a26fe docs/SLICE_22_4_VERIFICATION.json
e140f3ee3298b3894126e37900b04ff1073ed400e6414e35897815b3f674d93e docs/SLICE_23_FLUX_REFERENCE_PROGRESS_SETTINGS.md
b4b01b9f3751940d184d6fff269108798c7ec62ca7796b923cf82abbc142ff3b docs/SLICE_23_VERIFICATION.json
05e3fcf5aa9a0d8d53175a3d24c5feb36e55f73edfeadf05384e87a5de73353a docs/SLICE_28_1_FLUX_RUNTIME_HEALTHCHECK.md
43d867bb8b455f7450e5146648b28c759e50ebab45855d75a36dbc9f91d3f654 docs/SLICE_28_FLUX_STUDIO_VTO_CLEANUP.md
0bdbeed4b57767427afbebeddc30ea58a211f851663939d6301af38820cf098f docs/SLICE_28_VERIFICATION.json
1e20fd1abea3ce61f7f9cc88c6e8e4ddb0fe3513c5600e41b8f7c3f8d38e3ae9 docs/SLICE_29_FLUX_QUALITY_SETTINGS_TABS.md
1df7305e6a43212a582d5f83630e0ba04fbdd3da0d673d9dcb8f1c5f7ca37731 docs/SLICE_29_VERIFICATION.json
07d1ad0c19567cbdb05623567816f1506197a31e86fbcd1742f4ffa300335ae4 docs/SLICE_30_FLUX_STUDIO_PRO.md
008237388c4816d3cd67f3f0abfd0512f4ebf2dce75ab6790de41b0481ae1d97 docs/SLICE_30_VERIFICATION.json
db1674505e2ca7eb36c8752ea9b2d6fe2f2c12a5e6a1584e2722e20445b05e34 docs/SLICE_31_ADVANCED_IMAGE_EDITOR.md
3133a06e68cd98e615797665956f1bc401c0427045298b46c48ca590be3ef9da docs/SLICE_31_VERIFICATION.json
d425fc1724ac55853bf3433348486de8f8aab111f53fefee3c532beb1deb82af docs/SLICE_32_BATCH_IMAGE_FACTORY.md
0a8917412d000168956f7ac55e60ab79b54a8834deef0386a681bb8f920514cd docs/SLICE_32_VERIFICATION.json
25ff8492360d473e99c75c308be5f75cf84e0c11574d42aa6553d44f8bb35582 docs/SLICE_33_ARTICLE_QUALITY_CENTER.md
1d5411f69c62222d3155f0e89f2b4b5a3effe317ea1e59347efa7730a8e1b0e9 docs/SLICE_33_VERIFICATION.json
1161decfabd73c40ff1d2ffbc7d1b9b5168a8fb5fa392187c1b431e9a7f3a78f docs/SLICE_34_PUBLISHING_HARDENING.md
aa7ebc90470071566749c61b0dece4169f87666dcca4b88922f7fbafcfdd5a84 docs/SLICE_34_VERIFICATION.json
cc77a92ca268d3c444c6113a9cfaa38d3c805a579f6b1b21b7dd43a6ada58551 docs/superpowers/specs/2026-07-06-autolister-features-design.md
4b66a14b4515e38477f10325ab9d03d9782ad0d426845aefe2d508986ed2cd81 docs/UI_FOUNDATION_2026.md
5e655fcf3bb1182f8850b4104b56697ea952b01d2698af6d3d40b05e338b3506 docs/UI_UX_FIXES_SLICE_03.md
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extension/background.js
b86f00c7afa1dc921dd66f5cfea8c817eebc8876b9daca6a55dfd03680156c79 extension/content.css
8ee8d1a94bbf83e5d09aee3c7d8c4ea5f216b2a51e73b6dbc74f7e6b99017a1c extension/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extension/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extension/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extension/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extension/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extension/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b extension/manifest.json
e61fd8e1264995fd633bd76e71329813dd02f361286329832a18dfd5a8bdd372 extension/popup.css
bdf5b794473cae818789cf95a28a9c9a9d50f81529d72fdf45a536247a783922 extension/popup.html
d7893cfdd686d4a6a1bea333468d4ba72cfff0e7166687181a2d37ba1faf3332 extension/popup.js
c7db96df5fed3c8336062204322d62b4870f5c8ab1d30ea48cc6e7e38ed3513b extension/README.txt
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extension/vinted-categories.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extensions/background.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extensions/chrome/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e extensions/chrome/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 extensions/chrome/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extensions/chrome/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extensions/chrome/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extensions/chrome/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extensions/chrome/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extensions/chrome/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b extensions/chrome/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 extensions/chrome/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a extensions/chrome/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 extensions/chrome/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extensions/chrome/vinted-categories.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e extensions/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 extensions/content.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extensions/edge/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e extensions/edge/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 extensions/edge/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extensions/edge/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extensions/edge/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extensions/edge/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extensions/edge/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extensions/edge/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b extensions/edge/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 extensions/edge/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a extensions/edge/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 extensions/edge/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extensions/edge/vinted-categories.js
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extensions/firefox/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e extensions/firefox/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 extensions/firefox/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extensions/firefox/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extensions/firefox/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extensions/firefox/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extensions/firefox/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extensions/firefox/icon.svg
1954ca9f34b3afe109935173f685482f06bb685a9b8f0d4c344f0c6133ccfaaf extensions/firefox/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 extensions/firefox/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a extensions/firefox/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 extensions/firefox/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extensions/firefox/vinted-categories.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extensions/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extensions/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extensions/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extensions/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extensions/icon.svg
c2fdc0530c71ef400fe9d52aed914f65d331b0d89dfae7ef1d156d54d1a22a6b extensions/manifest.chromium.json
1954ca9f34b3afe109935173f685482f06bb685a9b8f0d4c344f0c6133ccfaaf extensions/manifest.firefox.json
e4ea31f91a4c8df18901bfc77fc351a8808d19d690243b80bc4faa140e18f851 extensions/packages/vendoo-link-chrome-1.9.0.zip
e4ea31f91a4c8df18901bfc77fc351a8808d19d690243b80bc4faa140e18f851 extensions/packages/vendoo-link-edge-1.9.0.zip
74c219587cf0f827a1a1e2b8adacac55477be717fd4ae80e2ae027a9ffb0744d extensions/packages/vendoo-link-firefox-1.9.0.zip
9e828844f41154c87ccfc5d8f3a19476396e2782fbd0f956465b42fb508cb098 extensions/packages/vendoo-link-safari-1.9.0.zip
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 extensions/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a extensions/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 extensions/popup.js
48b5f9f4ecc1c1c42f37321e9bb2fc857c646b9c16c34520fc7d4ca59a1036ac extensions/README.md
0b2a03d06faae7aaebeee8ec9fe1864422c8651f17ae90b185fd31474ac5eeb0 extensions/safari/build-safari-extension.command
afd76deccd8bcf26d39f8c86deb1de578873ddd8b09ac18eebacae33169bb420 extensions/safari/README_SAFARI.md
3873602c1529daad6647a7585c858d817821de0afbec93a26d1b3f5a7b9cb01e extensions/safari/web-extension/background.js
c5a0ca59a8858e9bd484d1e5fb7a2aca72db092fb062674f531bb76f5a0c952e extensions/safari/web-extension/content.css
22bd64723d279a6229bccba2a4cec56f1ae83f4cd5628bd1a1841930b0f442f6 extensions/safari/web-extension/content.js
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf extensions/safari/web-extension/icon-128.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b extensions/safari/web-extension/icon-16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 extensions/safari/web-extension/icon-32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 extensions/safari/web-extension/icon-48.png
5904aad2263358a5be638db435d5a0576b8c2bf21d1a20114636d65dbdbc07a8 extensions/safari/web-extension/icon.svg
772f1e2e33f4d6d882fa0af663e315fd3b8208141227bb5beb9baaf1f4e08397 extensions/safari/web-extension/manifest.json
e3a3863b58a571a0f0180bdd333f9389b918415b4ea96b70f3ab6d4105d95c50 extensions/safari/web-extension/popup.css
559dc70841ebb186ff96f9f2ba32ef26a3a7f8edd08363f09c0d7163049eae5a extensions/safari/web-extension/popup.html
2bf2d5ccf02622cf1d62fd553d21c0ef1b744616742e7962ac302c10d37426e2 extensions/safari/web-extension/popup.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extensions/safari/web-extension/vinted-categories.js
273322e8dc29b0c6b639a6cc7e44a9570ceece09306fd46003b05a8fc86c88b7 extensions/vinted-categories.js
367d8f879be543115a1060ece5beb1dcf2ac174c5dc4a53efdf54731e6bc4520 FEATURES.md
7f78a0d512de717ba76c9a5e3e1bd2e52db9edf146e8eeb7297458fde5d92afa GitHub-Deploy-Assistent.bat
9a5bfcafdce53130d7bc36695090a8f87096b4ead9dd5ccc3d46d1d80c07a0fa lib/ai-claude.mjs
ad6ba4ef521557d5c06bc546cda70db57e710e8173daadae74e8f15f99836c1c lib/ai-flux-prompt-jobs.mjs
347778ce521a1919ec0679918171dc625d7f04d6dec26c8a4700e702bc78de67 lib/ai-local-images.mjs
aeb5103c0179232b9954b7854be8099cf4bb0f3ef1ee908eb5e4faf6a8f1205f lib/ai-local.mjs
29fbe09982b0b327b773bd119f57f50363424161815ac894ca4d677759e93e83 lib/ai-model-jobs.mjs
9f474f665d6d610fe00d9e707e85314a854abb906e31db2bb9a3a7c76785ff4f lib/ai-model-photos.mjs
3fb484456b9e6374f14b53a2276eea8533642b7c9073bb73a1bb0dbed7048bbd lib/ai-openai.mjs
581c10b8346d0aa10169ed23ed49c038951ecd5cac014722c1080bbd5aec1c5b lib/ai-openrouter.mjs
271696d7cbef3581b667a8ce3b07d0b17b1e8b467fbede4d8aa512ecc5225515 lib/ai-router.mjs
76a2f1fdf60053739d82962264219060807022dfc9a2b3a644946fddff02a8d9 lib/archive.mjs
2015974b9ceced554ecf0cfbdbf50a7d1db57459d50fb0241b8e9277559e70f4 lib/auth.mjs
3e2b75c0758703e590233cbcc9b589e3177134accecf5ed921791891cbfc8522 lib/categories.mjs
86793fb57a1dad32f4d93e34c27ffe9e77a95785dd30b2b55ffb67d0ad5e14fb lib/config-store.mjs
8c203e70e9ab07b996d4a53031892bbf37b10efd024f9e0013266cf2af0244a4 lib/db.mjs
54722d3f76ad9ee4fbe731d3a65c2a03d343eb82d98f8ea5a5996b1bec24d57f lib/ebay-api.mjs
524f1b48d467998da819f0b947f2551ad45784e588eb442304c5f6e925dffaee lib/etsy-api.mjs
5b2c566ff14fa502ba2cd4d4c918fe238a8e93c3283d521144093a897f9d8018 lib/fees.mjs
7dcb2fb5606140afb7a019094d20ef88e9b4e2c70041f77b06d67d8992fd25ce lib/html-templates.mjs
e41a13284429ac01652d979efd0734d5a2b29945e7e93a910b44eaefab9c00b6 lib/image-batch-jobs.mjs
5ca5fc65a7de7c27243646d291dc42c0b5267a47705a09b306cd2c2eae2a77c8 lib/image-editor.mjs
5e7aa66faddd3d19bc6ebb9ddc13abfc4ab4f17d8c51bb39b2c4e0279385d788 lib/images.mjs
606f4cb1013c711d971dd201ab06df84ecb128bf5d5277095ce2e2ea56029e45 lib/mailer.mjs
493895deb08e51ef1f47b55c88e3225bb267ade9fe305a7ed2c59a3f417fab16 lib/operations-center.mjs
f10c3951bc604392e9fdaef7ba51b227893266baaa93981aa480409fed722062 lib/publishing-jobs.mjs
3a728417dd668d60fd1526ec738cb9b302f86c01d62b2227f12b2e44b7d389c7 lib/quality-center.mjs
74c783c1e06e9cc2da0165261a49511aaf374dab3159cbc24c0d69b6b467dcb9 lib/runtime-paths.mjs
d3d862ab32fd276ecffb54c0307976ca680135d92f24d024c95d365a50257643 lib/secret-store.mjs
f6bf70cd77a973daba47f6ab73b21413874055f1a71525ac0ed80a631aea16eb lib/security.mjs
2fd970a6a357a26211f0b9bcf432e59e79f73dc9a4cd35f88cca939655eefdff lib/structured-logger.mjs
ddb9c7677600795a4adf8a19a7525b7551455459d16eed4cdfbe751ef9ddf0eb lib/zip.mjs
2924f4e8abe5ebbd099fe1ceb2bc6ceb4bdda55fa3e57dd299cfc05d310a9246 local-ai/start-local-flux.ps1
7c6176d8311b1ba9d511beb40edd41b8248e61c298528bbec3f9ef1171856c05 local-ai/stop-local-flux.ps1
5f220a2dca02cc0764f6d0157677611b26c88860b48367eb661b6e47a1b92265 local-ai/workflows/vendoo_flux_schnell_api.json
302ab1609d08b3059ba6563b676c64f0709651f2e3c531857bfca3840c535a79 MockupDesign/AdminDashboard.png
49f7625a1299a16576feabfd7824ec3511391bd9b7c53a1fba9232da7e8bd6c6 MockupDesign/ChatGPT Image 7. Juli 2026, 10_05_19 (1).png
7b8cc9c5db8718b0b653ec6aa9d2a8bfa1bba03810248c3ba17745b6f15cc412 MockupDesign/Dashboard.png
4e3e797ed5d3ed0b60d00d8e567fbe51543c08578b858ef71e77b274ae449fd0 MockupDesign/Einstellungen.png
c78fd6f673c0e59789ea313396b12c2f21f75a2ee6c7ad2de81a6b89f6d90588 MockupDesign/ExtensionDesignMockup.png
ed20bc04cab8e85245a855810a61b736a682f972eb85e23340edc9b558851a93 MockupDesign/Heute StudioFlow.png
1ad88f45f377ab9b3f35f96a0ceaaa7f75cb0a996e83370d76c54f527392a08d MockupDesign/IconLogoMockup.png
0e8b4a31d075f1f83ea62b5eeeb53e89859e395a696deb43155932a23e7cef86 MockupDesign/Lager.png
b1c62e118d9be316274e966c558cdcccdd41afb3a9f05a60ec1e4a3433d2ca0c MockupDesign/Listings.png
a52983b9ea2bf920d115485d10bc30226da88bc5cba8b00bebf801b21c096346 MockupDesign/Publish.png
8c8bf278d0c6725e1dbb97b3c3d0c36a9bfc0753c3c86433fdc294bec70dbc0e MockupDesign/Startseite.png
62f14221b1d71c9e631efdadd221397ff657adae4b737df52c8bff1610b90999 MockupDesign/Vorlagen.png
95cf27f33fc83f1b74ba4a8c0a0688e3f3ab83f6194b030709adadeff2550ed0 package-lock.json
531673457db5e06958561c2cc5fa2aa2f32837157936ceb406fd3d907d744529 package.json
3da71dd28cb25c7c7317b9061855d40c6a3ab8bc39391963b49ee1e707f838e5 platforms/ebay-de.mjs
cc1ca2b4384c8c548bf755dc33101d248541bf893c3d5f35369961f904afcc00 platforms/ebay-ka.mjs
fa52b247dd758aeee06120499bd1ae6c53e9f460f8bd7762b8f06141b201e32b platforms/etsy.mjs
5c925e3934a4c9e2f26dc15b3449a249f5ce20ecebbd459b15365a34804824d6 platforms/vinted.mjs
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 public/android-chrome-192x192.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f public/android-chrome-512x512.png
0748df67926d63afb7d3fba9c1a451491631f9682477ee2c24f3a3e69120c066 public/app.js
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 public/apple-touch-icon.png
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 public/brand/favicons/android-chrome-192x192.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f public/brand/favicons/android-chrome-512x512.png
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 public/brand/favicons/apple-touch-icon.png
a0f1e01de4e8215e690c1ce869fecaae9d7ba3cc95883340a53ff38f6be52ce0 public/brand/favicons/browserconfig.xml
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b public/brand/favicons/favicon-16x16.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 public/brand/favicons/favicon-32x32.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 public/brand/favicons/favicon-48x48.png
15bf8dd655b34a8015447e834d387af12685238ede598f5f0e7927eea2933483 public/brand/favicons/favicon.ico
2daa93cca0ad2c0cab90a9e8ad4ea0ae4b64feeb68c422954020d17e2376a381 public/brand/favicons/html-snippet.txt
3798313cc939d9fa582a92638356abfcfc8f8b4f143d9434b7012446195e6937 public/brand/favicons/mstile-150x150.png
c372675942caa5010340f21fe521adc72af537d909008731976820fd84604d42 public/brand/favicons/site.webmanifest
b2dc767e7a01395d23a7f3f5915324db1a7d1912bac60470d2f7c10815895173 public/brand/icons/vendoo-icon-120x120.png
409a96b169bc91efbcd7e923614a8cb30c6ca36cbd727f41e02c2ee4f89098cf public/brand/icons/vendoo-icon-128x128.png
d276f50b298e4dfcbba9147550463aee498531280399167d1e9774aa8e5f7e21 public/brand/icons/vendoo-icon-144x144.png
3798313cc939d9fa582a92638356abfcfc8f8b4f143d9434b7012446195e6937 public/brand/icons/vendoo-icon-152x152.png
47122dc91010721e2692d11986f0b91d9b76634130a95723e92b2a070268d16f public/brand/icons/vendoo-icon-167x167.png
8c031a533aeec86818d442ce96e859497817d16c2c9bf037c68955b90e8ced6b public/brand/icons/vendoo-icon-16x16.png
e0e7b8ef01c36f0625b6157aa46bd69de05c17be0b054208fb635d6507b52154 public/brand/icons/vendoo-icon-180x180.png
a2ea3f5f56dba8bd4d23fa54a26fd941567b4febdd1ed1b4e9f5bcc1c9786e53 public/brand/icons/vendoo-icon-192x192.png
3f2517cfd215cb624ed639d60b064dfa5e88ce71eb7bbebbbfaa70b3d62556db public/brand/icons/vendoo-icon-256x256.png
9963f60ab46d7f015a9400ee22e8e7a9fed31781a3907ef14b674d179d8f5f45 public/brand/icons/vendoo-icon-32x32.png
cae3eb737c8ad3a82a679b09d33d991b501bf482e0132e99aa1b8ad064e472b4 public/brand/icons/vendoo-icon-384x384.png
64d7b63beed9f972848daabc86484b5672b42ac7ed402a0d3effb47e200bf253 public/brand/icons/vendoo-icon-48x48.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f public/brand/icons/vendoo-icon-512x512.png
bc85af557be532dcce6beb82cf9bd61af683666b00fb61e4b2069f78e60a9a33 public/brand/icons/vendoo-icon-64x64.png
01d59b665bc90dddbd34221e3a2ec3af11bff6fb328aab2c9947c03d74b0465d public/brand/icons/vendoo-icon-72x72.png
ed3dfa59e989b154fac88a3c72ac840290ee3e1565d44aa75596bf0055c74020 public/brand/icons/vendoo-icon-96x96.png
46ea6ba4ca6ca2352f37353b8bc4ca258935d29ecb8d3c9b133a48ea75c0c58f public/brand/icons/vendoo-icon-original-1254.png
8fd9901e07dc9172d162706511ac8dcce220a4c907cb3efa9940c9c13fa32526 public/brand/logo/vendoo-logo-cropped.png
3f39371abd1efa6cc8366aac9a6d067f3339b8f2a2da77ab8a26c6bdcf8c4fce public/brand/logo/vendoo-logo-original.png
b56d07515f6220de7fd0cb149fed598a7361c985ae6ca7cb14329a99e8947aee public/brand/logo/vendoo-logo-transparent.png
e83921d2af9930ab27df1abe64374cb9311189bfaaa951068109177443571a07 public/brand/logo/vendoo-wordmark-transparent.png
1711a9387f2d6e75797b77c8daa92b94d7a15e128476e4b8aa9d54ccb0692a0e public/core/api-client.js
f30395399a5c6d7e0a884b22f28f7648e6343695cee9960d6ff13b34de7b48f1 public/core/frontend-module-registry.js
fb3dbcd03f7ed15b773b582c2a2b785c3040d3319aba5b7c682a7e74e1cf3b4e public/core/safe-dom.js
38aa57d13aeb3ab70babcb903bfee71e47d80932ed24a73267c13ff81c24e3ba public/design-system/theme-contract.json
308f1c0e2ed1de34aa11545a1a660aab02631e422d6c6945e3203d11666784fc public/design-system/theme-runtime.js
4d69e2cb6b7f9f63b54d708a5d8b1ebefcdcb9f88a977053db5031c05b098464 public/design-system/tokens/source.json
4a9e65edeaee3421edc3dd4831230062494f1a42f8495f4cb979fde8664d06c4 public/design-system/tokens.css
15bf8dd655b34a8015447e834d387af12685238ede598f5f0e7927eea2933483 public/favicon.ico
5b14c728ef81ca4554510f29ab5050a6e4da0b61db670f0745847e2670d22524 public/index.html
f7e763f28b1ecf17919752081d94b169e499bba27b421c2276704945f91562db public/login.html
e37558ee9612a36db8a19999fbb320f1c249a8e155f94c83a82926bec920f989 public/login.js
59291f75eca405e3856bafea76cc601d681060eb6b36bf82a4be3c3ab7eac290 public/mobile-upload-expired.html
f046f166d89fc32774b87deb02e6d144fd2f40c0925aac67487e5b7c489a0ec1 public/mobile-upload.css
6152e4fe715efbf8fd6a7c4286f23172bc3cf15dde085e5e4f7389ad5e65ad73 public/mobile-upload.html
f13846801a8493aa43df6ec3d78b826b21b59e8f21d47735f68fd0b278e440c7 public/mobile-upload.js
3132436d52caba719a3460c29a807e6f0703cb2118a80c9fae6c30360498d249 public/modules/module-manager/module-manager.css
bf10d5ccc53f287a8b61d488af50c3151c764f36a29ee5d4fe9ee321fa0eda06 public/modules/module-manager/module-manager.js
01f2bd124257220005032bf234d122b9942fdd8fd57ed8195748b2fb1f5a5cfb public/modules/README.md
2d7a004db3e22b30ad3a682ba445bcee3fc1c5f0ed5e8fee45b5892c5b335e51 public/modules/theme-manager/theme-manager.css
0edc61f0c2bb604c3adc40813b18fe5ca8d9b846ec2a3d9f406ae26ae313d3ee public/modules/theme-manager/theme-manager.js
e0a6c981d4231eab26d981be62647d0e6f89e05e8371baad121348202ad54f49 public/style.css
ff525e0af963e6f54636cfdc1bd2d045aaf82e7b0199755eb5cdf4c52110be2e public/vendoo-icons.js
f0214bf65967029afe7b44b1ac9855d409f22ccecd302cd6aca454044bfdecb0 README.md
f397e46da92394d34c2fc01715f037cca380703ecfa1d4a451de8ec7342e05b3 scripts/docker-backup.sh
86a411ae1fa5e36a11b0a8cb61e6c0169e0b80d3cedc9b7b82c3cfff23dd7390 scripts/docker-entrypoint.sh
1b58c1e5f762c4928d42605c01872f38f6d6bca92342260f3cd88a132e6af095 scripts/docker-restore.sh
781c48e182149dbdfdcaa0ad505d92fd6f68998c9df2269c1ff46088359ce3d2 scripts/github-deploy.ps1
f9fcdc69bd0b8c63c0dd6ecbb3fc35a55246e62a0db127f36687c3cc4cc1751b scripts/github-deploy.sh
0a9bafc79c1c5d59fb9b51ebc34c00eec4a4e9a5e873ce1818f50f3ab983da70 scripts/install-local-flux.ps1
2924f4e8abe5ebbd099fe1ceb2bc6ceb4bdda55fa3e57dd299cfc05d310a9246 scripts/runtime-start-local-flux.ps1
7c6176d8311b1ba9d511beb40edd41b8248e61c298528bbec3f9ef1171856c05 scripts/runtime-stop-local-flux.ps1
1a5736cf5fccc991df122163977c2eac80281bd99a54a5680b3d7eae99e4b79d scripts/start-local-flux.bat
3bf3aa74f5cc1f2946bb2da637eb30fe8daec783a32f9721ebb0468e20df90bd scripts/uninstall-local-flux.ps1
161b8976908f04890ae019e321ccb52f22a0f1c1d57e03f7e79785299d2ffa1f SECURITY.md
87d95670742b567e646fabe09460f97272bf984316150804e83099059574d266 server.mjs
e74d70244e676d1955443ea61ba68cc44a83c35db1a298a71e67dbdf4892d313 setup-gui.ps1
cf4519ce5adc01f05458e3286e86f3a419cceaff5fcdd869a1d07f1c1d1a0d8c setup.bat
80baa880c86b9a3b4209990038685770665e059f2d43d7f827ca5e326230f5e4 setup.ps1
e1b6b956c164e16d0151501f78d4928b775027bddd28c2c2eb1c038ab592fe84 setup.sh
2851c914a1b50a036cb265ddd32e5545cc7e8e34ba9d682445926acc23eb8f28 THIRD_PARTY_NOTICES.md
90485a16e3468cb9a6750646700fbb036cb9ac410e9b8bd5c582f7b923bf3c31 tools/build-release.mjs
94f4ced84834fceeb4f797bf8aab0703c873b57fd5d4a5b3fb02fee12e42bd2e tools/check-syntax.mjs
ac8440bce2659a035302609722f1dfed5d125223376cd575ffc0636397c94b54 tools/generate-design-tokens.mjs
ae80c11b7a76f9c397f47f11dd1df940d546aa120eb55852535b867091c39ff4 tools/prepare-git-staging.mjs
85114eff887ba65ca7df00f43333414c44b3aadc16fbc2fe10dc4dd4f9aa7aed tools/verify-catalog-media-1.39.0.mjs
7940884a0456bc7561c5e54bee14d11e2c9ad8edf3888af6a980ca7d495adb3f tools/verify-catalog-media-1.40.0.mjs
93d8fdee3feaf6e82ef15e7ac84bfd7e43ad13192f94655ccfce37f5a87b21ef tools/verify-catalog-services-1.39.0.mjs
97b311f8245eb9a8ab34387ef2608a664bbb6e313350f6da6c5e8b2a5f36e57c tools/verify-catalog-services-1.40.0.mjs
8f9ede5f112ee03323db3a6c73aee00b7037f5139dad241b11baf5f0e9cee4e0 tools/verify-config-store.mjs
5752f6edb956696781da8bddb1c1848d26941fbed5a524691653c84c88c34bff tools/verify-db-migrations.py
3745de55a110d8254983b096c6afab196ddaec7f1153cd2f34c1e480b15aa33e tools/verify-deployment-1.32.0.mjs
44f6b349b722e5a83d4725c4879fa1a9383f59ab5634c49d3d7d9d7aa0cd5e12 tools/verify-deployment-1.33.0.mjs
cbd91b45d97e11bd4f5ca2f9d2edf2b5931cb2aa336cb71afc30aad9cffbe1e0 tools/verify-deployment-1.34.0.mjs
01a43040a95cdac40703f49031acd9267cdba99d9027a51718f35ffb643237fc tools/verify-deployment-1.34.2.mjs
906767e574c06aedebb2d7797150bda2f1e4c4536e8f82f4c7de2e3cc8398c8e tools/verify-deployment-1.34.3.mjs
71d00227a59592cc0ad8ba321c63350ec25748ef965d8cd0eff1317738c7fba8 tools/verify-deployment-1.35.0.mjs
b65eec7fd54e1459b363d99d20f9438ae5bc4b518e775de8b97e33e89a382e42 tools/verify-deployment-1.36.0.mjs
22a5ba1951b2e8dbc924e60aaff8be7c41189ae7b30de9ecf50d0b741e84e13a tools/verify-deployment-1.37.0.mjs
84961aed097ee00496dd853677895614263baf425b00218cc0e1f3ced1b5b7b9 tools/verify-deployment-1.38.0.mjs
2ecf465073b7ec9e8ba38bf83364f681886d50440fbdd579a5df14df5d1bb3af tools/verify-deployment-1.39.0.mjs
4b37972998d87c1336590e2550895a826d63b47e4828d5bb3ba619376c287271 tools/verify-deployment-1.40.0.mjs
947942c84416b126f29281a8bef7b8230ecde09ea8b3bf3304cfacb0f9623fff tools/verify-deployment-1.40.1.mjs
ee2bb20f860d7238f767b181be1ed543214cc80230036389037d405e67c913bc tools/verify-esm-export-contracts.mjs
edfd749dfd685844043ee7cb47aa8567259356f85735bc8018d12b2b1e700649 tools/verify-flux-loop-hotfix-1.40.1.mjs
d835975a24c188f9f2b7b82e4a8a21cc2104d7f4c9aca56f532bc14dee6e4429 tools/verify-git-safety-regression.mjs
195af91a936d6d809967acaa18b230fc0a1723b94b4e21a22276e5c06af85ef5 tools/verify-git-safety.mjs
86a852edf45a0c6067f950eeadbcd599ae46d929c79cffd3a1ece82c3d554493 tools/verify-git-staging.mjs
1d4351e4a827e718766a1677ddfbc3771a91942d0d5a93753e39f1b99c68a4dd tools/verify-hotfix-1.23.2.mjs
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 tools/verify-identity-db-1.38.0.py
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 tools/verify-identity-db-1.39.0.py
2f43dd1a89a36527cd3b4873b8cc9f7386cdfc06ade96fcc05dd5deb15dbcec7 tools/verify-identity-db-1.40.0.py
1b5c21eb5688bc15895541968fa1ab69a2384ed611b01d23901abc040dcc3255 tools/verify-identity-settings-1.38.0.mjs
a1dddb35f4b6eeafe47ff3f40e5565bdb4477c8f63101d3c0d7f84c7393abe4c tools/verify-identity-settings-1.39.0.mjs
763bc084a0fd850ad35fb9bccd49f0ccd310eae77adc8573969cce1b7f9b5d3d tools/verify-identity-settings-1.40.0.mjs
44c95844422be3deaad6054ee3f0cced9c25986815d976e0c64b042d0c2c5e1e tools/verify-installer-shell.sh
a8760388717a464d532ceb5dfaa55ae327384631b6edd3fdd91387c952ec114c tools/verify-module-manager-1.40.0.mjs
cab03e98687af87f359f6424d440fc0b644da97b3c614509b8c7d008d4b18a8d tools/verify-platform-architecture-1.35.0.mjs
732bb15431746a829e45ae55c695360cbf1dd21d4fc3be26a98f35708d571e84 tools/verify-platform-architecture-1.36.0.mjs
ee8ae7bed4e93a2ef278662552a4ae5d751306aad7133a93f380bbf2a5d5a28c tools/verify-platform-architecture-1.37.0.mjs
584ea4735937238b4c3bffa70364d0f45cf1f3d41bf34adde64c7cbb7b729efa tools/verify-platform-architecture-1.38.0.mjs
f8590c6986786cbbce95e58af1d1d3fec61d163c19fcf4c22aff57f5954c398e tools/verify-platform-architecture-1.39.0.mjs
c9e704c372cf6a973fcdb887b337ead6509fd03e78570e6d1c9e24b1d879fe6b tools/verify-platform-architecture-1.40.0.mjs
36e35fedb08923c22fd8551389d33432b66dbd4215d95c594ef29bfc790c98e0 tools/verify-release-1.25.0.mjs
89621694b7bad18b6f3f1ac1956032f64112c40d3edc069ca581dc813d57d628 tools/verify-release-1.25.1-static.mjs
c908f5186cf2d71ef83d5e649327ae19965568933acfb32057ca00d29cf890bc tools/verify-release-1.25.1.mjs
e31a055d2ebb8e439f5b0e0235a71dacecb891e299377cfbbcfa8a32f53a85b0 tools/verify-release-1.26.0-static.mjs
7e107b5f9a1b4ee381ff31105feb6d38dda5c40e4afe105a955badc36e6b8d10 tools/verify-release-1.26.1-static.mjs
d9a75c45f40d857c84790d51dca2fd088c3851ca250405871a7e32773918c66e tools/verify-release-1.27.0.mjs
3989e3ec236c1aa4c387b26cc15e04cf200a018e29c095321acf826c6bae4d66 tools/verify-release-1.28.0.mjs
7d196d913a697248ab1233907fed56c10329cf201e3bdc173bca73cb02755369 tools/verify-release-1.29.0.mjs
3f30260dabbdf0fa7b042381cb9e24f840d0c3ddbc44fe309763789a7d14afb7 tools/verify-release-1.30.0.mjs
b1ceed5dfc17dbd3b038b7168e61076e4d39a0f1d67e2b87677a91c4dbb2daff tools/verify-release-1.31.0.mjs
a372258b97aa68d59a1fe0fd3f380d019c59412d5c408a6064f437d5cfc6e709 tools/verify-security-1.31.0.py
08820d9bb7be1dec496c04e9ea4a39b2ebb84d373a9481136610d16dea0edde3 tools/verify-security-foundation-1.37.0.mjs
a415d294679adab8ea76b86235a522e73ad9dd9ea0e2348691b1de3191255b81 tools/verify-security-foundation-1.38.0.mjs
805aa61d7f9cba8c20afda0dd871189108b02f3751f8a75963784cc12fd6cf76 tools/verify-security-foundation-1.39.0.mjs
23cb2414515011e8c3b277a50a9090593aa176fc9c9435c74cdd6d8117bac63f tools/verify-security-foundation-1.40.0.mjs
31a120622ce8bb8451014f2662366f81abd28d0f3be59adfe35d17e0ada1838f tools/verify-slice30-mock.mjs
20957a4a038b9afdb01a8c98b881644daf793d2a6bb778a4c8e04780687d00e4 tools/verify-slice31-image-editor.mjs
21061ed5dc88feef48e80efffd9a1054d38598dce5a5d3f9f6bde39b539b83f0 tools/verify-slice32-batch.mjs
0f05b1ac3b686cf535bcfb3e6f6df24a29c3429ade1b3c666c1b99abb1a7311b tools/verify-slice32-image-render.mjs
c9aa6693aa93ff1f220a2ce3bc35ef714a0b18a53eae0f907879fc92c66c1e38 tools/verify-theme-manager-1.36.0.mjs
1e61c4b180aa09de3dae9e72aef313b09a6f422229f180984b69a8d226e7cd8d tools/verify-theme-manager-1.37.0.mjs
3257b31d80034c077b25d3f1b13f8378378772bc6512445aa5ac8e882e4be109 tools/verify-theme-manager-1.38.0.mjs
41033ba36a11a14ab74a80d65c1124848eddee21a5f3fef8bd5ab001699e2e4b tools/verify-theme-manager-1.39.0.mjs
233070db91925520dc31131a55579bc83fdcd340e4d19e90510f089c060f0c43 tools/verify-theme-manager-1.40.0.mjs
0f3f684019763a14f5fbaec42e42c680cf748d930d46cd607fc61eb413ca4553 tools/verify-ui-contracts-1.26.1.mjs
0be781fa922c6c915b10730db1e3a01676cce4e65fd8cd216da5a9444f237f3c update-manifest.json
@@ -0,0 +1,14 @@
@echo off
setlocal EnableExtensions
chcp 65001 >nul
title Vendoo GitHub Deploy Assistent
cd /d "%~dp0"
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -STA -File "%~dp0scripts\github-deploy.ps1"
set "EXITCODE=%ERRORLEVEL%"
if not "%EXITCODE%"=="0" (
echo.
echo [FEHLER] GitHub-Deployment wurde mit Exit-Code %EXITCODE% beendet.
echo.
pause
)
exit /b %EXITCODE%
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

@@ -0,0 +1,351 @@
# Vendoo 1.40.1
Vendoo 1.40.1 ist ein Stabilitäts-Hotfix für den FLUX-Studio-Modullebenszyklus. Der Startfehler durch den fehlenden Export `stopFluxPromptJobLoop` ist behoben. Zusätzlich prüft ein neues ESM-Export-Vertragsgate alle lokalen benannten Imports gegen die tatsächlich vorhandenen Exporte. Die Funktionen des sicheren Modulmanagers aus 1.40.0 bleiben vollständig erhalten.
## FLUX-Worker-Hotfix 1.40.1
- fehlender `stopFluxPromptJobLoop`-Export ergänzt
- FLUX-Polling-Intervall wird beim Deaktivieren oder Stoppen sauber beendet
- erneutes Aktivieren bleibt idempotent
- ESM-Export-Vertragsgate verhindert künftig Import-/Export-Abweichungen vor Release und GitHub-Push
- keine Datenbankmigration und kein Reset
## Modulmanager 1.40.0
- 16 registrierte Module: 14 nativ, 2 kontrollierte Legacy Bridges
- geschützte Kernmodule können weder deaktiviert noch gelöscht werden
- optionale Vendoo-Module besitzen Abhängigkeitsprüfung und Kaskadensteuerung
- persistente Aktivierungszustände unter `config/modules-state.json`
- `.vmod`-Import und -Export mit SHA-256-Datei- und Paketintegrität
- deklarative Fremdmodule ohne ausführbaren Code
- ausführbare Fremdmodule nur mit vertrauenswürdiger Signatur und isoliertem Extension-Host; bis dahin Quarantäne
- installierte Fremdmodule lassen sich nach Deaktivierung entfernen
- Modulpakete und Zustände werden in Backup und Restore einbezogen
- persistenter Modulordner für Windows, Docker, NAS und VPS
- vollständige Architektur: `docs/architecture/MODULE_MANAGER_1_40_0.md`
## Native Publishing-, AI-, FLUX- und Quality-Lifecycles
- Publishing-Queue, AI-Modelljobs, Bild-Batch-Jobs und FLUX-Prompt-Jobs starten und stoppen über den jeweiligen Modullebenszyklus
- deaktivierte optionale Module sperren ihre APIs kontrolliert mit HTTP 503
- bestehende öffentliche API-Pfade bleiben kompatibel
- ausführende Bestandsprozessoren bleiben vorerst als interne Adapter erhalten und werden nicht doppelt gestartet
## Security Foundation ab 1.37.0
- AES-256-GCM-Secret-Speicher mit separatem Master-Key
- automatische Migration bestehender Runtime-Secrets mit Sicherungskopie
- strikte Script-CSP ohne Inline-Skripte oder Inline-Eventhandler
- strukturierte JSON-Telemetrie und Request-/Correlation-IDs
- zentrale Input-Schema-Validierung für neue Kernel-Routen
- erweitertes Security-Dashboard ohne Klartext-Secrets
Vendoo 1.36.0 führt den ersten vollständig nativen Fachbereich auf dem Plattformkernel ein: den **Secure Theme Manager**. Benutzer können ihre persönliche Darstellung über geprüfte Eingabemasken wählen; Administratoren verwalten sichere Theme-Profile und den Systemstandard. Freies CSS, JavaScript, URLs oder Dateipfade werden nicht akzeptiert.
## Theme Manager 1.36.0
- Light, Dark, System und High Contrast
- persönliche Theme-Auswahl pro Benutzer
- UI-Dichte und reduzierte Bewegung
- eigene Theme-Profile auf Basis eines geprüften Basisthemes
- Live-Vorschau ohne sofortige Speicherung
- serverseitige Token- und Kontrastprüfung
- Import und Export validierter Theme-Profile
- administrativer Systemstandard
- Audit-Protokoll für Änderungen
- 42 Design Tokens einschließlich Komponenten-, Fokus- und Zielgrößen-Tokens
Die Theme-Verwaltung erfolgt vollständig über Vendoo. Es ist keine manuelle Bearbeitung von CSS-, JSON- oder Konfigurationsdateien erforderlich.
## Plattformarchitektur ab 1.35.0
- Kernel: `app/kernel/`
- Modulmanifeste: `app/modules/*/module.json`
- Architekturgrenzen: `app/architecture-boundaries.json`
- Design-Token-Quelle: `public/design-system/tokens/source.json`
- Theme-Vertrag: `public/design-system/theme-contract.json`
- Architektur-Gate: `npm run verify:architecture`
- vollständige technische Dokumentation: `docs/architecture/`
Von sechzehn registrierten Modulen sind vierzehn nativ. Nur System und Operations bleiben transparent als `legacy-bridge` markiert. Drittanbieter-Code wird nicht im Vendoo-Hauptprozess ausgeführt.
## Einfachster Start
- **Windows lokal oder Docker Desktop:** `setup.bat` doppelklicken, Ziel und Netzwerkzugriff auswählen, **Installieren** anklicken.
- **Linux/NAS/VPS:** `chmod +x setup.sh && ./setup.sh`, danach den geführten Assistenten verwenden.
- **VPS:** Domain eingeben; der integrierte Caddy-Stack übernimmt HTTPS automatisch, sobald DNS sowie Ports 80/443 korrekt auf den Server zeigen.
- **GitHub-Erstimport:** `GitHub-Deploy-Assistent.bat` starten. Der Assistent prüft Secrets/Laufzeitdaten, erstellt einen Release-Branch und öffnet die Browser-Anmeldung für Git.
## Sicherheit
- `.env`, Datenbanken, Uploads, Backups, Logs, installierte Modulpakete, Operations-Laufzeitdaten und FLUX-/ComfyUI-Modelle werden niemals committed.
- Der Erst-Admin-Code wird zufällig erzeugt und auf Windows in die Zwischenablage kopiert.
- Öffentliche VPS-Installationen verwenden ausschließlich HTTPS und veröffentlichen Vendoo nicht direkt auf Port 8124.
- Updates und Betriebsartwechsel löschen keine persistenten Daten.
---
## Vorheriger Stand 1.31.0
Vendoo 1.31.0 schafft die Grundlage für einen kontrollierten Mehrbenutzer- und Serverbetrieb. Rollen und Berechtigungen werden nicht nur in der Oberfläche, sondern an jeder geschützten API erzwungen. Artikelbearbeitung wird mit kurzlebigen Sperren koordiniert; Sitzungen, fehlgeschlagene Logins, Audit-Ereignisse und Rate Limits sind nachvollziehbar.
## Rollen
- **Administrator:** vollständiger Zugriff einschließlich Benutzer, Backups, Updates und Sicherheit.
- **Manager:** operative Verwaltung von Artikeln, Medien und Publishing, ohne Benutzer- oder Systemadministration.
- **Editor:** Artikel, Bilder, AI, FLUX, Bildproduktion und Qualitätsprüfung.
- **Publisher:** Artikel lesen, Qualität prüfen und Veröffentlichungen ausführen.
- **Leser:** reiner Lesezugriff.
## Sicherer Netzwerkbetrieb
Standardmäßig bindet Vendoo ausschließlich an `127.0.0.1`. Einen privaten LAN-Zugriff aktiviert der Installationsassistent nur nach bewusster Auswahl und setzt die erforderlichen Werte automatisch. Für öffentlichen Zugriff verwendet der VPS-Assistent den getrennten Caddy-Stack mit HTTPS; Port 8124 wird dabei nicht direkt veröffentlicht.
## Bestehende Funktionen
Alle Funktionen aus 1.30.0 bleiben enthalten: Operations Center, Publishing Hardening, Quality Center, Batch Image Factory, FLUX Studio Pro, Advanced Image Editor, Galerie und Browser-Extensions.
## Betriebszentrale (1.30.0)
Unter **Admin → System** stehen jetzt drei zusammenhängende Bereiche bereit:
- **Backup & Restore** mit SQLite-Snapshot, Datei-Prüfsummen, Integritätsprüfung, Download, Rotation und Wiederherstellungs-Staging
- **Update Center** mit Versionsprüfung, Paketvalidierung, Migrationsstatus, Sicherheitsbackup und bewusstem Offline-Anwenden über `setup.bat`
- **Extension-Diagnose** mit Paketversionen, Heartbeats, zuletzt verbundenen Browsern und Live-/Offline-Status
Update und Wiederherstellung ersetzen niemals während des laufenden Servers Dateien. Nach erfolgreicher Prüfung wird eine Operation vorbereitet und anschließend bei beendetem Vendoo über Setup-Menüpunkt 11 angewendet. Menüpunkt 12 stellt den zuvor gesicherten Programm- und Datenstand wieder her.
## Sicherheitsprinzipien
- Keine direkte Kopie einer geöffneten SQLite-Datei; Backups verwenden die SQLite-Backup-API.
- Jedes Backup enthält ein Manifest mit SHA-256-Prüfsummen und wird sofort geprüft.
- Eine Wiederherstellung erzeugt vorab automatisch ein vollständiges Sicherheitsbackup.
- Update-ZIPs mit `.env`, Datenbank, Uploads oder `node_modules` werden abgelehnt.
- Zugangsdaten aus `.env` werden nur nach ausdrücklicher Auswahl in manuelle Backups aufgenommen.
- Automatische Backups enthalten niemals `.env`.
- Update und Restore besitzen einen lokalen Rollback-Snapshot.
## Publishing Hardening (1.29.0)
- persistente Publishing-Queue für API- und Extension-Aufträge
- Schutz vor Doppelveröffentlichungen
- automatische Wiederholungen mit wachsendem Abstand
- Abbruch, manueller Retry und sichere Protokolllöschung
- Fehlerzentrale mit Audit-Ereignissen
- externe IDs, URLs und eBay Offer-IDs
- eBay Statusabgleich, Aktualisierung und Beenden über offizielle API
- Etsy Statusabgleich über offizielle API
- Vinted/Kleinanzeigen als bestätigungspflichtiger Extension-Workflow
- Wiederaufnahme laufender API-Aufträge nach Vendoo-Neustart
- geplante Veröffentlichungen werden an dieselbe gehärtete Queue übergeben
Vendoo 1.28.0 ergänzt die produktive **Batch Image Factory**. Mehrere Bilder aus der zentralen Galerie können in einem persistenten Auftrag über ein oder mehrere Produktionsprofile für Marktplätze, Webshops und Social Media verarbeitet werden. Ergebnisse bleiben nicht destruktiv, erscheinen wieder in der Galerie und lassen sich gesammelt als ZIP exportieren.
## Batch Image Factory (1.28.0)
- Hauptmenü **Bildproduktion** mit Quellenwahl aus der zentralen Bildergalerie
- Acht integrierte Ausgabeprofile sowie eigene speicherbare Profile
- Mehrfachprofile pro Auftrag und bis zu 200 Quellbilder
- Hintergrundentfernung, Sensitivität und Wasserzeichen als globale Auftragsoptionen
- persistente Job- und Positionshistorie mit Pause, Fortsetzen, Abbruch und Retry
- Wiederaufnahme nach Vendoo-Neustart
- nicht destruktive Ergebnisse unter `uploads/batch/`
- automatische Galerieintegration und ZIP-Export pro Auftrag
## Neu in 1.12.0
Der mobile QR-Upload bietet nun zwei eindeutige Wege: **Kamera öffnen** und **Mediathek auswählen**. Dadurch erzwingt das Smartphone nicht mehr ausschließlich die Kamera. Mehrere vorhandene Bilder können direkt gewählt werden; HEIC/HEIF werden nach Möglichkeit serverseitig zu JPG konvertiert.
OpenRouter wurde zusätzlich gehärtet: Vendoo erkennt Free-Bildmodelle präziser, prüft Bildinput-Fähigkeit, versucht mehrere kompatible Request-Formen und wechselt bei Fehlern automatisch zum nächsten Modell. Sind aktuell keine kostenlosen Bildmodelle vorhanden, zeigt die Diagnose das ausdrücklich an.
## Neu in 1.11.0
Der QR-Handy-Upload erzeugt jetzt automatisch Links mit der erkannten LAN-IP des Vendoo-PCs. Unter **Einstellungen → Vendoo LAN-Adresse für QR-Upload** kann die Adresse erkannt, geprüft und dauerhaft gespeichert werden. Die mobile Navigation wurde für Smartphone und Tablet komplett stabilisiert. Bei OpenRouter-Bildgenerierung versucht Vendoo automatisch mehrere passende Free-Modelle nacheinander und nutzt im Auto-Modus anschließend OpenAI als Fallback.
## Neu in 1.10.0
Vendoo unterstützt jetzt eine **AI-Job-Queue** für Bildgenerierung. Kleidung kann mit **1 bis 3** Varianten als **Model**, **Ghost Mannequin** oder **Flatlay** generiert werden. Im Listing-Editor gibt es zusätzlich eine **Historie früherer AI-Generierungen**, damit erzeugte Bilder schnell wiederverwendet werden können.
## Neu in 1.9.0
Die Einstellungen wurden um ein eigenes Steuerzentrum für **AI-Model-Fotos** erweitert. Dort lassen sich Provider, Free-Filter, Safety-Blocker, Standard-Preset, Variantenanzahl und das OpenAI-Fallback-Modell pflegen. Zusätzlich kann die UI die aktuell verfügbaren OpenRouter-Bildmodelle direkt laden und anzeigen.
## Neu in 1.8.0
Vendoo kann jetzt neben OpenAI auch OpenRouter für AI-Model-Fotos verwenden. Wenn `ai_model_photo_provider=auto` gesetzt ist und `OPENROUTER_API_KEY` vorhanden ist, fragt Vendoo automatisch aktuelle Bildmodelle von OpenRouter ab, filtert auf Bildausgabe und sofern aktiviert nur kostenlose Varianten. Gibt es kein passendes freies Modell mehr, fällt Vendoo sauber auf OpenAI zurück.
### Neue relevante Settings
- `ai_model_photo_provider`: `auto`, `openrouter`, `openai`
- `ai_model_photo_openrouter_free_only`: `1` oder `0`
- `ai_model_photo_openrouter_model`: optional feste OpenRouter-Model-ID
- `ai_model_photo_openai_model`: OpenAI-Fallback-Modell, Default `gpt-image-1`
### Neue ENV-Variablen
- `OPENROUTER_API_KEY`
- optional `OPENROUTER_SITE_URL`
- optional `OPENROUTER_APP_NAME`
## Neu in 1.7.0
Vendoo kann jetzt für geeignete Kleidungsstücke sichere AI-Model-Fotos erzeugen. Der Workflow prüft zuerst, ob ein Kleidungsartikel ohne Person vorliegt, blockiert sensible Kategorien und erstellt danach 13 zusätzliche Lifestyle-/Studio-Bilder mit fiktiven erwachsenen Personen oder alternative Ghost-Mannequin-/Flatlay-Varianten. Die Bilder lassen sich direkt in Generator und Listing-Editor übernehmen.
## Neu in 1.26.0
- Hauptnavigation mit **Neuer Artikel** direkt unter dem Dashboard und **Artikel** statt Listings
- repariertes Publish Center mit zuverlässigem Smart-Copy-Popup
- zoombare Medienvorschau mit Fit, 100 %, Mausrad und Verschieben
- kompakte lokale SVG-Iconbibliothek für Galerieaktionen
- aktualisierte Verkäufergebühren für eBay, Vinted, Kleinanzeigen und Etsy
- eigenes Extension Center für Chrome, Edge, Firefox und Safari
# Vendoo
Lokaler Multi-Plattform Listing-Generator mit AI, Lagerverwaltung und Publishing-System.
## Aktueller Entwicklungsstand
- Version: `1.39.0`
- UI-Slice: `UI 2026 / Slice 07 Cross-Browser Extensions, Responsive UI & Mobile Upload`
- Startseite: `Studio Flow`
- Tech Stack: Node.js, Express (ESM), Vanilla JS, SQLite (`better-sqlite3`)
Die vollständige Funktionsbeschreibung steht in [`FEATURES.md`](FEATURES.md). Die freigegebene Designrichtung liegt unter [`MockupDesign/`](MockupDesign/). Der vollständige Listing-Editor ist in [`docs/FULL_LISTING_EDITOR_2026.md`](docs/FULL_LISTING_EDITOR_2026.md) dokumentiert.
## Lokaler Start
```bash
npm install
npm start
```
Danach ist Vendoo standardmäßig unter `http://localhost:8124` erreichbar.
## Wichtige Sicherheitsregel
Nicht versionieren oder weitergeben:
- `.env`
- `db/vendoo.db*`
- `uploads/`
- Backups und Logs
- API-Schlüssel, OAuth-Tokens und SMTP-Passwörter
Die bereitgestellte Projektversion enthält ausschließlich `.env.example` und keine produktiven Laufzeitdaten.
## Browser-Erweiterungen
Die aktuellen Erweiterungen liegen getrennt unter `extensions/chrome`, `extensions/edge`, `extensions/firefox` und `extensions/safari`. Über den Vendoo-Menüpunkt **Extensions** wird der aktive Browser erkannt, der Installationsordner geöffnet und der Pfad kopiert. Safari benötigt auf macOS zusätzlich Xcode und die mitgelieferte WebExtension-Konvertierung.
## Mobiler Foto-Upload
Im Generator und im Listing-Editor kann ein zeitlich begrenzter QR-Code erzeugt werden. Nach dem Scan können Fotos direkt vom Smartphone aufgenommen und ohne Neuladen an Vendoo übertragen werden. Für andere Geräte muss Vendoo über eine erreichbare LAN-IP oder `PUBLIC_BASE_URL` geöffnet sein; `localhost` funktioniert nur auf demselben Gerät.
## Browser-Erweiterung 1.4.0
Die Erweiterungen für Chrome, Edge und Firefox verwenden jetzt eine kompakte, aktionsorientierte Oberfläche. Die primäre Aktion **Nur ausfüllen** trägt ein Listing in das geöffnete Vinted-Formular ein, ohne einen Entwurf zu speichern und ohne eine Veröffentlichung auszulösen. Abschlussaktionen sind davon deutlich getrennt.
## Aktueller UI-Stand
Slice 10 ergänzt das interaktive Dashboard, den aufgeräumten Studio Flow, robuste Publish-Initialisierung, ZIP-Fotodownloads und erweiterte Responsive-Gates.
## Branding
Logo, App-Icons, mobile Größen und Favicons liegen unter `public/brand/`. Die Browser-Erweiterungen für Chrome, Edge und Firefox verwenden dieselbe Icon-Familie.
## Local FLUX / ComfyUI
Vendoo can now prefer a local image backend for AI model photos. The intended order is: **Local FLUX / ComfyUI -> OpenRouter Free -> OpenAI**.
### What was added
- Settings for local URL, token, workflow path and install path
- Backend-only access to the local image server
- PowerShell bootstrap via `setup.ps1` or Settings UI
- Token regeneration for restricted local access
### Default assumptions
- ComfyUI is reachable at `http://127.0.0.1:8188`
- Workflow file: `local-ai/workflows/vendoo_flux_schnell_api.json`
- Vendoo talks to the local server from the backend, not directly from the browser
> Note: the included workflow template is a bootstrap starter and may need adjustment to the exact ComfyUI / FLUX node setup on the target machine.
## Vollautomatische lokale FLUX-Installation
Vendoo kann ComfyUI Portable und optional FLUX.1-schnell FP8 direkt aus der Einstellungsseite oder über `setup.bat` installieren.
### Über die Benutzeroberfläche
1. **Einstellungen → AI-Model-Fotos** öffnen.
2. Als Provider `Auto` oder `Nur lokales FLUX / ComfyUI` auswählen.
3. Installationsoptionen wählen.
4. **Lokales FLUX installieren** anklicken.
5. Den Fortschritt direkt in Vendoo verfolgen.
### Über setup.bat
- `7` lokales FLUX / ComfyUI installieren oder aktualisieren
- `8` Status anzeigen
- `9` lokalen Server starten
- `10` lokalen Server stoppen
### Sicherheitsmodell
ComfyUI wird ausschließlich an `127.0.0.1:8188` gebunden. Der Browser greift nicht direkt auf ComfyUI zu; nur das Vendoo-Backend sendet Bildjobs. Standardmäßig werden Remote-URLs abgelehnt. Ein zufälliger lokaler Token wird zusätzlich in der `.env` gespeichert. Das schützt den Dienst vor Zugriff aus dem LAN, ersetzt aber keine vollständige Prozessisolation gegenüber anderer Software auf demselben Windows-PC.
### Große Downloads
Der Modell-Download ist optional und wird vor dem Start ausdrücklich bestätigt. Bereits vorhandene ComfyUI- oder Modelldateien werden nicht ohne `Force` überschrieben. Downloads und Installationsfortschritt werden protokolliert.
## FLUX installer status and recovery
The local FLUX installer now records a detailed, resumable state in `local-ai/install-state.json`. The settings page displays individual checks for 7-Zip, the ComfyUI archive, embedded Python, ComfyUI, the FLUX model, workflow and runtime scripts. Failed installations can be started again without blindly discarding complete downloads.
The PowerShell 5.1 path bug that could turn `C:\Program Files\7-Zip\7z.exe` into the command `C` has been fixed.
## FLUX installer status hotfix (1.14.2)
The local FLUX installer now supervises 7-Zip instead of waiting without feedback. During extraction Vendoo shows files, extracted MB, elapsed time, heartbeat and the current 7-Zip log. A stale installer is marked as **stalled** and can be resumed without downloading the complete ComfyUI archive again.
## FLUX Studio ab 1.21.0
Vendoo enthält einen eigenen Hauptmenüpunkt **FLUX Studio**. Dort werden Bilder ausschließlich aus freien Prompts über das lokale ComfyUI/FLUX erzeugt. Einstellbar sind Stil, Ausgabeformat, Seed und Inferenzschritte. Ergebnisse werden in einer lokalen Bibliothek gespeichert, können heruntergeladen, in den Listing-Generator übernommen oder mit dem integrierten Editor nachbearbeitet werden.
Der frühere FASHN-/Virtual-Try-on-Stack wurde vollständig aufgegeben. Es werden kein Python-, Torch-, ONNX- oder separater VTO-Dienst mehr installiert. Beim ersten Start des aktualisierten Setups werden alte VTO-Runtime, Autostarts und Einstellungen entfernt; eigene frühere Modelbilder werden zur Sicherheit nach `uploads/ai-generated/legacy-models` verschoben.
### Update
1. Vendoo schließen.
2. Paketinhalt über die bestehende Installation kopieren und Dateien ersetzen.
3. `setup.bat` starten und **Reparieren** ausführen.
4. Vendoo starten und den Menüpunkt **FLUX Studio** öffnen.
## FLUX Studio Pro ab 1.22.0
Slice 30 erweitert das reine Prompt-Studio zu einem persistenten Job-Center. Aufträge können 1, 2 oder 4 Varianten mit eigenen Seeds erzeugen. Seed Lock, Wiederholen, „Ähnlich erneut erzeugen“, Favoriten, Queue-/History-Anbindung, System-/GPU-Daten und Wiederaufnahme nach Vendoo-Neustart sind integriert.
Die Fortschrittsanzeige verwendet im FLUX-Studio-Pro-Pfad ausschließlich reale Phasen und verstrichene Laufzeit. Es werden keine Prozentwerte aus einer angenommenen Renderdauer errechnet.
### Update auf 1.22.0
1. Vendoo und ComfyUI-Fenster schließen.
2. Den Inhalt des Paket-Unterordners `vendoo` über die bestehende Installation kopieren und Dateien ersetzen.
3. Den bestehenden Zielordner und Laufzeitdaten nicht löschen.
4. `setup.bat` starten und **3 Update** ausführen.
5. Bei Bedarf **9 Lokales FLUX / ComfyUI starten**, danach **8 Status** prüfen.
6. Vendoo starten und FLUX Studio öffnen.
## Artikel Quality Center
Vendoo 1.28.0 prüft Artikel vor dem Publishing auf Blocker, Vollständigkeit, Bildqualität, mögliche Duplikate und Plattformtauglichkeit. AI-Verbesserungen werden nur als Vorschlag angezeigt und erst nach ausdrücklicher Bestätigung gespeichert.
## Installationsziel wählen (1.36.0)
`setup.bat` führt auf Windows durch lokale Node-Installation oder Docker Desktop. Für Linux, NAS, Portainer und VPS steht `setup.sh` bereit. Beide Wege verwenden dieselbe `.env`, dieselben Compose-Dateien und dieselben persistenten Datenbereiche.
@@ -0,0 +1,129 @@
# Sicherheit
## Vertrauliche Dateien
Folgende Dateien dürfen niemals in Git oder öffentliche Pakete gelangen:
- `.env`
- `db/*.db`, `db/*.db-wal`, `db/*.db-shm`
- `uploads/`
- Backups, Logs und Session-Daten
- private Schlüssel und Zertifikate
## Online-Betrieb
Vendoo darf nicht durch eine direkte Portfreigabe von Port 8124 veröffentlicht werden. Für öffentliche Nutzer ist eine getrennte Server-/VPS-Instanz hinter HTTPS und Reverse Proxy vorgesehen.
## Meldung von Sicherheitsproblemen
Sicherheitsprobleme nicht mit Zugangsdaten oder personenbezogenen Daten in öffentliche Issues schreiben.
## Lokaler FLUX / ComfyUI
- ComfyUI wird standardmäßig nur an `127.0.0.1` gebunden.
- Vendoo blockiert Remote-ComfyUI-URLs, solange `LOCAL_IMAGE_ALLOW_REMOTE` nicht ausdrücklich aktiviert wird.
- Die ComfyUI-Oberfläche wird nicht über das LAN veröffentlicht.
- API-Aufrufe erfolgen serverseitig durch Vendoo.
- Ein zufälliger Token wird für die lokale Integrationskonfiguration erzeugt.
- Andere Prozesse auf demselben Windows-Rechner können theoretisch ebenfalls auf einen localhost-Dienst zugreifen; für echte Prozessisolation wäre ein separates Windows-Konto oder eine VM erforderlich.
## ESM-Modulverträge ab 1.40.1
- lokale benannte ESM-Imports werden vor CI und Release gegen die tatsächlich exportierten Symbole geprüft
- fehlende Exporte blockieren den Build vor der Auslieferung
- Worker-Start- und Stop-Verträge werden separat geprüft
## FLUX Studio
- ComfyUI bleibt standardmäßig ausschließlich an `127.0.0.1` gebunden.
- Das FLUX Studio akzeptiert nur Textprompts und erzeugt Dateien unter `uploads/ai-generated`.
- API-Pfade für Bibliothek und Bearbeitungen werden serverseitig auf dieses Verzeichnis begrenzt.
- Start und Stopp der lokalen Engine erfordern eine Admin-Rolle.
- Bearbeitungen erzeugen neue Dateien; Originalausgaben werden nicht still überschrieben.
## Operations Center, Backups und Updates
- Backups werden mit einem Manifest und SHA-256-Prüfsummen erzeugt und vor der Freigabe verifiziert.
- Sicherungen, die `.env` enthalten, enthalten möglicherweise API-Schlüssel, Tokens und Zugangsdaten. Sie sind wie Passwörter zu behandeln und dürfen nicht unverschlüsselt weitergegeben werden.
- Restore- und Update-Archive werden vor der Anwendung in einem lokalen Staging-Bereich geprüft.
- Archive mit Pfad-Traversal, absoluten Pfaden oder unzulässigen Laufzeitdaten werden abgewiesen.
- Updates dürfen keine `.env`, produktive Datenbank, Uploads, Backups, Logs, Modelle oder `node_modules` mitbringen.
- Das eigentliche Anwenden erfolgt nur bei gestopptem Vendoo über `setup.bat` und erzeugt vorher einen Rollback-Snapshot.
- Eine optionale Update-Manifest-URL sollte ausschließlich über HTTPS und aus einer kontrollierten Quelle verwendet werden.
- Extension-Heartbeats enthalten nur Diagnosemetadaten wie Browser, Version, Plattform und Zeitpunkt; keine Formularinhalte oder Zugangsdaten.
## Mehrbenutzer- und Server-Sicherheit ab 1.31.0
- Vendoo bindet standardmäßig an `127.0.0.1`. LAN-Zugriff muss ausdrücklich über `VENDOO_BIND_HOST=0.0.0.0` aktiviert werden.
- Öffentlicher Betrieb ausschließlich über HTTPS und einen korrekt konfigurierten Reverse Proxy. `VENDOO_TRUST_PROXY=true` nur setzen, wenn der Proxy vertrauenswürdig ist und Client-IP-Header kontrolliert.
- `VENDOO_ALLOWED_HOSTS` und `VENDOO_ALLOWED_ORIGINS` eng begrenzen.
- Rollen ersetzen keine Betriebssystemrechte: Datenbank, `.env`, Backups und Uploads müssen auf Dateisystemebene geschützt bleiben.
- Bearbeitungssperren verhindern parallele Änderungen, ersetzen aber keine Backups.
- Audit-Logs können personenbezogene Betriebsdaten wie Benutzer, IP und Aktionen enthalten; Aufbewahrung und Zugriff müssen organisatorisch geregelt werden.
## Architektur-Sicherheitsregeln ab 1.35.0
- Neue Kernel-Routen sind Deny-by-default und benötigen eine registrierte Policy.
- Modulmanifeste, Abhängigkeiten, Capabilities und Ownership werden vor dem Start validiert.
- Zyklische Abhängigkeiten, fehlende Capabilities und doppelte Ressourcen-Ownership blockieren den Kernelstart.
- Drittanbieter-Erweiterungen dürfen nicht im Vendoo-Hauptprozess ausgeführt werden.
- Themes dürfen nur freigegebene, typisierte Design Tokens verändern; freies CSS, JavaScript und externe URLs sind verboten.
- Der Event Bus ordnet Listener einem Owner zu, damit Module beim Stoppen ihre Listener vollständig entfernen können.
- Das Architektur-Gate `npm run verify:architecture` ist verpflichtender Bestandteil von CI und Releases.
## Theme-Sicherheit ab 1.36.0
- Theme-Profile akzeptieren ausschließlich bekannte, typisierte Design Tokens.
- Freies CSS, JavaScript, HTML, URLs und Dateipfade sind nicht zulässig.
- Alle Werte werden im Browser zur Benutzerführung und erneut auf dem Server validiert.
- Normale Benutzer können nur die eigene Theme-Präferenz verändern.
- Theme-Profile und Systemstandard erfordern `settings.manage`.
- Theme-Änderungen werden auditiert.
- Importierte Profile durchlaufen dieselbe Validierung wie manuell erstellte Profile.
- Kontrastprüfungen verhindern nicht automatisch jede bewusste administrative Gestaltung, zeigen problematische Paare aber vor dem Speichern deutlich an.
## Security Foundation ab 1.37.0
Zugangsdaten werden bevorzugt im verschlüsselten Secret-Speicher unter dem persistenten Konfigurationsbereich abgelegt. Die Verschlüsselung verwendet AES-256-GCM; der Master-Key liegt getrennt und wird nicht in Git oder Release-Pakete aufgenommen. Bestehende Secrets aus der Runtime-Konfiguration werden beim ersten Start gesichert, verschlüsselt migriert und aus der Klartextdatei entfernt.
Die Weboberfläche verwendet eine erzwungene Content Security Policy ohne Inline-Skripte und Inline-Eventhandler. Request- und Correlation-IDs werden in Antworten ausgegeben und in der strukturierten Telemetrie geführt.
## Identity- und Settings-Sicherheit ab 1.38.0
- Auth, Benutzer, Sitzungen und Einstellungen laufen als native Module über explizite Policies und Eingabeschemata.
- Der letzte aktive Administrator kann nicht gelöscht, deaktiviert oder zu einer Nicht-Admin-Rolle herabgestuft werden.
- Benutzer können nur Sitzungen widerrufen, die ihrer eigenen Benutzer-ID gehören; administrative globale Revocation erfordert `sessions.manage`.
- Login-Historie erfordert `users.manage`, SMTP-Verwaltung `settings.manage`.
- Die Settings-Allowlist weist unbekannte oder nicht freigegebene Felder zurück.
- Passwort-Hashes, Session-Tokens und Secret-Klarwerte dürfen nicht in Listen-, Status- oder Audit-Antworten erscheinen.
- `lib/auth.mjs` ist nur noch eine Kompatibilitätsfassade; neue Identitätslogik gehört in die nativen Module.
## Catalog- und Medien-Sicherheit ab 1.39.0
- Artikelrouten verwenden explizite Policies für Lesen, Bearbeiten, Papierkorb und endgültiges Löschen.
- Unbekannte Artikel-, Lager- und Medienfelder werden abgewiesen.
- Rich-HTML wird serverseitig bereinigt; Preise, Texte, Tags und Fotolisten besitzen feste Grenzen.
- Endgültiges Löschen ist nur für bereits im Papierkorb befindliche Artikel möglich.
- Lager-Bulk-Aktionen sind auf 500 eindeutige positive Artikel-IDs begrenzt.
- Medienpfade werden normalisiert und gegen Traversal, Nullbytes sowie Zeilenumbrüche geprüft.
- Von aktiven Artikeln referenzierte Bilder sind beim Löschen geschützt.
- Modulimporte initialisieren keine Datenbank; Repositories werden beim Serverstart injiziert.
## Modulsicherheit ab 1.40.0
- Kernmodule sind geschützt und können weder deaktiviert noch gelöscht werden.
- Aktivierungszustände werden atomar im persistenten Konfigurationsbereich gespeichert.
- `.vmod`-Pakete werden auf Format, Manifest, Pfade, Dateigrößen, Einzeldatei-SHA-256 und Gesamtintegrität geprüft.
- Installierbare Fremdmodule müssen den Typ `extension-host` verwenden.
- Deklarative Pakete dürfen keine JavaScript-, Shell-, Native- oder Binärdateien enthalten.
- Ausführbare Pakete benötigen eine vertrauenswürdige Ed25519-Signatur und dürfen ausschließlich in einem isolierten Extension-Host laufen. Solange dieser Host nicht freigegeben ist, bleiben solche Pakete deaktiviert und quarantänisiert.
- Fremdmodule werden niemals durch bloßes Kopieren automatisch registriert oder aktiviert.
- Abhängigkeiten werden vor Aktivierung geprüft; geschützte Abhängigkeiten verhindern unsichere Deaktivierung.
- Installierte Modulpakete und `modules-state.json` werden gemeinsam gesichert und wiederhergestellt.
- Der Laufzeitordner `modules/` ist von Git-Import und Release-Paketen ausgeschlossen.
@@ -0,0 +1,13 @@
# Drittanbieter-Hinweise für lokale AI-Engines
## FLUX / ComfyUI
Vendoo kann eine lokale ComfyUI-Installation mit einem FLUX-kompatiblen Modell ansteuern. ComfyUI, Modelle, Custom Nodes und deren Gewichte werden nicht als Vendoo-eigene Software ausgegeben. Für jede installierte Komponente gelten die jeweiligen Lizenz- und Nutzungsbedingungen der Herausgeber.
Vendoo liefert keine FASHN-VTON-, Python-, Torch-, ONNX- oder Human-Parser-Komponenten mehr aus und installiert diese auch nicht mehr.
## Lucide Icons
Die lokale Vendoo-Iconbibliothek verwendet eine kompakte Auswahl von Lucide-Icon-Geometrien.
Lucide steht unter der ISC-Lizenz. Projekt: https://lucide.dev/
@@ -0,0 +1,38 @@
{
"schemaVersion": 2,
"architecture": "modular-monolith",
"rules": {
"modulePrefix": "vendoo.",
"denyImplicitRoutes": true,
"denyCrossModuleDatabaseAccess": true,
"denyCrossModuleInternalImports": true,
"thirdPartyExtensionsInMainProcess": false,
"themeCustomCss": false,
"themeTokensOnly": true,
"denyUnknownSettings": true,
"sessionOwnershipRequired": true,
"lastActiveAdminProtected": true,
"catalogPayloadAllowlist": true,
"mediaReferenceProtection": true,
"inventoryBulkLimit": 500
},
"nativeModules": [
"vendoo.auth",
"vendoo.users",
"vendoo.sessions",
"vendoo.settings",
"vendoo.security",
"vendoo.themes",
"vendoo.media",
"vendoo.listings",
"vendoo.inventory"
],
"migration": {
"mode": "strangler",
"legacyBridgeStatus": "legacy-bridge",
"frameworkMigration": false,
"databaseReplacement": false,
"identityCompatibilityFacade": "lib/auth.mjs",
"catalogCompatibilityLayer": "lib/db.mjs"
}
}
@@ -0,0 +1,34 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://vendoo.local/contracts/module.schema.json",
"title": "Vendoo Module Manifest",
"type": "object",
"additionalProperties": false,
"required": ["schemaVersion", "id", "name", "version", "type", "status", "requires", "permissions", "provides", "consumes", "owns"],
"properties": {
"schemaVersion": { "const": 1 },
"id": { "type": "string", "pattern": "^vendoo\\.[a-z][a-z0-9-]*$" },
"name": { "type": "string", "minLength": 1, "maxLength": 80 },
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$" },
"type": { "enum": ["core", "feature", "adapter", "extension-host"] },
"status": { "enum": ["native", "legacy-bridge", "disabled"] },
"description": { "type": "string", "maxLength": 500 },
"requires": { "$ref": "#/$defs/moduleIds" },
"permissions": { "$ref": "#/$defs/capabilities" },
"provides": { "$ref": "#/$defs/capabilities" },
"consumes": { "$ref": "#/$defs/capabilities" },
"owns": { "$ref": "#/$defs/capabilities" }
},
"$defs": {
"moduleIds": {
"type": "array",
"uniqueItems": true,
"items": { "type": "string", "pattern": "^vendoo\\.[a-z][a-z0-9-]*$" }
},
"capabilities": {
"type": "array",
"uniqueItems": true,
"items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(?:\\.[a-z][a-z0-9-]*)+$" }
}
}
}
@@ -0,0 +1,386 @@
import { db } from '../../../lib/db.mjs';
import { createHash, randomBytes, scryptSync, timingSafeEqual } from 'crypto';
// --- Schema ---
db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL DEFAULT '',
password_hash TEXT,
role TEXT NOT NULL DEFAULT 'editor',
active INTEGER NOT NULL DEFAULT 1,
avatar_color TEXT,
last_active_at TEXT,
created_at TEXT DEFAULT (datetime('now')),
invited_by INTEGER,
FOREIGN KEY (invited_by) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
token_hash TEXT UNIQUE NOT NULL,
ip TEXT,
user_agent TEXT,
expires_at TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS auth_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL,
token_hash TEXT UNIQUE NOT NULL,
type TEXT NOT NULL DEFAULT 'login',
role TEXT DEFAULT 'editor',
used INTEGER NOT NULL DEFAULT 0,
expires_at TEXT NOT NULL,
created_by INTEGER,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (created_by) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
user_email TEXT,
action TEXT NOT NULL,
target_type TEXT,
target_id TEXT,
details TEXT,
ip TEXT,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS login_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
ip TEXT,
user_agent TEXT,
success INTEGER NOT NULL DEFAULT 1,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
`);
// Migration: add password_hash column if missing
try { db.exec("ALTER TABLE users ADD COLUMN password_hash TEXT"); } catch {}
try { db.exec("ALTER TABLE users ADD COLUMN failed_login_count INTEGER NOT NULL DEFAULT 0"); } catch {}
try { db.exec("ALTER TABLE users ADD COLUMN locked_until TEXT"); } catch {}
try { db.exec("ALTER TABLE users ADD COLUMN password_changed_at TEXT"); } catch {}
try { db.exec("ALTER TABLE sessions ADD COLUMN last_seen_at TEXT"); } catch {}
try { db.exec("ALTER TABLE sessions ADD COLUMN revoked_at TEXT"); } catch {}
try { db.exec("UPDATE sessions SET last_seen_at = COALESCE(last_seen_at, created_at)"); } catch {}
const AVATAR_COLORS = [
'#4a7c59', '#2d6a9f', '#8b5a3c', '#6b4c8a', '#c4713b',
'#3a8c7a', '#7c4d6e', '#5a7c3a', '#8c5a5a', '#3a6b8c',
];
const SESSION_DURATION_MS = Math.max(1, Number(process.env.VENDOO_SESSION_DAYS || 3)) * 24 * 60 * 60 * 1000;
const SESSION_IDLE_MS = Math.max(10, Number(process.env.VENDOO_SESSION_IDLE_MINUTES || 120)) * 60 * 1000;
const SESSION_TOUCH_INTERVAL_MS = 60 * 1000;
const LOGIN_TOKEN_EXPIRY_MIN = 15;
const INVITE_TOKEN_EXPIRY_HOURS = 48;
function hashToken(token) {
return createHash('sha256').update(token).digest('hex');
}
function generateToken() {
return randomBytes(32).toString('hex');
}
function randomAvatarColor() {
return AVATAR_COLORS[Math.floor(Math.random() * AVATAR_COLORS.length)];
}
// --- Password Hashing (scrypt) ---
export function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const hash = scryptSync(password, salt, 64).toString('hex');
return `${salt}:${hash}`;
}
export function verifyPassword(password, storedHash) {
if (!storedHash) return false;
const [salt, hash] = storedHash.split(':');
if (!salt || !hash) return false;
const hashBuf = Buffer.from(hash, 'hex');
const supplied = scryptSync(password, salt, 64);
return timingSafeEqual(hashBuf, supplied);
}
// --- Users ---
export function createUser(email, name, role = 'editor', invitedBy = null, password = null) {
role = ['admin', 'manager', 'editor', 'publisher', 'viewer'].includes(role) ? role : 'editor';
const existing = db.prepare('SELECT id FROM users WHERE email = ?').get(email);
if (existing) throw new Error('User existiert bereits');
const color = randomAvatarColor();
const pwHash = password ? hashPassword(password) : null;
const r = db.prepare('INSERT INTO users (email, name, role, avatar_color, invited_by, password_hash) VALUES (?, ?, ?, ?, ?, ?)').run(email, name, role, color, invitedBy, pwHash);
return getUser(r.lastInsertRowid);
}
export function setPassword(userId, password) {
const pwHash = hashPassword(password);
db.prepare("UPDATE users SET password_hash = ?, password_changed_at = datetime('now'), failed_login_count = 0, locked_until = NULL WHERE id = ?").run(pwHash, userId);
destroyUserSessions(userId);
}
export function validatePasswordStrength(password) {
const value = String(password || '');
const problems = [];
if (value.length < 10) problems.push('mindestens 10 Zeichen');
if (!/[a-z]/.test(value)) problems.push('einen Kleinbuchstaben');
if (!/[A-Z]/.test(value)) problems.push('einen Großbuchstaben');
if (!/\d/.test(value)) problems.push('eine Zahl');
if (!/[^A-Za-z0-9]/.test(value)) problems.push('ein Sonderzeichen');
return { valid: problems.length === 0, problems };
}
export function registerFailedLogin(userId, maxAttempts = 8, lockMinutes = 15) {
if (!userId) return null;
const user = getUser(userId);
if (!user) return null;
const count = Number(user.failed_login_count || 0) + 1;
if (count >= maxAttempts) {
const lockedUntil = new Date(Date.now() + lockMinutes * 60 * 1000).toISOString();
db.prepare('UPDATE users SET failed_login_count = 0, locked_until = ? WHERE id = ?').run(lockedUntil, userId);
destroyUserSessions(userId);
return { locked: true, lockedUntil };
}
db.prepare('UPDATE users SET failed_login_count = ? WHERE id = ?').run(count, userId);
return { locked: false, remaining: Math.max(0, maxAttempts - count) };
}
export function clearFailedLogins(userId) {
if (!userId) return;
db.prepare('UPDATE users SET failed_login_count = 0, locked_until = NULL WHERE id = ?').run(userId);
}
export function isUserLocked(user) {
if (!user?.locked_until) return false;
const until = Date.parse(user.locked_until);
if (!Number.isFinite(until) || until <= Date.now()) {
clearFailedLogins(user.id);
return false;
}
return true;
}
export function getUser(id) {
return db.prepare('SELECT * FROM users WHERE id = ?').get(id);
}
export function getUserByEmail(email) {
return db.prepare('SELECT * FROM users WHERE email = ? COLLATE NOCASE').get(email);
}
export function getUsers() {
return db.prepare("SELECT id, email, name, role, active, avatar_color, last_active_at, created_at, locked_until, failed_login_count, CASE WHEN password_hash IS NOT NULL AND password_hash != '' THEN 1 ELSE 0 END as has_password FROM users ORDER BY created_at").all();
}
export function updateUser(id, data) {
const allowed = ['name', 'role', 'active', 'avatar_color'];
const fields = [], values = [];
for (const [k, rawValue] of Object.entries(data)) {
if (!allowed.includes(k) || rawValue === undefined) continue;
const v = k === 'role' ? (['admin', 'manager', 'editor', 'publisher', 'viewer'].includes(rawValue) ? rawValue : 'viewer') : rawValue;
fields.push(`${k} = ?`); values.push(v);
}
if (!fields.length) return getUsers().find(user => Number(user.id) === Number(id)) || null;
values.push(id);
db.prepare(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(...values);
return getUsers().find(user => Number(user.id) === Number(id)) || null;
}
export function deleteUser(id) {
db.prepare('DELETE FROM sessions WHERE user_id = ?').run(id);
db.prepare('DELETE FROM users WHERE id = ?').run(id);
}
export function touchUserActivity(userId) {
db.prepare("UPDATE users SET last_active_at = datetime('now') WHERE id = ?").run(userId);
}
export function getUserCount() {
return db.prepare('SELECT COUNT(*) as count FROM users').get().count;
}
// --- Sessions ---
export function createSession(userId, ip, userAgent) {
const token = generateToken();
const hash = hashToken(token);
const now = new Date();
const expiresAt = new Date(now.getTime() + SESSION_DURATION_MS).toISOString();
const lastSeenAt = now.toISOString();
db.prepare('INSERT INTO sessions (user_id, token_hash, ip, user_agent, expires_at, last_seen_at, revoked_at) VALUES (?, ?, ?, ?, ?, ?, NULL)').run(userId, hash, ip, userAgent || '', expiresAt, lastSeenAt);
return { token, expiresAt };
}
export function validateSession(token) {
if (!token) return null;
const hash = hashToken(token);
const session = db.prepare("SELECT s.*, u.email, u.name, u.role, u.active, u.avatar_color, u.locked_until FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.token_hash = ? AND s.revoked_at IS NULL AND s.expires_at > datetime('now')").get(hash);
if (!session || !session.active || isUserLocked(session)) return null;
const lastSeen = Date.parse(session.last_seen_at || session.created_at || 0);
if (Number.isFinite(lastSeen) && Date.now() - lastSeen > SESSION_IDLE_MS) {
db.prepare("UPDATE sessions SET revoked_at = datetime('now') WHERE id = ?").run(session.id);
return null;
}
if (!Number.isFinite(lastSeen) || Date.now() - lastSeen >= SESSION_TOUCH_INTERVAL_MS) {
const now = new Date().toISOString();
db.prepare('UPDATE sessions SET last_seen_at = ? WHERE id = ?').run(now, session.id);
session.last_seen_at = now;
touchUserActivity(session.user_id);
}
return session;
}
export function destroySession(token) {
const hash = hashToken(token);
db.prepare("UPDATE sessions SET revoked_at = datetime('now') WHERE token_hash = ?").run(hash);
}
export function destroySessionById(id) {
db.prepare("UPDATE sessions SET revoked_at = datetime('now') WHERE id = ?").run(id);
}
export function getSessionById(id) {
return db.prepare("SELECT s.id, s.user_id, s.ip, s.user_agent, s.created_at, s.last_seen_at, s.expires_at, s.revoked_at, u.email, u.name, u.role FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.id = ?").get(id);
}
export function destroyOwnedSessionById(userId, id) {
const result = db.prepare("UPDATE sessions SET revoked_at = datetime('now') WHERE id = ? AND user_id = ? AND revoked_at IS NULL").run(id, userId);
return Number(result.changes || 0);
}
export function destroyUserSessions(userId) {
db.prepare("UPDATE sessions SET revoked_at = datetime('now') WHERE user_id = ? AND revoked_at IS NULL").run(userId);
}
export function getUserSessions(userId) {
return db.prepare("SELECT id, ip, user_agent, created_at, last_seen_at, expires_at FROM sessions WHERE user_id = ? AND revoked_at IS NULL AND expires_at > datetime('now') ORDER BY created_at DESC").all(userId);
}
export function getAllActiveSessions() {
return db.prepare("SELECT s.id, s.user_id, s.ip, s.user_agent, s.created_at, s.last_seen_at, s.expires_at, u.email, u.name, u.role FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.revoked_at IS NULL AND s.expires_at > datetime('now') ORDER BY s.created_at DESC").all();
}
// clean expired sessions periodically
export function cleanExpiredSessions() {
db.prepare("DELETE FROM sessions WHERE expires_at <= datetime('now') OR (revoked_at IS NOT NULL AND revoked_at <= datetime('now', '-7 days'))").run();
}
// --- Auth Tokens (Magic Links) ---
export function createAuthToken(email, type = 'login', role = 'editor', createdBy = null) {
const token = generateToken();
const hash = hashToken(token);
const minutes = type === 'invite' ? INVITE_TOKEN_EXPIRY_HOURS * 60 : LOGIN_TOKEN_EXPIRY_MIN;
const expiresAt = new Date(Date.now() + minutes * 60 * 1000).toISOString();
// invalidate previous unused tokens of same type for same email
db.prepare("UPDATE auth_tokens SET used = 1 WHERE email = ? COLLATE NOCASE AND type = ? AND used = 0").run(email, type);
db.prepare('INSERT INTO auth_tokens (email, token_hash, type, role, expires_at, created_by) VALUES (?, ?, ?, ?, ?, ?)').run(email, hash, type, role, expiresAt, createdBy);
return { token, expiresAt };
}
export function validateAuthToken(token) {
const hash = hashToken(token);
const row = db.prepare("SELECT * FROM auth_tokens WHERE token_hash = ? AND used = 0 AND expires_at > datetime('now')").get(hash);
if (!row) return null;
db.prepare('UPDATE auth_tokens SET used = 1 WHERE id = ?').run(row.id);
return row;
}
// --- Rate Limiting ---
const rateLimits = new Map();
export function checkRateLimit(key, maxAttempts = 5, windowMs = 15 * 60 * 1000) {
const now = Date.now();
const entry = rateLimits.get(key);
if (!entry) {
rateLimits.set(key, { count: 1, firstAttempt: now });
return { allowed: true, remaining: maxAttempts - 1 };
}
if (now - entry.firstAttempt > windowMs) {
rateLimits.set(key, { count: 1, firstAttempt: now });
return { allowed: true, remaining: maxAttempts - 1 };
}
entry.count++;
if (entry.count > maxAttempts) {
const retryAfter = Math.ceil((entry.firstAttempt + windowMs - now) / 1000);
return { allowed: false, remaining: 0, retryAfter };
}
return { allowed: true, remaining: maxAttempts - entry.count };
}
// --- CSRF ---
export function generateCsrfToken() {
return randomBytes(24).toString('hex');
}
// --- Audit Log ---
export function auditLog(userId, userEmail, action, targetType = null, targetId = null, details = null, ip = null) {
db.prepare('INSERT INTO audit_log (user_id, user_email, action, target_type, target_id, details, ip) VALUES (?, ?, ?, ?, ?, ?, ?)').run(userId, userEmail, action, targetType, targetId, details, ip);
}
export function getAuditLog(limit = 100, offset = 0) {
return db.prepare('SELECT * FROM audit_log ORDER BY created_at DESC LIMIT ? OFFSET ?').all(limit, offset);
}
export function searchAuditLog({ limit = 100, offset = 0, userId = null, action = '', from = '', to = '', query = '' } = {}) {
const clauses = [];
const values = [];
if (userId) { clauses.push('user_id = ?'); values.push(Number(userId)); }
if (action) { clauses.push('action LIKE ?'); values.push(`%${String(action).slice(0, 80)}%`); }
if (from) { clauses.push('created_at >= ?'); values.push(String(from).slice(0, 30)); }
if (to) { clauses.push('created_at <= ?'); values.push(String(to).slice(0, 30)); }
if (query) {
const q = `%${String(query).slice(0, 120)}%`;
clauses.push('(user_email LIKE ? OR action LIKE ? OR target_type LIKE ? OR target_id LIKE ? OR details LIKE ? OR ip LIKE ?)');
values.push(q, q, q, q, q, q);
}
const where = clauses.length ? `WHERE ${clauses.join(' AND ')}` : '';
const safeLimit = Math.max(1, Math.min(1000, Number(limit) || 100));
const safeOffset = Math.max(0, Number(offset) || 0);
const rows = db.prepare(`SELECT * FROM audit_log ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`).all(...values, safeLimit, safeOffset);
const total = db.prepare(`SELECT COUNT(*) AS count FROM audit_log ${where}`).get(...values)?.count || 0;
return { rows, total, limit: safeLimit, offset: safeOffset };
}
export function getAuditLogForUser(userId, limit = 50) {
return db.prepare('SELECT * FROM audit_log WHERE user_id = ? ORDER BY created_at DESC LIMIT ?').all(userId, limit);
}
// --- Login History ---
export function recordLogin(userId, ip, userAgent, success = true) {
db.prepare('INSERT INTO login_history (user_id, ip, user_agent, success) VALUES (?, ?, ?, ?)').run(userId, ip, userAgent || '', success ? 1 : 0);
}
export function getLoginHistory(userId, limit = 20) {
return db.prepare('SELECT * FROM login_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?').all(userId, limit);
}
export function getRecentFailedLogins(email, windowMinutes = 15) {
const user = getUserByEmail(email);
if (!user) return 0;
const r = db.prepare("SELECT COUNT(*) as count FROM login_history WHERE user_id = ? AND success = 0 AND created_at > datetime('now', ?)").get(user.id, `-${windowMinutes} minutes`);
return r.count;
}
// --- Setup: ensure at least one admin exists ---
export function ensureAdminExists() {
const count = getUserCount();
return count === 0;
}
export function isSetupMode() {
return getUserCount() === 0;
}
// Clean expired sessions every 10 minutes
setInterval(cleanExpiredSessions, 10 * 60 * 1000);
@@ -0,0 +1,49 @@
export const SECRET_DEFINITIONS = Object.freeze({
ANTHROPIC_API_KEY: { label: 'Anthropic API-Key', category: 'AI', editable: true },
OPENAI_API_KEY: { label: 'OpenAI API-Key', category: 'AI', editable: true },
OPENROUTER_API_KEY: { label: 'OpenRouter API-Key', category: 'AI', editable: true },
ETSY_API_KEY: { label: 'Etsy API-Key', category: 'Marktplatz', editable: true },
ETSY_ACCESS_TOKEN: { label: 'Etsy Access Token', category: 'Marktplatz', editable: false },
ETSY_REFRESH_TOKEN: { label: 'Etsy Refresh Token', category: 'Marktplatz', editable: false },
EBAY_CLIENT_SECRET: { label: 'eBay Client Secret', category: 'Marktplatz', editable: true },
EBAY_ACCESS_TOKEN: { label: 'eBay Access Token', category: 'Marktplatz', editable: false },
EBAY_REFRESH_TOKEN: { label: 'eBay Refresh Token', category: 'Marktplatz', editable: false },
LOCAL_IMAGE_TOKEN: { label: 'FLUX Dienst-Token', category: 'FLUX', editable: true },
SMTP_PASS: { label: 'SMTP-Passwort', category: 'E-Mail', editable: true },
VENDOO_SETUP_TOKEN: { label: 'Ersteinrichtungs-Token', category: 'System', editable: false },
});
export const SECRET_NAMES = Object.freeze(Object.keys(SECRET_DEFINITIONS));
const SECRET_NAME = /^[A-Z][A-Z0-9_]{2,80}$/;
export function validateSecretName(name) {
const normalized = String(name || '').trim();
if (!SECRET_NAME.test(normalized) || !SECRET_DEFINITIONS[normalized]) {
const error = new Error(`Unbekanntes Secret: ${normalized || '(leer)'}`);
error.code = 'SECRET_NAME_INVALID';
throw error;
}
return normalized;
}
export function validateSecretValue(value) {
const normalized = String(value ?? '');
if (/\r|\n|\0/.test(normalized)) {
const error = new Error('Secrets dürfen keine Zeilenumbrüche oder Nullbytes enthalten.');
error.code = 'SECRET_VALUE_INVALID';
throw error;
}
if (Buffer.byteLength(normalized, 'utf8') > 16_384) {
const error = new Error('Secret ist zu groß.');
error.code = 'SECRET_VALUE_TOO_LARGE';
throw error;
}
return normalized;
}
export function maskSecret(value) {
const text = String(value || '');
if (!text) return '';
if (text.length <= 4) return '••••';
return `••••••••${text.slice(-4)}`;
}
@@ -0,0 +1,169 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { APP_ROOT } from '../../../lib/runtime-paths.mjs';
import { PlatformError } from '../../kernel/errors.mjs';
const source = JSON.parse(readFileSync(join(APP_ROOT, 'public', 'design-system', 'tokens', 'source.json'), 'utf8'));
const BUILTIN_THEME_IDS = new Set([...source.themes, 'system', 'inherit']);
const HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
const RGB_COLOR = /^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)(?:\s*,\s*(0|1|0?\.\d+))?\s*\)$/i;
const DIMENSION = /^-?\d+(?:\.\d+)?px$/i;
const THEME_ID = /^[a-z][a-z0-9-]{2,39}$/;
function expandHex(value) {
const hex = value.replace('#', '');
if (hex.length === 3 || hex.length === 4) return hex.split('').map(char => char + char).join('');
return hex;
}
function parseColor(value) {
const raw = String(value || '').trim();
if (HEX_COLOR.test(raw)) {
const hex = expandHex(raw);
return [0, 2, 4].map(index => Number.parseInt(hex.slice(index, index + 2), 16));
}
const match = raw.match(RGB_COLOR);
if (!match) return null;
const channels = match.slice(1, 4).map(Number);
return channels.every(channel => Number.isFinite(channel) && channel >= 0 && channel <= 255) ? channels : null;
}
function validColor(value) {
if (!parseColor(value)) return false;
const match = String(value).trim().match(RGB_COLOR);
if (!match) return true;
const alpha = match[4] === undefined ? 1 : Number(match[4]);
return Number.isFinite(alpha) && alpha >= 0 && alpha <= 1;
}
function validateValue(token, value) {
const raw = String(value ?? '').trim();
if (token.type === 'color') return validColor(raw);
if (token.type === 'dimension') {
if (!DIMENSION.test(raw)) return false;
const numeric = Number.parseFloat(raw);
if (token.min !== undefined && numeric < Number(token.min)) return false;
if (token.max !== undefined && numeric > Number(token.max)) return false;
return true;
}
return false;
}
function relativeLuminance(value) {
const rgb = parseColor(value);
if (!rgb) return null;
const linear = rgb.map(channel => {
const normalized = channel / 255;
return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
}
export function contrastRatio(foreground, background) {
const first = relativeLuminance(foreground);
const second = relativeLuminance(background);
if (first === null || second === null) return null;
const lighter = Math.max(first, second);
const darker = Math.min(first, second);
return (lighter + 0.05) / (darker + 0.05);
}
export function getBaseThemeValues(themeId = 'light') {
const base = source.themes.includes(themeId) ? themeId : 'light';
return Object.fromEntries(Object.entries(source.tokens).map(([name, token]) => [name, token[base]]));
}
export function resolveThemeValues({ baseTheme = 'light', values = {} } = {}) {
return Object.freeze({ ...getBaseThemeValues(baseTheme), ...values });
}
export function evaluateThemeAccessibility({ baseTheme = 'light', values = {} } = {}) {
const resolved = resolveThemeValues({ baseTheme, values });
const checks = [
['primary-on-canvas', 'color.ink', 'color.canvas', 4.5],
['primary-on-surface', 'color.ink', 'color.surface', 4.5],
['secondary-on-surface', 'color.inkSecondary', 'color.surface', 4.5],
['muted-on-surface', 'color.inkMuted', 'color.surface', 3],
['brand-on-surface', 'color.brand', 'color.surface', 3],
['danger-on-surface', 'color.danger', 'color.surface', 3],
['line-on-surface', 'color.lineStrong', 'color.surface', 3],
].map(([id, foregroundToken, backgroundToken, minimum]) => {
const ratio = contrastRatio(resolved[foregroundToken], resolved[backgroundToken]);
return {
id,
foregroundToken,
backgroundToken,
ratio: ratio === null ? null : Number(ratio.toFixed(2)),
minimum,
ok: ratio !== null && ratio >= minimum,
};
});
return Object.freeze({
ok: checks.every(check => check.ok),
checks: Object.freeze(checks),
failures: Object.freeze(checks.filter(check => !check.ok)),
});
}
export function getThemeContract() {
return {
schemaVersion: source.schemaVersion,
contractVersion: source.contractVersion,
themes: [...source.themes],
tokens: Object.fromEntries(Object.entries(source.tokens).map(([name, token]) => [name, {
css: token.css,
type: token.type,
customizable: Boolean(token.customizable),
label: token.label || name,
group: token.group || name.split('.')[0],
...(token.min !== undefined ? { min: token.min } : {}),
...(token.max !== undefined ? { max: token.max } : {}),
}])),
};
}
export function getBuiltinThemes() {
return source.themes.map(id => ({
id,
name: ({ light: 'Hell', dark: 'Dunkel', contrast: 'Hoher Kontrast' })[id] || id,
base_theme: id,
builtin: true,
values: {},
resolved_values: getBaseThemeValues(id),
accessibility: evaluateThemeAccessibility({ baseTheme: id }),
}));
}
export function validateThemeDefinition(theme, { allowExistingId = false } = {}) {
if (!theme || typeof theme !== 'object' || Array.isArray(theme)) {
throw new PlatformError('Theme-Definition ist ungültig.', { code: 'THEME_INVALID', status: 400, expose: true });
}
const id = String(theme.id || '').trim().toLowerCase();
const name = String(theme.name || '').trim();
const baseTheme = String(theme.base_theme || theme.baseTheme || 'light').trim().toLowerCase();
if (!THEME_ID.test(id) || BUILTIN_THEME_IDS.has(id)) throw new PlatformError('Theme-ID ist ungültig oder reserviert.', { code: 'THEME_ID_INVALID', status: 400, expose: true });
if (!allowExistingId && !id.startsWith('custom-')) throw new PlatformError('Eigene Theme-IDs müssen mit custom- beginnen.', { code: 'THEME_ID_PREFIX', status: 400, expose: true });
if (!name || name.length > 80) throw new PlatformError('Theme-Name ist ungültig.', { code: 'THEME_NAME_INVALID', status: 400, expose: true });
if (!source.themes.includes(baseTheme)) throw new PlatformError('Basis-Theme ist ungültig.', { code: 'THEME_BASE_INVALID', status: 400, expose: true });
const values = {};
for (const [tokenName, value] of Object.entries(theme.values || {})) {
const token = source.tokens[tokenName];
if (!token || !token.customizable) throw new PlatformError(`Token ist nicht anpassbar: ${tokenName}`, { code: 'THEME_TOKEN_FORBIDDEN', status: 400, expose: true });
if (!validateValue(token, value)) throw new PlatformError(`Ungültiger Wert für ${tokenName}.`, { code: 'THEME_VALUE_INVALID', status: 400, expose: true });
values[tokenName] = String(value).trim();
}
const accessibility = evaluateThemeAccessibility({ baseTheme, values });
return Object.freeze({ schemaVersion: 1, id, name, base_theme: baseTheme, values: Object.freeze(values), accessibility });
}
export function validateThemePreference(input, { customThemeExists = () => false } = {}) {
const themeId = String(input?.theme_id || input?.themeId || 'inherit').trim().toLowerCase();
const density = String(input?.density || 'comfortable').trim().toLowerCase();
const reducedMotion = String(input?.reduced_motion || input?.reducedMotion || 'system').trim().toLowerCase();
if (![...BUILTIN_THEME_IDS].includes(themeId) && !customThemeExists(themeId)) {
throw new PlatformError('Gewähltes Theme existiert nicht.', { code: 'THEME_NOT_FOUND', status: 404, expose: true });
}
if (!['compact', 'comfortable', 'spacious'].includes(density)) throw new PlatformError('UI-Dichte ist ungültig.', { code: 'THEME_DENSITY_INVALID', status: 400, expose: true });
if (!['system', 'reduce', 'allow'].includes(reducedMotion)) throw new PlatformError('Bewegungseinstellung ist ungültig.', { code: 'THEME_MOTION_INVALID', status: 400, expose: true });
return Object.freeze({ theme_id: themeId, density, reduced_motion: reducedMotion });
}
@@ -0,0 +1,31 @@
export class PlatformError extends Error {
constructor(message, { code = 'PLATFORM_ERROR', status = 500, details = null, expose = false, cause = undefined } = {}) {
super(String(message || 'Unbekannter Plattformfehler'), { cause });
this.name = 'PlatformError';
this.code = String(code || 'PLATFORM_ERROR');
this.status = Number.isInteger(status) ? status : 500;
this.details = details;
this.expose = Boolean(expose || this.status < 500);
}
}
export function normalizePlatformError(error) {
if (error instanceof PlatformError) return error;
return new PlatformError(error?.message || 'Interner Serverfehler', {
code: error?.code || 'INTERNAL_ERROR',
status: Number.isInteger(error?.status) ? error.status : 500,
details: error?.details || null,
expose: Boolean(error?.expose),
cause: error,
});
}
export function platformErrorPayload(error, requestId = null) {
const normalized = normalizePlatformError(error);
return {
error: normalized.expose ? normalized.message : 'Interner Serverfehler',
code: normalized.code,
request_id: requestId || null,
...(normalized.expose && normalized.details ? { details: normalized.details } : {}),
};
}
@@ -0,0 +1,77 @@
import { PlatformError } from './errors.mjs';
const EVENT_PATTERN = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
export class EventBus {
#listeners = new Map();
#maxListeners;
constructor({ maxListenersPerEvent = 50 } = {}) {
this.#maxListeners = Math.max(1, Number(maxListenersPerEvent) || 50);
}
on(eventName, handler, { owner = 'core', once = false } = {}) {
if (!EVENT_PATTERN.test(String(eventName))) {
throw new PlatformError(`Ungültiger Eventname: ${eventName}`, { code: 'EVENT_NAME_INVALID', status: 500 });
}
if (typeof handler !== 'function') {
throw new PlatformError('Event-Handler muss eine Funktion sein.', { code: 'EVENT_HANDLER_INVALID', status: 500 });
}
const listeners = this.#listeners.get(eventName) || [];
if (listeners.length >= this.#maxListeners) {
throw new PlatformError(`Zu viele Listener für ${eventName}.`, { code: 'EVENT_LISTENER_LIMIT', status: 500 });
}
const entry = Object.freeze({ handler, owner: String(owner || 'core'), once: Boolean(once) });
listeners.push(entry);
this.#listeners.set(eventName, listeners);
return () => this.off(eventName, handler);
}
once(eventName, handler, options = {}) {
return this.on(eventName, handler, { ...options, once: true });
}
off(eventName, handler) {
const listeners = this.#listeners.get(eventName) || [];
const remaining = listeners.filter(entry => entry.handler !== handler);
if (remaining.length) this.#listeners.set(eventName, remaining);
else this.#listeners.delete(eventName);
return remaining.length !== listeners.length;
}
removeOwner(owner) {
let removed = 0;
for (const [eventName, listeners] of this.#listeners) {
const remaining = listeners.filter(entry => {
const match = entry.owner === owner;
if (match) removed += 1;
return !match;
});
if (remaining.length) this.#listeners.set(eventName, remaining);
else this.#listeners.delete(eventName);
}
return removed;
}
async emit(eventName, payload = null, context = {}) {
const listeners = [...(this.#listeners.get(eventName) || [])];
const results = [];
for (const entry of listeners) {
try {
results.push({ owner: entry.owner, ok: true, value: await entry.handler(payload, Object.freeze({ ...context, eventName })) });
} catch (error) {
results.push({ owner: entry.owner, ok: false, error });
} finally {
if (entry.once) this.off(eventName, entry.handler);
}
}
return results;
}
snapshot() {
return [...this.#listeners.entries()].map(([event, listeners]) => ({
event,
listeners: listeners.map(entry => ({ owner: entry.owner, once: entry.once })),
}));
}
}
@@ -0,0 +1,59 @@
import { PlatformError } from './errors.mjs';
const FLAG_PATTERN = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
function envKey(flag) {
return `VENDOO_FEATURE_${flag.replace(/[^a-z0-9]/gi, '_').toUpperCase()}`;
}
function parseBoolean(value, fallback) {
if (value === undefined || value === null || value === '') return fallback;
if (/^(1|true|yes|on)$/i.test(String(value))) return true;
if (/^(0|false|no|off)$/i.test(String(value))) return false;
throw new PlatformError(`Ungültiger Feature-Flag-Wert: ${value}`, { code: 'FEATURE_FLAG_VALUE_INVALID', status: 500 });
}
export class FeatureFlagRegistry {
#flags = new Map();
define(name, { defaultValue = false, owner = 'vendoo.system', description = '', mutable = false } = {}) {
const normalized = String(name || '');
if (!FLAG_PATTERN.test(normalized)) {
throw new PlatformError(`Ungültiger Feature-Flag: ${normalized}`, { code: 'FEATURE_FLAG_NAME_INVALID', status: 500 });
}
if (this.#flags.has(normalized)) {
throw new PlatformError(`Feature-Flag bereits definiert: ${normalized}`, { code: 'FEATURE_FLAG_DUPLICATE', status: 500 });
}
const configured = parseBoolean(process.env[envKey(normalized)], Boolean(defaultValue));
this.#flags.set(normalized, {
name: normalized,
value: configured,
defaultValue: Boolean(defaultValue),
owner: String(owner),
description: String(description),
mutable: Boolean(mutable),
source: process.env[envKey(normalized)] === undefined ? 'default' : 'environment',
});
return configured;
}
isEnabled(name) {
if (!this.#flags.has(name)) {
throw new PlatformError(`Unbekannter Feature-Flag: ${name}`, { code: 'FEATURE_FLAG_UNKNOWN', status: 500 });
}
return this.#flags.get(name).value;
}
set(name, value) {
const flag = this.#flags.get(name);
if (!flag) throw new PlatformError(`Unbekannter Feature-Flag: ${name}`, { code: 'FEATURE_FLAG_UNKNOWN', status: 404, expose: true });
if (!flag.mutable) throw new PlatformError(`Feature-Flag ist nicht zur Laufzeit änderbar: ${name}`, { code: 'FEATURE_FLAG_IMMUTABLE', status: 409, expose: true });
flag.value = Boolean(value);
flag.source = 'runtime';
return flag.value;
}
list() {
return [...this.#flags.values()].map(flag => ({ ...flag }));
}
}
@@ -0,0 +1,43 @@
import { PlatformError } from './errors.mjs';
function fail(message, field) {
throw new PlatformError(message, { code: 'INPUT_VALIDATION_FAILED', status: 400, expose: true, details: { field } });
}
export function objectSchema(fields, { allowUnknown = false } = {}) {
const contract = Object.freeze({ ...fields });
return input => {
const source = input && typeof input === 'object' && !Array.isArray(input) ? input : {};
const output = {};
if (!allowUnknown) for (const key of Object.keys(source)) if (!contract[key]) fail(`Unbekanntes Eingabefeld: ${key}`, key);
for (const [name, rule] of Object.entries(contract)) {
let value = source[name];
if (value === undefined || value === null) {
if (rule.required) fail(`${name} ist erforderlich.`, name);
continue;
}
if (rule.type === 'string') {
value = String(value);
if (rule.trim !== false) value = value.trim();
if (rule.minLength && value.length < rule.minLength) fail(`${name} ist zu kurz.`, name);
if (rule.maxLength && value.length > rule.maxLength) fail(`${name} ist zu lang.`, name);
if (rule.pattern && !rule.pattern.test(value)) fail(`${name} besitzt ein ungültiges Format.`, name);
} else if (rule.type === 'boolean') {
if (typeof value !== 'boolean') fail(`${name} muss true oder false sein.`, name);
} else if (rule.type === 'number' || rule.type === 'integer') {
value = Number(value);
if (!Number.isFinite(value)) fail(`${name} muss eine Zahl sein.`, name);
if (rule.type === 'integer' && !Number.isInteger(value)) fail(`${name} muss eine ganze Zahl sein.`, name);
if (rule.min !== undefined && value < rule.min) fail(`${name} ist zu klein.`, name);
if (rule.max !== undefined && value > rule.max) fail(`${name} ist zu groß.`, name);
}
if (rule.enum && !rule.enum.includes(value)) fail(`${name} enthält einen nicht erlaubten Wert.`, name);
if (typeof rule.validate === 'function') {
const result = rule.validate(value);
if (result !== true) fail(typeof result === 'string' ? result : `${name} ist ungültig.`, name);
}
output[name] = value;
}
return Object.freeze(output);
};
}
@@ -0,0 +1,49 @@
import { PlatformError } from './errors.mjs';
export class LifecycleManager {
#state = 'created';
#hooks = [];
register({ id, order = 100, start = async () => {}, stop = async () => {} }) {
if (!id || this.#hooks.some(hook => hook.id === id)) {
throw new PlatformError(`Ungültiger oder doppelter Lifecycle-Hook: ${id}`, { code: 'LIFECYCLE_HOOK_INVALID' });
}
this.#hooks.push({ id: String(id), order: Number(order) || 100, start, stop, state: 'registered' });
}
async start(context) {
if (!['created', 'stopped'].includes(this.#state)) throw new PlatformError(`Kernel kann aus Zustand ${this.#state} nicht starten.`, { code: 'LIFECYCLE_STATE_INVALID' });
this.#state = 'starting';
const started = [];
try {
for (const hook of [...this.#hooks].sort((a, b) => a.order - b.order)) {
hook.state = 'starting';
await hook.start(context);
hook.state = 'running';
started.push(hook);
}
this.#state = 'running';
} catch (error) {
for (const hook of started.reverse()) {
try { await hook.stop({ ...context, rollback: true }); } catch {}
hook.state = 'stopped';
}
this.#state = 'failed';
throw error;
}
}
async stop(context) {
if (!['running', 'starting'].includes(this.#state)) return;
this.#state = 'stopping';
for (const hook of [...this.#hooks].sort((a, b) => b.order - a.order)) {
if (hook.state !== 'running') continue;
try { await hook.stop(context); } finally { hook.state = 'stopped'; }
}
this.#state = 'stopped';
}
snapshot() {
return { state: this.#state, hooks: this.#hooks.map(({ start: _s, stop: _t, ...hook }) => ({ ...hook })) };
}
}
@@ -0,0 +1,47 @@
import { PlatformError } from './errors.mjs';
const MODULE_ID = /^vendoo\.[a-z][a-z0-9-]*$/;
const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
const CAPABILITY = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
const TYPES = new Set(['core', 'feature', 'adapter', 'extension-host']);
const STATUSES = new Set(['native', 'legacy-bridge', 'disabled']);
function uniqueStrings(values, label, pattern = CAPABILITY) {
if (!Array.isArray(values)) throw new PlatformError(`${label} muss ein Array sein.`, { code: 'MODULE_MANIFEST_INVALID' });
const normalized = values.map(value => String(value || '').trim());
if (normalized.some(value => !pattern.test(value))) {
throw new PlatformError(`${label} enthält einen ungültigen Eintrag.`, { code: 'MODULE_MANIFEST_INVALID' });
}
if (new Set(normalized).size !== normalized.length) {
throw new PlatformError(`${label} enthält Duplikate.`, { code: 'MODULE_MANIFEST_INVALID' });
}
return normalized;
}
export function validateModuleManifest(manifest) {
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) {
throw new PlatformError('Modulmanifest fehlt oder ist ungültig.', { code: 'MODULE_MANIFEST_INVALID' });
}
const normalized = {
schemaVersion: Number(manifest.schemaVersion || 1),
id: String(manifest.id || '').trim(),
name: String(manifest.name || '').trim(),
version: String(manifest.version || '').trim(),
type: String(manifest.type || '').trim(),
status: String(manifest.status || 'native').trim(),
description: String(manifest.description || '').trim(),
requires: Object.freeze(uniqueStrings(manifest.requires || [], 'requires', MODULE_ID)),
permissions: Object.freeze(uniqueStrings(manifest.permissions || [], 'permissions')),
provides: Object.freeze(uniqueStrings(manifest.provides || [], 'provides')),
consumes: Object.freeze(uniqueStrings(manifest.consumes || [], 'consumes')),
owns: Object.freeze(uniqueStrings(manifest.owns || [], 'owns')),
};
if (normalized.schemaVersion !== 1) throw new PlatformError('Nicht unterstützte Manifestversion.', { code: 'MODULE_MANIFEST_VERSION' });
if (!MODULE_ID.test(normalized.id)) throw new PlatformError(`Ungültige Modul-ID: ${normalized.id}`, { code: 'MODULE_ID_INVALID' });
if (!normalized.name) throw new PlatformError(`Modulname fehlt: ${normalized.id}`, { code: 'MODULE_NAME_REQUIRED' });
if (!SEMVER.test(normalized.version)) throw new PlatformError(`Ungültige Modulversion: ${normalized.id}`, { code: 'MODULE_VERSION_INVALID' });
if (!TYPES.has(normalized.type)) throw new PlatformError(`Ungültiger Modultyp: ${normalized.id}`, { code: 'MODULE_TYPE_INVALID' });
if (!STATUSES.has(normalized.status)) throw new PlatformError(`Ungültiger Modulstatus: ${normalized.id}`, { code: 'MODULE_STATUS_INVALID' });
if (normalized.requires.includes(normalized.id)) throw new PlatformError(`Modul darf sich nicht selbst benötigen: ${normalized.id}`, { code: 'MODULE_SELF_DEPENDENCY' });
return Object.freeze(normalized);
}
@@ -0,0 +1,265 @@
import { PlatformError } from './errors.mjs';
import { validateModuleManifest } from './module-contract.mjs';
export class ModuleRegistry {
#modules = new Map();
#startOrder = [];
#ownership = new Map();
#started = false;
register({ manifest, lifecycle = {}, source = 'builtin' }, { enabled = true } = {}) {
const validated = validateModuleManifest(manifest);
if (this.#modules.has(validated.id)) {
throw new PlatformError(`Modul bereits registriert: ${validated.id}`, { code: 'MODULE_DUPLICATE' });
}
for (const resource of validated.owns) {
const owner = this.#ownership.get(resource);
if (owner) throw new PlatformError(`Ressource ${resource} wird bereits von ${owner} besessen.`, { code: 'MODULE_OWNERSHIP_CONFLICT' });
}
const active = validated.status !== 'disabled' && enabled !== false;
const record = {
manifest: validated,
lifecycle: {
start: typeof lifecycle.start === 'function' ? lifecycle.start : async () => {},
stop: typeof lifecycle.stop === 'function' ? lifecycle.stop : async () => {},
health: typeof lifecycle.health === 'function' ? lifecycle.health : async () => ({ ok: true }),
},
source: String(source || 'builtin'),
enabled: active,
state: active ? 'registered' : 'disabled',
startedAt: null,
error: null,
};
this.#modules.set(validated.id, record);
for (const resource of validated.owns) this.#ownership.set(resource, validated.id);
return validated;
}
get(id) {
return this.#modules.get(id) || null;
}
has(id) {
return this.#modules.has(id);
}
isEnabled(id) {
return this.#modules.get(id)?.enabled === true;
}
dependentsOf(id, { enabledOnly = false, recursive = true } = {}) {
const found = new Set();
const visit = dependency => {
for (const [candidateId, record] of this.#modules) {
if (enabledOnly && !record.enabled) continue;
if (!record.manifest.requires.includes(dependency) || found.has(candidateId)) continue;
found.add(candidateId);
if (recursive) visit(candidateId);
}
};
visit(id);
return [...found];
}
#resolveStartOrder() {
const visiting = new Set();
const visited = new Set();
const order = [];
const visit = id => {
if (visited.has(id)) return;
if (visiting.has(id)) throw new PlatformError(`Zyklische Modulabhängigkeit bei ${id}.`, { code: 'MODULE_DEPENDENCY_CYCLE' });
const record = this.#modules.get(id);
if (!record) throw new PlatformError(`Fehlende Modulabhängigkeit: ${id}`, { code: 'MODULE_DEPENDENCY_MISSING' });
if (!record.enabled) return;
visiting.add(id);
for (const dependency of record.manifest.requires) {
const dependencyRecord = this.#modules.get(dependency);
if (!dependencyRecord) throw new PlatformError(`Fehlende Modulabhängigkeit: ${dependency}`, { code: 'MODULE_DEPENDENCY_MISSING' });
if (!dependencyRecord.enabled) {
throw new PlatformError(`Modul ${id} benötigt das deaktivierte Modul ${dependency}.`, {
code: 'MODULE_DEPENDENCY_DISABLED', details: { module: id, dependency },
});
}
visit(dependency);
}
visiting.delete(id);
visited.add(id);
order.push(id);
};
for (const [id, record] of this.#modules) if (record.enabled) visit(id);
const capabilities = new Set([...this.#modules.values()].filter(record => record.enabled).flatMap(record => record.manifest.provides));
for (const record of this.#modules.values()) {
if (!record.enabled) continue;
for (const capability of record.manifest.consumes) {
if (!capabilities.has(capability)) throw new PlatformError(`Fehlende Capability ${capability} für ${record.manifest.id}.`, { code: 'MODULE_CAPABILITY_MISSING' });
}
}
return order;
}
async #startRecord(id, context) {
const record = this.#modules.get(id);
if (!record || !record.enabled || record.state === 'running') return;
for (const dependency of record.manifest.requires) {
const dependencyRecord = this.#modules.get(dependency);
if (!dependencyRecord?.enabled) {
throw new PlatformError(`Modul ${id} benötigt das deaktivierte Modul ${dependency}.`, {
code: 'MODULE_DEPENDENCY_DISABLED', status: 409, expose: true,
details: { module: id, dependency },
});
}
if (dependencyRecord.state !== 'running') await this.#startRecord(dependency, context);
}
try {
record.state = 'starting';
record.error = null;
await record.lifecycle.start(Object.freeze({ ...context, module: record.manifest }));
record.state = 'running';
record.startedAt = new Date().toISOString();
if (!this.#startOrder.includes(id)) this.#startOrder.push(id);
} catch (error) {
record.state = 'failed';
record.error = error?.message || String(error);
throw new PlatformError(`Modulstart fehlgeschlagen: ${id}`, { code: 'MODULE_START_FAILED', cause: error, details: { module: id } });
}
}
async startAll(context) {
this.#startOrder = this.#resolveStartOrder();
const started = [];
for (const id of this.#startOrder) {
const record = this.#modules.get(id);
if (!record.enabled) continue;
try {
await this.#startRecord(id, context);
started.push(id);
} catch (error) {
for (const startedId of started.reverse()) {
const startedRecord = this.#modules.get(startedId);
try { await startedRecord.lifecycle.stop(Object.freeze({ ...context, module: startedRecord.manifest, rollback: true })); } catch {}
startedRecord.state = 'stopped';
}
throw error;
}
}
this.#started = true;
}
async enable(id, context) {
const record = this.#modules.get(id);
if (!record) throw new PlatformError('Modul nicht gefunden.', { code: 'MODULE_NOT_FOUND', status: 404, expose: true });
if (record.enabled && record.state === 'running') return this.describe(id);
record.enabled = true;
record.state = 'registered';
try {
this.#resolveStartOrder();
if (this.#started) await this.#startRecord(id, context);
return this.describe(id);
} catch (error) {
record.enabled = false;
record.state = 'disabled';
throw error;
}
}
async disable(id, context, { cascade = false } = {}) {
const record = this.#modules.get(id);
if (!record) throw new PlatformError('Modul nicht gefunden.', { code: 'MODULE_NOT_FOUND', status: 404, expose: true });
if (!record.enabled) return { module: this.describe(id), disabled: [] };
const dependents = this.dependentsOf(id, { enabledOnly: true, recursive: true });
if (dependents.length && !cascade) {
throw new PlatformError('Das Modul wird von aktiven Modulen benötigt.', {
code: 'MODULE_HAS_ACTIVE_DEPENDENTS', status: 409, expose: true, details: { dependents },
});
}
const orderIndex = new Map(this.#startOrder.map((moduleId, index) => [moduleId, index]));
const toDisable = [...dependents, id].sort((a, b) => (orderIndex.get(b) ?? -1) - (orderIndex.get(a) ?? -1));
for (const moduleId of toDisable) {
const target = this.#modules.get(moduleId);
if (!target?.enabled) continue;
if (target.state === 'running') {
target.state = 'stopping';
try {
await target.lifecycle.stop(Object.freeze({ ...context, module: target.manifest, disabled: true }));
target.state = 'disabled';
} catch (error) {
target.state = 'failed';
target.error = error?.message || String(error);
throw new PlatformError(`Modul konnte nicht deaktiviert werden: ${moduleId}`, { code: 'MODULE_STOP_FAILED', status: 500, cause: error });
}
} else {
target.state = 'disabled';
}
target.enabled = false;
target.startedAt = null;
}
return { module: this.describe(id), disabled: toDisable };
}
async unregister(id, context) {
const record = this.#modules.get(id);
if (!record) return false;
if (record.enabled || record.state === 'running') await this.disable(id, context, { cascade: false });
const dependents = this.dependentsOf(id, { enabledOnly: false, recursive: false });
if (dependents.length) {
throw new PlatformError('Modul kann wegen vorhandener Abhängigkeiten nicht entfernt werden.', {
code: 'MODULE_HAS_DEPENDENTS', status: 409, expose: true, details: { dependents },
});
}
for (const resource of record.manifest.owns) if (this.#ownership.get(resource) === id) this.#ownership.delete(resource);
this.#modules.delete(id);
this.#startOrder = this.#startOrder.filter(moduleId => moduleId !== id);
return true;
}
async stopAll(context) {
for (const id of [...this.#startOrder].reverse()) {
const record = this.#modules.get(id);
if (!record || record.state !== 'running') continue;
try {
record.state = 'stopping';
await record.lifecycle.stop(Object.freeze({ ...context, module: record.manifest }));
record.state = 'stopped';
} catch (error) {
record.state = 'failed';
record.error = error?.message || String(error);
}
}
this.#started = false;
}
async health() {
const checks = [];
for (const [id, record] of this.#modules) {
if (!record.enabled || record.state === 'disabled') {
checks.push({ id, ok: true, state: 'disabled' });
continue;
}
try {
const result = await record.lifecycle.health({ module: record.manifest });
checks.push({ id, state: record.state, ok: record.state === 'running' && result?.ok !== false, ...(result || {}) });
} catch (error) {
checks.push({ id, state: record.state, ok: false, error: error?.message || String(error) });
}
}
return checks;
}
describe(id) {
const record = this.#modules.get(id);
if (!record) return null;
return {
...record.manifest,
source: record.source,
enabled: record.enabled,
state: record.state,
startedAt: record.startedAt,
error: record.error,
dependents: this.dependentsOf(id, { enabledOnly: false, recursive: false }),
};
}
snapshot() {
return [...this.#modules.keys()].map(id => this.describe(id));
}
}
@@ -0,0 +1,149 @@
import { EventBus } from './event-bus.mjs';
import { FeatureFlagRegistry } from './feature-flags.mjs';
import { LifecycleManager } from './lifecycle.mjs';
import { ModuleRegistry } from './module-registry.mjs';
import { PolicyEngine } from './policy-engine.mjs';
import { RouteRegistry } from './route-registry.mjs';
import { loadBuiltInModules } from '../modules/catalog.mjs';
import { ModuleStateStore } from '../core/modules/module-state-store.mjs';
import { ModulePackageStore } from '../core/modules/module-package-store.mjs';
import { createExternalLifecycle, PROTECTED_MODULE_IDS } from '../modules/module-manager/service.mjs';
import { MODULES_DIR, MODULE_STATE_PATH } from '../../lib/runtime-paths.mjs';
export function createPlatformKernel({ version, hasPermission, moduleTrustKeys = {} }) {
const events = new EventBus();
const features = new FeatureFlagRegistry();
const modules = new ModuleRegistry();
const moduleStateStore = new ModuleStateStore(MODULE_STATE_PATH);
const modulePackageStore = new ModulePackageStore(MODULES_DIR, { trustKeys: moduleTrustKeys });
const policies = new PolicyEngine();
const routes = new RouteRegistry({ policyEngine: policies, moduleRegistry: modules });
const lifecycle = new LifecycleManager();
policies.register('platform.authenticated', ({ user }) => Boolean(user), {
description: 'Erfordert eine gültige Vendoo-Sitzung.',
});
policies.register('platform.security-admin', ({ user }) => Boolean(user && hasPermission(user.role, 'security.manage')), {
description: 'Erfordert die Berechtigung security.manage.',
});
policies.register('security.secrets.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'security.manage')), {
owner: 'vendoo.security', description: 'Erfordert security.manage für verschlüsselte Zugangsdaten.',
});
policies.register('auth.public', () => true, { owner: 'vendoo.auth', description: 'Öffentliche Authentifizierungsroute mit eigener Eingabe- und Rate-Limit-Prüfung.' });
policies.register('auth.authenticated', ({ user }) => Boolean(user), { owner: 'vendoo.auth', description: 'Erfordert eine gültige Vendoo-Identität.' });
policies.register('users.self', ({ user }) => Boolean(user), { owner: 'vendoo.users', description: 'Erlaubt Zugriff auf das eigene Benutzerprofil.' });
policies.register('users.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'users.manage')), { owner: 'vendoo.users', description: 'Erfordert users.manage.' });
policies.register('sessions.self', ({ user }) => Boolean(user), { owner: 'vendoo.sessions', description: 'Erlaubt Zugriff auf eigene Sitzungen.' });
policies.register('sessions.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'sessions.manage')), { owner: 'vendoo.sessions', description: 'Erfordert sessions.manage.' });
policies.register('settings.read', ({ user }) => Boolean(user), { owner: 'vendoo.settings', description: 'Erfordert eine gültige Sitzung zum Lesen der Anwendungseinstellungen.' });
policies.register('settings.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'settings.manage')), { owner: 'vendoo.settings', description: 'Erfordert settings.manage.' });
policies.register('listings.view', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.view')), { owner: 'vendoo.listings', description: 'Erfordert listings.view.' });
policies.register('listings.edit', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.edit')), { owner: 'vendoo.listings', description: 'Erfordert listings.edit.' });
policies.register('listings.delete', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.delete')), { owner: 'vendoo.listings', description: 'Erfordert listings.delete.' });
policies.register('listings.permanent-delete', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.permanent_delete')), { owner: 'vendoo.listings', description: 'Erfordert listings.permanent_delete.' });
policies.register('inventory.view', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.view')), { owner: 'vendoo.inventory', description: 'Erfordert listings.view für Lagerübersichten.' });
policies.register('inventory.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'inventory.edit')), { owner: 'vendoo.inventory', description: 'Erfordert inventory.edit.' });
policies.register('media.view', ({ user }) => Boolean(user && hasPermission(user.role, 'media.view')), { owner: 'vendoo.media', description: 'Erfordert media.view.' });
policies.register('media.edit', ({ user }) => Boolean(user && hasPermission(user.role, 'media.edit')), { owner: 'vendoo.media', description: 'Erfordert media.edit.' });
policies.register('media.delete', ({ user }) => Boolean(user && hasPermission(user.role, 'media.delete')), { owner: 'vendoo.media', description: 'Erfordert media.delete.' });
policies.register('themes.use', ({ user }) => Boolean(user), {
owner: 'vendoo.themes', description: 'Erfordert eine gültige Sitzung für persönliche Darstellungseinstellungen.',
});
policies.register('themes.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'settings.manage')), {
owner: 'vendoo.themes', description: 'Erfordert settings.manage für systemweite und eigene Theme-Profile.',
});
policies.register('modules.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'modules.manage')), {
owner: 'vendoo.module-manager', description: 'Erfordert modules.manage für Installation, Aktivierung, Export und Entfernung von Modulen.',
});
policies.register('publishing.view', ({ user }) => Boolean(user && hasPermission(user.role, 'publishing.view')), { owner: 'vendoo.publishing', description: 'Erfordert publishing.view.' });
policies.register('publishing.execute', ({ user }) => Boolean(user && hasPermission(user.role, 'publishing.execute')), { owner: 'vendoo.publishing', description: 'Erfordert publishing.execute.' });
policies.register('publishing.manage', ({ user }) => Boolean(user && hasPermission(user.role, 'publishing.manage')), { owner: 'vendoo.publishing', description: 'Erfordert publishing.manage.' });
policies.register('ai.execute', ({ user }) => Boolean(user && hasPermission(user.role, 'generation.execute')), { owner: 'vendoo.ai', description: 'Erfordert generation.execute.' });
policies.register('flux.execute', ({ user }) => Boolean(user && hasPermission(user.role, 'generation.execute')), { owner: 'vendoo.flux-studio', description: 'Erfordert generation.execute.' });
policies.register('quality.view', ({ user }) => Boolean(user && hasPermission(user.role, 'listings.view')), { owner: 'vendoo.quality', description: 'Erfordert listings.view.' });
policies.register('quality.execute', ({ user }) => Boolean(user && hasPermission(user.role, 'quality.execute')), { owner: 'vendoo.quality', description: 'Erfordert quality.execute.' });
features.define('platform.module-kernel', { defaultValue: true, description: 'Aktiviert den modularen Plattformkernel.' });
features.define('platform.route-contracts', { defaultValue: true, description: 'Aktiviert registrierte Routenverträge.' });
features.define('security.encrypted-secret-store', { defaultValue: true, owner: 'vendoo.security', description: 'Aktiviert AES-256-GCM-verschlüsselte Zugangsdaten außerhalb der Runtime-Konfiguration.' });
features.define('security.request-telemetry', { defaultValue: true, owner: 'vendoo.security', description: 'Aktiviert Request-/Correlation-IDs und strukturierte Telemetrie.' });
features.define('security.strict-script-csp', { defaultValue: true, owner: 'vendoo.security', description: 'Blockiert Inline-Skripte und Inline-Eventhandler per CSP.' });
features.define('identity.native-auth', { defaultValue: true, owner: 'vendoo.auth', description: 'Aktiviert native Setup-, Login- und Einladungsabläufe.' });
features.define('identity.native-users', { defaultValue: true, owner: 'vendoo.users', description: 'Aktiviert native Benutzer- und Rollenverwaltung.' });
features.define('identity.native-sessions', { defaultValue: true, owner: 'vendoo.sessions', description: 'Aktiviert eigentümergebundene Sitzungsverwaltung und Revocation.' });
features.define('settings.native-module', { defaultValue: true, owner: 'vendoo.settings', description: 'Aktiviert allowlist-basierte Anwendungs- und SMTP-Einstellungen.' });
features.define('catalog.native-listings', { defaultValue: true, owner: 'vendoo.listings', description: 'Aktiviert native Artikel-, Duplikat- und Papierkorbverträge.' });
features.define('catalog.native-inventory', { defaultValue: true, owner: 'vendoo.inventory', description: 'Aktiviert native Lagerort- und Bulk-Bestandsverträge.' });
features.define('catalog.native-media', { defaultValue: true, owner: 'vendoo.media', description: 'Aktiviert native Medienbibliothek und Referenzschutz.' });
features.define('themes.token-runtime', { defaultValue: true, owner: 'vendoo.themes', description: 'Aktiviert den versionierten Design-Token-Vertrag.' });
features.define('themes.manager', { defaultValue: true, owner: 'vendoo.themes', description: 'Aktiviert den sicheren Theme Manager mit Benutzerpräferenzen.' });
features.define('themes.accessibility-gate', { defaultValue: true, owner: 'vendoo.themes', description: 'Prüft Theme-Kontraste und sichere Tokenwerte.' });
features.define('extensions.isolated-host', { defaultValue: false, owner: 'vendoo.security', description: 'Reserviert für einen späteren isolierten Extension-Host.' });
features.define('modules.manager', { defaultValue: true, owner: 'vendoo.module-manager', description: 'Aktiviert den sicheren Modulmanager und den persistenten Modulstatus.' });
features.define('modules.package-format', { defaultValue: true, owner: 'vendoo.module-manager', description: 'Aktiviert validierte .vmod-Pakete mit SHA-256-Integrität und optionaler Ed25519-Signatur.' });
features.define('publishing.native-module', { defaultValue: true, owner: 'vendoo.publishing', description: 'Aktiviert native Publishing-Verträge.' });
features.define('ai.native-module', { defaultValue: true, owner: 'vendoo.ai', description: 'Aktiviert native AI-Verträge.' });
features.define('flux.native-module', { defaultValue: true, owner: 'vendoo.flux-studio', description: 'Aktiviert native FLUX-Verträge.' });
features.define('quality.native-module', { defaultValue: true, owner: 'vendoo.quality', description: 'Aktiviert native Quality-Verträge.' });
for (const module of loadBuiltInModules()) {
const defaultEnabled = module.manifest.status !== 'disabled';
const forcedEnabled = PROTECTED_MODULE_IDS.includes(module.manifest.id);
modules.register(module, { enabled: forcedEnabled || moduleStateStore.isEnabled(module.manifest.id, defaultEnabled) });
}
for (const installed of modulePackageStore.list()) {
if (installed.invalid || modules.has(installed.id)) continue;
try {
const pkg = modulePackageStore.get(installed.id);
const enabled = installed.activatable && moduleStateStore.isEnabled(installed.id, false);
modules.register({ manifest: pkg.manifest, lifecycle: createExternalLifecycle(pkg), source: 'external' }, { enabled });
} catch {
// Ungültige oder konfliktbehaftete Fremdmodule bleiben quarantänisiert und erscheinen im Modulmanager.
}
}
lifecycle.register({
id: 'modules',
order: 20,
start: context => modules.startAll(context),
stop: context => modules.stopAll(context),
});
const context = Object.freeze({ version, events, features, policies, modules, moduleStateStore, modulePackageStore });
return Object.freeze({
version,
events,
features,
lifecycle,
modules,
policies,
routes,
async start() {
await lifecycle.start(context);
await events.emit('platform.started', { version }, { owner: 'vendoo.system' });
},
async stop() {
await events.emit('platform.stopping', { version }, { owner: 'vendoo.system' });
await lifecycle.stop(context);
},
async health() {
const moduleChecks = await modules.health();
return {
ok: lifecycle.snapshot().state === 'running' && moduleChecks.every(check => check.ok),
lifecycle: lifecycle.snapshot(),
modules: moduleChecks,
};
},
snapshot() {
return {
version,
architecture: 'modular-monolith',
lifecycle: lifecycle.snapshot(),
modules: modules.snapshot(),
features: features.list(),
policies: policies.list(),
routes: routes.list(),
moduleState: moduleStateStore.snapshot(),
};
},
});
}
@@ -0,0 +1,30 @@
import { PlatformError } from './errors.mjs';
const POLICY_ID = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
export class PolicyEngine {
#policies = new Map();
register(id, evaluator, { owner = 'vendoo.security', description = '' } = {}) {
const normalized = String(id || '');
if (!POLICY_ID.test(normalized)) throw new PlatformError(`Ungültige Policy-ID: ${normalized}`, { code: 'POLICY_ID_INVALID' });
if (this.#policies.has(normalized)) throw new PlatformError(`Policy bereits registriert: ${normalized}`, { code: 'POLICY_DUPLICATE' });
if (typeof evaluator !== 'function') throw new PlatformError(`Policy benötigt eine Prüffunktion: ${normalized}`, { code: 'POLICY_EVALUATOR_INVALID' });
this.#policies.set(normalized, { id: normalized, evaluator, owner, description });
}
async evaluate(id, context) {
const policy = this.#policies.get(id);
if (!policy) {
return { allowed: false, reason: 'policy_not_registered', policy: id };
}
const result = await policy.evaluator(Object.freeze({ ...context }));
if (result === true) return { allowed: true, policy: id };
if (result === false || result == null) return { allowed: false, reason: 'denied', policy: id };
return { allowed: Boolean(result.allowed), reason: result.reason || null, policy: id, details: result.details || null };
}
list() {
return [...this.#policies.values()].map(({ evaluator: _evaluator, ...policy }) => ({ ...policy }));
}
}
@@ -0,0 +1,72 @@
import { PlatformError, platformErrorPayload } from './errors.mjs';
const METHODS = new Set(['get', 'post', 'put', 'patch', 'delete']);
const ROUTE_ID = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
export class RouteRegistry {
#routes = new Map();
#policyEngine;
#moduleRegistry;
constructor({ policyEngine, moduleRegistry = null }) {
this.#policyEngine = policyEngine;
this.#moduleRegistry = moduleRegistry;
}
register(app, definition) {
const method = String(definition.method || '').toLowerCase();
const id = String(definition.id || '');
const path = String(definition.path || '');
if (!ROUTE_ID.test(id)) throw new PlatformError(`Ungültige Route-ID: ${id}`, { code: 'ROUTE_ID_INVALID' });
if (!METHODS.has(method)) throw new PlatformError(`Ungültige HTTP-Methode für ${id}.`, { code: 'ROUTE_METHOD_INVALID' });
if (!path.startsWith('/')) throw new PlatformError(`Ungültiger Routenpfad für ${id}.`, { code: 'ROUTE_PATH_INVALID' });
if (!definition.policy) throw new PlatformError(`Route ${id} benötigt eine explizite Policy.`, { code: 'ROUTE_POLICY_REQUIRED' });
if (!definition.owner) throw new PlatformError(`Route ${id} benötigt einen Modulbesitzer.`, { code: 'ROUTE_OWNER_REQUIRED' });
if (typeof definition.handler !== 'function') throw new PlatformError(`Route ${id} benötigt einen Handler.`, { code: 'ROUTE_HANDLER_REQUIRED' });
const key = `${method.toUpperCase()} ${path}`;
if (this.#routes.has(key)) throw new PlatformError(`Route bereits registriert: ${key}`, { code: 'ROUTE_DUPLICATE' });
const contract = Object.freeze({
id,
method: method.toUpperCase(),
path,
owner: String(definition.owner),
policy: String(definition.policy),
audit: String(definition.audit || ''),
input: definition.input ? 'validated' : 'none',
rateLimit: String(definition.rateLimit || 'default'),
csrf: definition.csrf !== false,
stability: String(definition.stability || 'internal'),
});
this.#routes.set(key, contract);
app[method](path, ...(definition.middleware || []), async (req, res, next) => {
try {
if (this.#moduleRegistry && !this.#moduleRegistry.isEnabled(contract.owner)) {
throw new PlatformError('Dieses Modul ist deaktiviert.', {
code: 'MODULE_DISABLED', status: 503, expose: true,
details: { module: contract.owner },
});
}
const decision = await this.#policyEngine.evaluate(contract.policy, { req, user: req.user, route: contract });
if (!decision.allowed) {
throw new PlatformError('Keine Berechtigung für diese Aktion.', {
code: 'POLICY_DENIED', status: 403, expose: true,
details: { policy: contract.policy, reason: decision.reason },
});
}
if (typeof definition.input === 'function') req.validatedBody = definition.input(req.body);
await definition.handler(req, res, { route: contract, decision });
} catch (error) {
if (res.headersSent) return next(error);
const status = Number.isInteger(error?.status) ? error.status : 500;
res.status(status).json(platformErrorPayload(error, req.requestId));
}
});
return contract;
}
list() {
return [...this.#routes.values()].map(route => ({ ...route }));
}
}
@@ -0,0 +1,30 @@
import dotenv from 'dotenv';
import { existsSync } from 'node:fs';
import { dirname, isAbsolute, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const appRoot = dirname(fileURLToPath(import.meta.url));
const rootEnvPath = join(appRoot, '.env');
// Lokaler Windows-/Entwicklungsbetrieb: klassische .env zuerst laden.
if (existsSync(rootEnvPath)) dotenv.config({ path: rootEnvPath, override: false });
// Docker/NAS/VPS: schreibbarer persistenter Overlay-Speicher für Eingabemasken.
const configuredPath = String(process.env.VENDOO_CONFIG_PATH || '').trim();
const defaultPath = process.env.VENDOO_DATA_DIR
? join(String(process.env.VENDOO_DATA_DIR), 'config', 'vendoo.env')
: rootEnvPath;
const configCandidate = configuredPath || defaultPath;
const runtimeConfigPath = resolve(isAbsolute(configCandidate) ? configCandidate : join(appRoot, configCandidate));
process.env.VENDOO_CONFIG_PATH = runtimeConfigPath;
if (runtimeConfigPath !== rootEnvPath && existsSync(runtimeConfigPath)) {
dotenv.config({ path: runtimeConfigPath, override: true });
}
const { hydrateSecretsToEnvironment, migrateRuntimeConfigSecrets } = await import('./lib/secret-store.mjs');
const migration = migrateRuntimeConfigSecrets();
if (migration.migrated.length) console.log(`Security: ${migration.migrated.length} Secrets aus der Runtime-Konfiguration verschlüsselt migriert.`);
hydrateSecretsToEnvironment();
await import('./server.mjs');
@@ -0,0 +1,12 @@
# Optionaler Override für NAS-Bind-Mounts.
# Vorher ./runtime/{db,uploads,backups,operations,logs} anlegen und UID/GID 1000 Schreibrechte geben.
services:
vendoo:
volumes:
- ./runtime/db:/app/data/db
- ./runtime/uploads:/app/data/uploads
- ./runtime/backups:/app/data/backups
- ./runtime/operations:/app/data/operations
- ./runtime/logs:/app/data/logs
- ./runtime/config:/app/data/config
- ./runtime/modules:/app/data/modules
@@ -0,0 +1,108 @@
name: vendoo
services:
vendoo:
build:
context: .
dockerfile: Dockerfile
image: vendoo:1.40.1
container_name: vendoo
restart: unless-stopped
init: true
env_file:
- .env
environment:
NODE_ENV: production
PORT: 8124
VENDOO_BIND_HOST: 0.0.0.0
VENDOO_TRUST_PROXY: "true"
VENDOO_COOKIE_SECURE: "true"
VENDOO_DATA_DIR: /app/data
VENDOO_DB_PATH: /app/data/db/vendoo.db
VENDOO_UPLOADS_DIR: /app/data/uploads
VENDOO_BACKUP_DIR: /app/data/backups
VENDOO_OPERATIONS_DIR: /app/data/operations
VENDOO_LOG_DIR: /app/data/logs
VENDOO_CONFIG_PATH: /app/data/config/vendoo.env
VENDOO_REQUIRE_SETUP_TOKEN: "true"
LOCAL_IMAGE_ENABLED: "${LOCAL_IMAGE_ENABLED:-false}"
expose:
- "8124"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- vendoo_db:/app/data/db
- vendoo_uploads:/app/data/uploads
- vendoo_backups:/app/data/backups
- vendoo_operations:/app/data/operations
- vendoo_logs:/app/data/logs
- vendoo_config:/app/data/config
- vendoo_modules:/app/data/modules
read_only: true
tmpfs:
- /tmp:size=512m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
pids_limit: 256
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
stop_grace_period: 15s
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8124/readyz').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
interval: 30s
timeout: 5s
start_period: 30s
retries: 3
networks:
- vendoo
caddy:
image: caddy:2-alpine
container_name: vendoo-caddy
restart: unless-stopped
depends_on:
vendoo:
condition: service_healthy
environment:
VENDOO_DOMAIN: "${VENDOO_DOMAIN}"
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
pids_limit: 128
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
networks:
- vendoo
networks:
vendoo:
driver: bridge
volumes:
vendoo_db:
vendoo_uploads:
vendoo_backups:
vendoo_operations:
vendoo_logs:
vendoo_config:
vendoo_modules:
caddy_data:
caddy_config:
@@ -0,0 +1,74 @@
name: vendoo
services:
vendoo:
build:
context: .
dockerfile: Dockerfile
image: vendoo:1.40.1
container_name: vendoo
restart: unless-stopped
init: true
env_file:
- .env
environment:
NODE_ENV: production
PORT: 8124
VENDOO_BIND_HOST: 0.0.0.0
VENDOO_DATA_DIR: /app/data
VENDOO_DB_PATH: /app/data/db/vendoo.db
VENDOO_UPLOADS_DIR: /app/data/uploads
VENDOO_BACKUP_DIR: /app/data/backups
VENDOO_OPERATIONS_DIR: /app/data/operations
VENDOO_LOG_DIR: /app/data/logs
VENDOO_CONFIG_PATH: /app/data/config/vendoo.env
VENDOO_REQUIRE_SETUP_TOKEN: "true"
LOCAL_IMAGE_ENABLED: "${LOCAL_IMAGE_ENABLED:-false}"
ports:
- "${VENDOO_PUBLISH_ADDRESS:-127.0.0.1}:${VENDOO_HOST_PORT:-8124}:8124"
expose:
- "8124"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- vendoo_db:/app/data/db
- vendoo_uploads:/app/data/uploads
- vendoo_backups:/app/data/backups
- vendoo_operations:/app/data/operations
- vendoo_logs:/app/data/logs
- vendoo_config:/app/data/config
- vendoo_modules:/app/data/modules
read_only: true
tmpfs:
- /tmp:size=512m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
pids_limit: 256
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
stop_grace_period: 15s
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8124/readyz').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
interval: 30s
timeout: 5s
start_period: 30s
retries: 3
networks:
- vendoo
networks:
vendoo:
driver: bridge
volumes:
vendoo_db:
vendoo_uploads:
vendoo_backups:
vendoo_operations:
vendoo_logs:
vendoo_config:
vendoo_modules:
@@ -0,0 +1,278 @@
CREATE TABLE IF NOT EXISTS listings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
platform TEXT NOT NULL,
ai_provider TEXT NOT NULL,
title TEXT,
description TEXT,
description_html TEXT,
tags TEXT,
photos TEXT,
seller_notes TEXT,
brand TEXT,
category TEXT,
size TEXT,
color TEXT,
condition TEXT,
price REAL,
status TEXT DEFAULT 'active',
language TEXT DEFAULT 'de',
created_by INTEGER,
updated_by INTEGER,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT
);
CREATE TABLE IF NOT EXISTS templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
platform TEXT,
seller_notes TEXT,
language TEXT DEFAULT 'de',
default_tags TEXT,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT
);
CREATE TABLE IF NOT EXISTS publish_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
listing_id INTEGER NOT NULL,
platform TEXT NOT NULL,
status TEXT DEFAULT 'pending',
external_id TEXT,
external_url TEXT,
offer_id TEXT,
sync_status TEXT,
last_synced_at TEXT,
ended_at TEXT,
updated_at TEXT,
published_at TEXT,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (listing_id) REFERENCES listings(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_publish_log_external ON publish_log(platform, external_id);
INSERT OR IGNORE INTO settings (key, value) VALUES ('default_platform', 'vinted');
INSERT OR IGNORE INTO settings (key, value) VALUES ('default_ai', 'claude');
INSERT OR IGNORE INTO settings (key, value) VALUES ('seller_notes', '');
INSERT OR IGNORE INTO settings (key, value) VALUES ('default_language', 'de');
CREATE TABLE IF NOT EXISTS mobile_upload_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
token_hash TEXT NOT NULL UNIQUE,
user_id INTEGER,
listing_id INTEGER,
context TEXT NOT NULL DEFAULT 'generator',
files TEXT NOT NULL DEFAULT '[]',
status TEXT NOT NULL DEFAULT 'active',
expires_at TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_mobile_upload_token ON mobile_upload_sessions(token_hash);
CREATE INDEX IF NOT EXISTS idx_mobile_upload_expires ON mobile_upload_sessions(expires_at);
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photos_enabled', '1');
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photo_default_variants', '1');
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photo_default_preset', 'mixed');
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photo_block_underwear', '1');
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photo_block_kids', '1');
INSERT OR IGNORE INTO settings (key, value) VALUES ('ai_model_photo_provider', 'openai');
CREATE TABLE IF NOT EXISTS ai_model_generations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
listing_id INTEGER,
context TEXT NOT NULL DEFAULT 'generator',
preset TEXT NOT NULL,
variants INTEGER NOT NULL DEFAULT 3,
source_photos TEXT NOT NULL DEFAULT '[]',
generated_photos TEXT NOT NULL DEFAULT '[]',
prompt_summary TEXT,
moderation_notes TEXT,
safety_status TEXT NOT NULL DEFAULT 'pending',
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT,
FOREIGN KEY (listing_id) REFERENCES listings(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_ai_model_generations_listing ON ai_model_generations(listing_id);
CREATE TABLE IF NOT EXISTS ai_model_photos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
generation_id INTEGER NOT NULL,
listing_id INTEGER,
variant_index INTEGER NOT NULL DEFAULT 1,
preset TEXT NOT NULL,
image_path TEXT NOT NULL,
source_photo TEXT,
prompt TEXT,
moderation_result TEXT,
safety_status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (generation_id) REFERENCES ai_model_generations(id) ON DELETE CASCADE,
FOREIGN KEY (listing_id) REFERENCES listings(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_ai_model_photos_listing ON ai_model_photos(listing_id);
CREATE TABLE IF NOT EXISTS flux_images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
prompt TEXT NOT NULL,
image_path TEXT NOT NULL UNIQUE,
width INTEGER,
height INTEGER,
seed INTEGER,
steps INTEGER,
style TEXT DEFAULT 'none',
edited_from INTEGER,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_flux_images_created ON flux_images(created_at DESC);
CREATE TABLE IF NOT EXISTS quality_reports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
listing_id INTEGER NOT NULL,
score INTEGER NOT NULL DEFAULT 0,
grade TEXT NOT NULL DEFAULT 'E',
ready INTEGER NOT NULL DEFAULT 0,
blockers INTEGER NOT NULL DEFAULT 0,
warnings INTEGER NOT NULL DEFAULT 0,
recommendations INTEGER NOT NULL DEFAULT 0,
report_json TEXT NOT NULL DEFAULT '{}',
analyzed_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY(listing_id) REFERENCES listings(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_quality_reports_listing ON quality_reports(listing_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_quality_reports_score ON quality_reports(score, analyzed_at DESC);
CREATE TABLE IF NOT EXISTS publishing_jobs (
id TEXT PRIMARY KEY,
listing_id INTEGER NOT NULL,
platform TEXT NOT NULL,
mode TEXT NOT NULL DEFAULT 'api',
action TEXT NOT NULL DEFAULT 'publish',
status TEXT NOT NULL DEFAULT 'queued',
phase TEXT NOT NULL DEFAULT 'queued',
idempotency_key TEXT NOT NULL UNIQUE,
external_id TEXT,
external_url TEXT,
offer_id TEXT,
retries INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 3,
next_attempt_at TEXT,
claimed_by TEXT,
claimed_at TEXT,
error_code TEXT,
error_message TEXT,
payload_json TEXT NOT NULL DEFAULT '{}',
result_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
started_at TEXT,
completed_at TEXT,
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY(listing_id) REFERENCES listings(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_publishing_jobs_status ON publishing_jobs(status, next_attempt_at, created_at);
CREATE INDEX IF NOT EXISTS idx_publishing_jobs_listing ON publishing_jobs(listing_id, platform, created_at DESC);
CREATE TABLE IF NOT EXISTS publishing_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
job_id TEXT,
listing_id INTEGER NOT NULL,
platform TEXT NOT NULL,
level TEXT NOT NULL DEFAULT 'info',
event_type TEXT NOT NULL,
message TEXT NOT NULL,
details_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY(job_id) REFERENCES publishing_jobs(id) ON DELETE SET NULL,
FOREIGN KEY(listing_id) REFERENCES listings(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_publishing_events_job ON publishing_events(job_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_publishing_events_listing ON publishing_events(listing_id, id DESC);
-- Mehrbenutzer- und Sicherheitsgrundlage 1.31.0
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL DEFAULT '',
password_hash TEXT,
role TEXT NOT NULL DEFAULT 'editor',
active INTEGER NOT NULL DEFAULT 1,
avatar_color TEXT,
last_active_at TEXT,
failed_login_count INTEGER NOT NULL DEFAULT 0,
locked_until TEXT,
password_changed_at TEXT,
created_at TEXT DEFAULT (datetime('now')),
invited_by INTEGER
);
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
token_hash TEXT UNIQUE NOT NULL,
ip TEXT,
user_agent TEXT,
expires_at TEXT NOT NULL,
last_seen_at TEXT,
revoked_at TEXT,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
user_email TEXT,
action TEXT NOT NULL,
target_type TEXT,
target_id TEXT,
details TEXT,
ip TEXT,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS resource_locks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
resource_type TEXT NOT NULL,
resource_id TEXT NOT NULL,
user_id INTEGER NOT NULL,
token_hash TEXT NOT NULL UNIQUE,
acquired_at TEXT NOT NULL DEFAULT (datetime('now')),
renewed_at TEXT NOT NULL DEFAULT (datetime('now')),
expires_at TEXT NOT NULL,
client_label TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(resource_type, resource_id)
);
CREATE INDEX IF NOT EXISTS idx_resource_locks_expiry ON resource_locks(expires_at);
CREATE INDEX IF NOT EXISTS idx_resource_locks_user ON resource_locks(user_id, expires_at);
-- Natives Theme-Modul 1.36.0
CREATE TABLE IF NOT EXISTS theme_profiles (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
base_theme TEXT NOT NULL DEFAULT 'light',
values_json TEXT NOT NULL DEFAULT '{}',
created_by INTEGER,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY(created_by) REFERENCES users(id) ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS user_theme_preferences (
user_id INTEGER PRIMARY KEY,
theme_id TEXT NOT NULL DEFAULT 'inherit',
density TEXT NOT NULL DEFAULT 'comfortable',
reduced_motion TEXT NOT NULL DEFAULT 'system',
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_theme_profiles_updated ON theme_profiles(updated_at DESC);
@@ -0,0 +1,16 @@
{
admin off
}
{$VENDOO_DOMAIN} {
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy vendoo:8124
}
@@ -0,0 +1,60 @@
# Vendoo 1.32.0 Abnahmebericht
**Release:** Docker, NAS & Production Deployment Foundation
**Prüfdatum:** 09.07.2026
**Ausgangsbasis:** `Vendoo_Feature_1_31_0_Multiuser_Security_Foundation.zip`
**Basis-SHA-256:** `cad2670d663c98964b7c3b4e95e5f6e475a3bcae12921339a0a84576b77d325b`
## Ergebnis
Vendoo 1.32.0 ist als vollständiges Drüberkopierpaket erstellt. Die Code-, Migrations-, Pfad-, Sicherheits- und Paketprüfungen sind bestanden. Die reale Docker-/NAS-, Windows- und Browser-End-to-End-Abnahme konnte in der bereitgestellten Linux-Sandbox nicht ausgeführt werden, weil dort weder Docker noch PowerShell/Windows noch ein Browser zur Verfügung stehen und das native `better-sqlite3`-Modul in dieser stark begrenzten Build-Umgebung nicht innerhalb des Ausführungszeitlimits kompiliert werden konnte.
Der Release ist deshalb **für Installation und reale Umgebungsabnahme vorbereitet**, aber Docker-, Windows- und Browserbetrieb werden nicht fälschlich als praktisch getestet ausgewiesen.
## Bestandene Prüfungen
| Prüfung | Status | Ergebnis/Nachweis |
|---|---|---|
| Handover-Reihenfolge | bestanden | `00_START_HIER.md` bis `14_SOURCE_PACKAGE_CHECKSUM.txt` vollständig in vorgegebener Reihenfolge gelesen |
| Basis-ZIP SHA-256 | bestanden | stimmt exakt mit Handover überein |
| Basis-Dateiprüfsummen | bestanden | 271 von 271 Dateien `OK` |
| Reale 1.31.0-Codeanalyse | bestanden | RBAC, Sessions, Audit, Locks, Setup, Windows-Menü, FLUX-Trennung und reale Deployment-Lücken geprüft |
| Versionssynchronität | bestanden | Paket, Lockfile, Manifest, UI-Build und Windows-Setup = `1.32.0` |
| JS-/MJS-Syntax | bestanden | alle geänderten Laufzeitdateien sowie Verifikator mit `node --check` |
| Shell-Syntax | bestanden | Entry-Point, Backup und Restore mit `sh -n` |
| YAML-Syntax | bestanden | `compose.yaml` und Bind-Mount-Override mit PyYAML geladen |
| Datenbankmigration frisch | bestanden | 68 additive DB-Ausführungsblöcke; Pflichttabellen vorhanden |
| Datenbankmigration bestehend | bestanden | vorhandener Testdatensatz blieb erhalten; Publishing- und Operations-Struktur gültig |
| Lockfile-Auflösung | bestanden | sauberer `npm ci --ignore-scripts`: 151 Pakete installiert |
| Laufzeitpfade | bestanden | DB, Uploads, Backups, Operations und Logs in getrenntem temporären Datenbereich beschreibbar |
| Setup-Token Entry-Point | bestanden | fehlender Token beendet Produktion mit Exit 78; 32-Zeichen-Token akzeptiert |
| Deployment-Gate | bestanden | Version, Pfadtrennung, Readiness, Shutdown, Setup-Schutz, Origins, Container-Härtung und Datenhygiene |
| Datenhygiene | bestanden | keine `.env`, DB, Logs, Uploads, Backups, Operations, Modelle oder `node_modules` im Anwendungspaket |
| Secret-Musterscan | bestanden | keine erkannten privaten Schlüssel, AWS- oder `sk-`-Live-Schlüssel |
| FLUX/VTO-Regel | bestanden | FLUX bleibt getrennt; Hauptcontainer standardmäßig deaktiviert; freier Workflow ohne `LoadImage`; kein VTO-Wiedereinbau |
| Originalbildschutz | bestanden | geänderte Pfadlogik erzeugt keine destruktive Originalüberschreibung |
## Nicht ausgeführte beziehungsweise nicht vollständig ausführbare Prüfungen
| Prüfung | Status | Grund |
|---|---|---|
| vollständiges `npm ci` mit nativen Install-Skripten | nicht abgeschlossen | Registry-/GitHub-Prebuild war nicht verfügbar; lokaler `better-sqlite3`-Fallback kompilierte in der Sandbox auch nach 5 bzw. 10 Minuten nicht fertig |
| Serverstart und API-Smoke-Test | nicht ausgeführt | natives `better-sqlite3`-Binary dadurch nicht verfügbar |
| Docker-Build | nicht ausgeführt | `docker` ist in der Sandbox nicht installiert (`exit 127`) |
| `docker compose config` über Docker CLI | nicht ausgeführt | Docker fehlt; YAML wurde statisch erfolgreich validiert |
| Container-Healthcheck/Persistenz/Backup/Restore | nicht ausgeführt | Docker fehlt; Skripte und Mount-Logik wurden statisch geprüft |
| Reverse-Proxy-/HTTPS-Livetest | nicht ausgeführt | keine Proxy-/TLS-Laufzeit vorhanden |
| Windows-Start/Update | nicht ausgeführt | kein Windows und kein PowerShell vorhanden; reale Menüpunkte 2 und 3 statisch bestätigt |
| Login, Session, Logout, Rollen, Upload, Artikel, SmartCopy, Publish-Center | nicht ausgeführt | Server-/Browserlaufzeit nicht verfügbar |
| Dark Mode, Responsive, Tastatur/Fokus | nicht ausgeführt | kein Browser-End-to-End-Test; dieser Slice verändert keine Haupt-UI-Layouts, nur das Setup-Token-Feld im Login |
| echte Plattform-APIs | nicht ausgeführt | bewusst keine Veröffentlichung ausgelöst |
## Reale Abnahme nach Installation
Der Betreiber muss die in `INSTALLATION_1_32_0_WINDOWS_DOCKER_NAS.md` beschriebene Funktionsprüfung ausführen. Besonders wichtig sind `/readyz`, Login/Logout, Rollen, bestehende Artikel und Bilder, Upload, Containerneustart, Testbackup, Restore in einem sicheren Testpfad sowie ein Reverse-Proxy-Test mit HTTPS.
## Bekannte Folgepunkte
- Widerrufbare, minimale Browser-Extension-Tokenkopplung statt dauerhafter Cookie-Abhängigkeit bleibt ein späterer Security-Slice.
- Offline-Notfallverfahren für den verlorenen letzten Administrator bleibt ein späterer Operations-Slice.
- Ein veröffentlichtes, signiertes Container-Image und automatisierte CI-Builds sind noch nicht Bestandteil dieses Pakets.
@@ -0,0 +1,34 @@
# Vendoo 1.33.0 Abnahmebericht
**Release:** Multiplatform Deployment Wizard & Flux/Admin Fixes
**Prüfdatum:** 09.07.2026
**Basis:** Vendoo 1.32.0
## Bestandene statische Prüfungen
- Versionsgleichstand in Paket, Lockfile, UI, Compose, Manifest und Windows-Setup
- JavaScript-/MJS-Syntax der geänderten Dateien
- POSIX-Shell-Syntax von `setup.sh`
- Deployment-Gate 1.33.0
- Windows-Assistent enthält alle vier Zieltypen
- Linux-Assistent enthält Docker-, NAS- und VPS-Modus
- Compose behält non-root, read-only, Healthcheck und getrennte Volumes
- FLUX-Historie wählt beim Laden kein Bild mehr automatisch aus
- Reset-Funktion löscht weder Verlauf noch Bilder noch Jobs
- Benutzeraktionen verwenden gebundene Event-Listener
- Passwortvalidierung findet vor dem Benutzer-Update statt
- Benutzer-Update liefert einen sanitiserten Datensatz
- keine produktive `.env`, DB, Uploads, Backups, Logs, Operations oder `node_modules` im Release
## Nicht als praktisch getestet ausgewiesen
- Windows PowerShell 5.1 Laufzeit, da die Sandbox kein Windows/PowerShell enthält
- Docker-Build und Containerstart, da kein Docker-Daemon vorhanden ist
- Portainer-Import und herstellerspezifische NAS-Oberflächen
- realer VPS-Reverse-Proxy und TLS
- Browser-End-to-End-Klicktest
- native Serverlaufzeit mit `better-sqlite3`
## Abnahmeentscheidung
Das Paket ist als Drüberkopier-Release und als geführte Installationsgrundlage vorbereitet. Die reale Zielsystemabnahme muss nach `02_INSTALLATION_UND_ABNAHME.md` erfolgen. Kein nicht ausgeführter Laufzeittest wird als bestanden dargestellt.
@@ -0,0 +1,50 @@
# Vendoo 1.34.0 Abnahmebericht
**Release:** GitHub CI/CD & Zero-Edit Installer Foundation
**Prüfdatum:** 09.07.2026
**Basis:** Vendoo 1.33.0
## Umgesetzte Abnahmepunkte
- geführte Windows-Installationsmaske für lokalen Betrieb und Docker Desktop,
- geführter Shell-Assistent für Linux, macOS, NAS/Portainer und VPS,
- keine manuelle Bearbeitung von `.env`, Compose oder Caddy-Konfiguration erforderlich,
- automatisch erzeugter Erst-Admin-Code,
- Eingabevalidierung für Port, URL und Domain,
- automatisches VPS-HTTPS über getrennten Caddy-Stack,
- persistenter Runtime-Konfigurationsspeicher für Einstellungen im read-only Container,
- CI für reproduzierbare Installation, Syntax, Migrationen, Git-Sicherheit, Compose und Docker-Testbuild,
- Release-Automation für ZIP, SHA-256 und GHCR-Images,
- kontrollierter Git-Erstimport mit lokalem Sicherheitsgate,
- real angelegter Branch `release/1.34.0-initial-import`,
- real angelegter Draft Pull Request #3.
## Bestandene Prüfungen
- JavaScript-/MJS-Syntaxprüfung,
- POSIX-Shell-Syntaxprüfung,
- simulierte Installationsläufe für Docker lokal, NAS-Bind-Mount und VPS/Caddy,
- dabei erkannter und behobener Standardwert-/Prompt-Fehler im Shell-Assistenten,
- YAML-Parsing aller Compose- und GitHub-Workflow-Dateien,
- Deployment-Gate 1.34.0,
- Git-Sicherheitsgate,
- Datenbankmigrationstest gegen frische und bestehende Testdatenbank,
- bestehender Testdatensatz blieb erhalten,
- persistenter Konfigurationsspeicher einschließlich Dateirechten und Mehrzeilen-Sperre,
- Versionsgleichstand von Paket, Lockfile, UI, Manifest, Compose und Installer,
- kein produktives Secret oder Laufzeitdatum im bereinigten Release.
## Nicht als praktisch getestet ausgewiesen
- tatsächlicher WinForms-/PowerShell-5.1-Lauf auf Windows,
- Docker-Build und Containerstart mit realem Docker-Daemon,
- Docker Desktop auf Windows/macOS,
- Portainer-Import auf einem realen NAS,
- Caddy-Zertifikatsausstellung mit echter Domain und öffentlichem DNS,
- Browser-End-to-End-Abnahme,
- vollständige native Node-Laufzeit mit kompiliertem `better-sqlite3`,
- veröffentlichter GitHub-Release-Workflow und GHCR-Push.
## Abnahmeentscheidung
Das Release ist als vollständiges Drüberkopier-Paket, Zero-Edit-Installationsgrundlage und kontrollierte GitHub-Importbasis freigegeben. Zielsystemtests bleiben gemäß Installations- und Abnahmeanleitung verpflichtend. Nicht ausgeführte Laufzeittests werden nicht als bestanden dargestellt.
@@ -0,0 +1,20 @@
# Vendoo 1.34.1 Abnahmebericht
## Bestanden
- JavaScript-Syntax des Git-Sicherheitsgates und des Regressionstests
- vollständiger Arbeitsbaumscan auf sauberem Release-Quellstand
- Blockierung unversionierter `.env.local`- und Token-Testdateien
- erfolgreicher Lauf nach Entfernung der Test-Secrets
- Deployment-Gate 1.34.1
- Shell-Syntax des Linux/macOS-Deploy-Assistenten
- Versionsgleichstand in Paket, Lockfile, UI, Setup und Manifest
- GitHub-Branch `release/1.34.1-initial-import` und Draft Pull Request #4 real angelegt
- Pull Request #3 geschlossen und als ersetzt dokumentiert
## Nicht als real getestet ausgewiesen
- vollständiger Lauf unter Windows PowerShell 5.1
- echte Browser-Anmeldung und kompletter Push vom Nutzer-PC
- GitHub Actions nach vollständigem Quellimport
- Docker-/NAS-/VPS-Laufzeit, da dieser Hotfix ausschließlich das Git-Sicherheitsgate betrifft
@@ -0,0 +1,25 @@
# Vendoo 1.34.2 Abnahmebericht
## Bestanden
- JavaScript-Syntax von Staging-Builder, Staging-Regressionstest, Sicherheitsgate und Deployment-Gate
- Shell-Syntax des Linux/macOS-Deploy-Assistenten
- YAML-Parsing von CI, Release und Compose-Dateien
- Git-Staging-Regressionstest: sichere Dateien kopiert, lokale `.env.local`, Operations-, Log-, Upload-, DB- und Modelltestdaten ausgeschlossen
- `.git` des temporären Klons blieb unverändert erhalten
- Git-Sicherheitsgate auf dem vollständigen Release-Quellstand
- Secret-Regressionstest mit unversionierten Testdateien
- Deployment-Gate 1.34.2
- Shell-Installer-Simulation für Docker, NAS und VPS
- Datenbankmigrationen: 68 Einheiten auf frischer und bestehender Datenbank
- vorhandener Testdatensatz blieb erhalten
- Versionsgleichstand in Paket, Lockfile, UI, Setup, Compose und Update-Manifest
## Nicht als real getestet ausgewiesen
- vollständiger Lauf unter Windows PowerShell 5.1
- echte GitHub-Browseranmeldung und kompletter Push vom Nutzer-PC
- GitHub Actions nach vollständigem Quellimport
- echter Docker-/NAS-/VPS-Lauf
Die Windows-spezifische Prozessausgabe wurde statisch geprüft; eine echte Windows-Laufzeit steht in der Erstellungsumgebung nicht zur Verfügung.
@@ -0,0 +1,20 @@
# Vendoo 1.34.3 Abnahmebericht
## Bestanden
- Staging-Regression mit `updates/backups/slice22_1_20260707-194953/scripts/install-local-flux.ps1`
- Staging-Regression mit `updates/backups/slice22_1_20260707-194953/setup.bat`
- Staging-Regression mit `updates/backups/slice22_1_20260707-194953/setup.ps1`
- aktive Root-/scripts-Installationsdateien bleiben im Staging
- Git-Sicherheitsgate auf bereinigtem Quellstand
- JavaScript-/MJS-Syntaxprüfung
- Deployment-Gate 1.34.3
- Shell-Installer-Simulation
- Datenbankmigrationsprüfung gegen frische und bestehende Testdatenbank
## Nicht als real getestet
- Windows PowerShell 5.1 auf dem Benutzerrechner
- echter Push aus dem lokalen Projektordner
- Docker-/Portainer-/VPS-Livetest
- GitHub-Actions-Lauf nach dem vollständigen Import
@@ -0,0 +1,53 @@
# Vendoo 1.35.0 Abnahmebericht
## Bestanden
- JavaScript-/MJS-Syntax aller bestehenden und neuen Kernbestandteile
- Plattform-Architecture-Gate
- zwölf Modulmanifeste und Abhängigkeiten
- Zykluserkennung
- fehlende Capability wird blockiert
- doppelte Ressourcen-Ownership wird blockiert
- Deny-by-default-Route ohne Policy wird blockiert
- nicht berechtigter Zugriff auf registrierte Route ergibt HTTP 403
- Event-Auslieferung und Owner-Cleanup
- Lifecycle- und Modulshutdown
- sichere Theme-Werte und verbotene Token
- RGB-Bereichsprüfung
- deterministische Token-Generierung
- Light, Dark und High Contrast vorhanden
- Safe-DOM-Vertrag ohne `innerHTML`
- API-Client-Vertrag mit CSRF und Same-Origin
- Deployment-Gate 1.35.0
- Git-Sicherheitsgate: 365 Dateien ohne Secrets/Laufzeitdaten
- Git-Sicherheits-Regressionstest
- Git-Staging-Regressionstest
- persistenter Konfigurationsspeicher
- Shell-Installer-Simulation für Docker, NAS und VPS
- 68 Migrationseinheiten gegen frische Datenbank
- 68 Migrationseinheiten gegen bestehende Datenbank
- vorhandener Testdatensatz blieb erhalten
## Dependency-Test
`npm ci` wurde versucht. Die Lockdatei wurde aufgelöst, aber `better-sqlite3` konnte in der Sandbox nicht fertig gebaut werden:
1. Prebuild-Download scheiterte wegen fehlender DNS-/Netzverbindung zu GitHub.
2. Der Fallback mit lokal vorhandenen Node-Headern begann erfolgreich zu kompilieren, wurde aber beim SQLite-C-Build durch das Ausführungslimit beendet.
Dieser Punkt wird nicht als bestanden ausgegeben.
## Nicht praktisch getestet
- Windows PowerShell 5.1 und WinForms
- echter Windows-Lokalstart
- echter Docker-/NAS-/Portainer-Start
- VPS/Caddy/TLS
- Browser-End-to-End-Test
- visuelle Regression aller Seiten
- vollständiger Node-Serverstart mit nativ kompiliertem `better-sqlite3`
- GitHub Actions und GHCR-Liveausführung
## Daten- und Kompatibilitätsaussage
Keine Datenbank, Uploads, Backups, Operations-Daten, Benutzer, Artikel, API-Schlüssel, FLUX-Modelle oder ComfyUI-Daten wurden in das Paket aufgenommen oder gelöscht. Es gibt keine Framework- oder Datenbankmigration.
@@ -0,0 +1,32 @@
# Abnahmebericht Vendoo 1.36.0
## Gegenstand
Secure Theme Manager, Accessibility & Component Token Foundation.
## Erfolgreich geprüft
- JavaScript-/MJS-Syntax
- Plattform-Architektur und zwölf Modulmanifeste
- natives Theme-Modul
- 42 Design Tokens und drei integrierte Themes
- Theme-Validierung und ungültige CSS-/Script-Werte
- Deny-by-default Theme-Routen
- Benutzer-/Administrator-Policy-Trennung
- Theme-Tabellen auf frischer und bestehender Datenbank
- Git-Sicherheitsgate mit 385 geprüften Dateien und Staging-Filter
- Windows-/Docker-/NAS-/VPS-Deploymentverträge
- reproduzierbare Paketauflösung mit 151 Paketen über `npm ci --ignore-scripts`
- Release-Staging mit 384 Einzeldatei-Prüfsummen
## Nicht als real ausgeführt gewertet
- Browser-End-to-End-Test unter echtem Windows
- Docker-/NAS-/VPS-Livestart
- Caddy-/TLS-Livetest
- GitHub-Actions-Livelauf
- native Kompilierung/Ausführung von `better-sqlite3` in der Sandbox; `npm ci --ignore-scripts` war erfolgreich, native Installationsskripte wurden bewusst nicht ausgeführt
## Ergebnis
Die statische, architektonische und migrationsbezogene Abnahme ist bestanden. Die genannten plattformspezifischen Laufzeittests sind nach Installation in der Zielumgebung durchzuführen.
@@ -0,0 +1,3 @@
# Abnahmebericht 1.37.0
Siehe die vollständige Release-Abnahme im Paketroot `04_ABNAHMEBERICHT.md`. Die automatisierten Gates prüfen Secret-Migration, Verschlüsselung, CSP, Request-IDs, Telemetrie, Architektur, Deployment, Installer und Datenbankkompatibilität.
@@ -0,0 +1,31 @@
# Abnahmebericht Vendoo 1.38.0
## Ergebnis
Die statische, architektonische, migrationsbezogene und sicherheitsbezogene Abnahme ist bestanden.
## Bestanden
- vierzehn registrierte Module
- sechs native Module und acht Legacy Bridges
- native Auth-, Benutzer-, Sitzungs- und Settings-Routen
- Deny-by-default-Policies und Eingabeschemata
- letzter-Admin-Schutz
- Eigentümerprüfung beim Widerruf eigener Sitzungen
- Settings-Allowlist und Ablehnung unbekannter Felder
- spezifische Permissions für SMTP und Login-Historie
- Git-Sicherheitsgate einschließlich legitimen Quellmoduls `app/modules/sessions/`
- Secret-, Theme-, Architektur-, Deployment-, Konfigurations-, Installer- und DB-Gates
- frische und bestehende SQLite-Testdatenbank
- vorhandener Testdatensatz blieb erhalten
## Nicht als praktisch ausgeführt behauptet
- Browser-End-to-End-Abnahme unter echtem Windows
- produktiver Docker-/NAS-/VPS-Start
- Caddy-/TLS-Livetest
- echte SMTP-, OAuth- und Marktplatzverbindungen
- vollständige native `better-sqlite3`-Installation in der Sandbox
- GitHub-Actions-Livelauf vor dem vollständigen lokalen Quellpush
Die native Node-Komponente kann in der Sandbox wegen fehlendem Zugriff auf Prebuilds beziehungsweise Node-Header nicht zuverlässig gebaut werden. Dieser Punkt muss auf dem Zielsystem über `setup.bat` beziehungsweise den Docker-Build geprüft werden.
@@ -0,0 +1,19 @@
# Abnahmebericht Vendoo 1.39.0
## Bestanden
- native Modulverträge für Listings, Inventory und Media
- Entfernung der öffentlichen Legacy-Routen aus `server.mjs`
- Artikel-Allowlist, Rich-HTML-Sanitizing und Lock-Vertrag
- Papierkorbgrenze für endgültiges Löschen
- Inventory-Deduplizierung und 500er-Bulk-Limit
- Medienpfad- und Artikelreferenzschutz
- Dependency Injection ohne Datenbank-Seiteneffekt beim Modulimport
- kombinierte Git-, Architektur-, Theme-, Security-, Identity-, Catalog-, Deployment-, Installer- und Datenbank-Gates
## Nicht als real ausgeführt behauptet
- Browser-End-to-End-Test auf Windows
- nativer `better-sqlite3`-Lauf in dieser Sandbox
- Docker-/NAS-/VPS-Livestart
- GitHub-Actions-Lauf vor dem vollständigen Quellpush
@@ -0,0 +1,33 @@
# Vendoo 1.31.0 Ist- und Lückenanalyse
Stand der Prüfung: 09.07.2026
Geprüfte Basis: `Vendoo_Feature_1_31_0_Multiuser_Security_Foundation.zip`
Verifizierte SHA-256 der Basis: `cad2670d663c98964b7c3b4e95e5f6e475a3bcae12921339a0a84576b77d325b`
Die Bewertung basiert auf dem real enthaltenen Code. Paketnamen und Dokumentation wurden nicht als alleiniger Funktionsnachweis verwendet.
| Bereich | Status in 1.31.0 | Reale Fundstelle | Risiko/Lücke | Änderung in 1.32.0 |
|---|---|---|---|---|
| Versionen | bestätigt | `package.json`, Lockfile, UI-Build und Manifest = 1.31.0 | keine | auf 1.32.0 synchronisiert |
| Rollen/RBAC | bestätigt | `lib/security.mjs`, globaler `apiPermissionGuard` | einzelne Sonderrouten bleiben zusätzlich manuell zu beobachten | unverändert erhalten |
| Sessions/Login-Schutz | bestätigt, Setup-Ausnahme riskant | `lib/auth.mjs`, gehashte Tokens, Sperrlogik, Widerruf; `requireAuth` übersprang im Setup-Modus alle APIs | vor erstem Admin waren geschützte API-Routen unnötig offen; kein Offline-Notfallreset für verlorenen letzten Admin | API im Setup-Modus gesperrt; Notfallreset als Folgepunkt dokumentiert |
| CSRF/Cookies | vorhanden | Double-Submit-Cookie und Header, `HttpOnly`, dynamisches `Secure`, `SameSite=lax` | Cookie-Modus nicht konfigurierbar; Proxyannahme nur boolesch/ein Hop | Cookie-Modus konfigurierbar, Proxy-Hops/Scopes unterstützt |
| CORS/Origin | vorhanden, unvollständig | Host-/Origin-Middleware in `server.mjs` | jede Browser-Extension-Origin wurde pauschal akzeptiert | in Produktion nur konkrete Extension-Origins, unsicherer Opt-in separat |
| Audit/Locks | bestätigt | Audit-Log, `resource_locks`, Adminansicht | keine kritische Deployment-Lücke | erhalten |
| Health | teilweise | `/healthz` liefert Prozessstatus | keine Readiness-, DB- oder Schreibpfadprüfung | `/readyz` mit DB- und Volume-Schreibtest |
| Shutdown | fehlt | direkter `app.listen()` ohne Signalbehandlung | WAL/Jobs können beim Containerstopp hart beendet werden | SIGTERM/SIGINT, Server-Close, WAL-Checkpoint, DB-Close |
| Datenbankpfad | unvollständig | fest `db/vendoo.db` im Codeordner | Container-Image und Nutzerdaten nicht sauber trennbar | `VENDOO_DB_PATH` und zentrale Laufzeitpfade |
| Uploadpfad | unvollständig | fest `uploads/` im Codeordner | keine getrennte Persistenz; öffentlich statisch erreichbar | konfigurierbarer Pfad, Zugriff hinter Anmeldung |
| Uploadprüfung | Sicherheitsrisiko | Dateiendung **oder** `image/*` genügte | manipulierbarer MIME-Typ konnte beliebige Endungen umgehen | Endung **und** Bild-MIME erforderlich; Größenlimit bleibt aktiv |
| Backups | bestätigt, aber codegebunden | verifizierte ZIPs mit DB/Uploads in `operations-center.mjs` | Pfade fest an Projektroot; Live-Volume-Kopie nicht dokumentiert | separate Backup-/Operations-Volumes und sichere Stop/Backup/Start-Anleitung |
| Restore/Update | vorhanden, gestuft | Operations Center und `setup.ps1` | Container darf Anwendungscode nicht in-place überschreiben | Docker-Update nur über neues Image; Windows-Update bleibt erhalten |
| Docker/Compose | fehlt | keine entsprechenden Dateien | kein reproduzierbarer NAS-/Produktionsbetrieb | Dockerfile, Compose, Healthcheck, non-root, read-only, Volumes |
| Reverse Proxy | teilweise | Host/Origin, `PUBLIC_BASE_URL`, `trust proxy` | kein fertiger Produktionsleitfaden | HTTPS-/Proxy-Dokumentation und sichere Standardbindung |
| FLUX/ComfyUI | getrennt im Konzept | externer URL-Endpunkt; lokaler Windows-Installer | Bootstrap schreibt in Projektordner und passt nicht zu read-only Container | Container startet standardmäßig ohne FLUX; externer Dienst bleibt optional |
| Browser-Erweiterungen | real vorhanden | Chrome/Edge/Firefox/Safari-Strukturen und Pakete | Remote-Kopplung nutzt weiterhin Login-Cookie statt widerrufbarem Extension-Token | CORS gehärtet; Tokenkopplung bleibt geplanter 1.34.0-Slice |
| UI-Begriffe/Kernbereiche | weitgehend bestätigt | Navigation, Artikel, Galerie, SmartCopy, Publish und Erweiterungen im realen HTML/JS | vollständige Browser-End-to-End-Abnahme nicht statisch beweisbar | keine unnötige UI-Neuentwicklung in diesem Deployment-Slice |
| VTO | entfernt | kein aktiver FASHN-/VTO-Dienst; freier FLUX-Workflow ohne `LoadImage` | historische Dokumente enthalten weiterhin Kontext | keine VTO-Rückkehr |
## Ergebnis
1.31.0 besitzt eine echte Mehrbenutzer- und Sicherheitsgrundlage, war aber noch kein sauber containerisierbarer Produktionsstand. Die Hauptlücken lagen in der festen Kopplung von Code und Nutzerdaten, fehlender Readiness, fehlendem geordneten Shutdown, fehlenden Containerdateien sowie zu breiten Extension-Origin- und Uploadregeln.
@@ -0,0 +1,23 @@
# Vendoo Branding
Die Anwendung verwendet ab Version 1.6.2 ein gemeinsames Vendoo-Branding für Web-App, Login, mobilen Foto-Upload und Browser-Erweiterungen.
## Web-App
Assets liegen unter `public/brand/`:
- `logo/` horizontales Logo, transparente und zugeschnittene Varianten
- `icons/` App- und Mobilgrößen von 16 bis 512 Pixel
- `favicons/` ICO, PNG-Favicons, Apple Touch Icon, Android-Icons und Webmanifest
## Browser-Erweiterungen
Chrome, Edge und Firefox verwenden dieselbe Icon-Familie in 16, 32, 48 und 128 Pixeln. Popup, Browser-Toolbar, Vinted Assistant und minimierter Assistant verwenden das neue Markenzeichen.
## Farben
- Vendoo Orange: `#E63B17`
- Graphit: `#22201D`
- Warmes Off-White: `#FAF6F2`
Die Proportionen und Farben der bereitgestellten Assets sollen nicht manuell verändert werden.
@@ -0,0 +1,29 @@
# Vendoo Full Listing Editor 2026
## Ziel
Bereits gespeicherte Artikel werden nicht mehr in einem reduzierten Detailformular, sondern in einem vollständigen Arbeitsbereich bearbeitet. Generator und Listing-Editor verwenden dieselbe Rich-Text- und HTML-Logik.
## Funktionsumfang
- vollständige Bearbeitung aller Listing-Felder
- Plattform, AI-Provider, Sprache, Status, SKU und Lagerort
- Titel, Tags, Verkäufernotizen und sämtliche erkannten Attribute
- Preis und Kategorie
- Foto hinzufügen, entfernen, sortieren und als Cover festlegen
- vorhandene Fotos mit Helligkeit, Kontrast, Sättigung, Rotation, Spiegelung und Crop bearbeiten
- WYSIWYG und HTML-Code gleichzeitig sichtbar
- Änderungen im WYSIWYG erscheinen sofort im HTML-Code
- Änderungen im HTML-Code werden in den WYSIWYG-Editor zurückgeführt
- separate sandboxed Plattformvorschau
- Editor-HTML und Plattform-HTML separat kopierbar
## Datenmodell
`listings.description_html` speichert das bereinigte Rich-Text-HTML. `listings.description` bleibt als Klartext-Fallback und für Plattformen beziehungsweise Exporte erhalten.
Die neue Spalte wird über das bestehende `MIGRATIONS`-Array in `lib/db.mjs` ergänzt.
## Sicherheit
HTML wird auf unterstützte Formatierungs-Tags reduziert. Skripte, eingebettete Frames, Formulare, Event-Handler und gefährliche URLs werden entfernt. Vorschauen werden in einem `sandbox`-iframe dargestellt.
@@ -0,0 +1,61 @@
# Vendoo Listing Studio 2026
## Ziel
Der Listing-Generator ist kein Formularstapel mehr, sondern ein zusammenhängender Studio-Arbeitsplatz mit drei klaren Zonen:
1. Fotos & Medien
2. AI-Konfiguration
3. Vorschau & Bearbeitung
Die bestehende Vanilla-JS-, Express- und SQLite-Architektur bleibt erhalten.
## Fotos & Medien
- großes Cover mit vollständiger Bilddarstellung über `object-fit: contain`
- Klick auf ein Vorschaubild setzt es als Cover
- Drag & Drop sortiert die Bildreihenfolge
- maximal zehn Bilder pro Listing
- sichtbarer Foto-Check mit Qualitätsindikatoren
- bestehender Bildeditor, Hintergrundentfernung und Wasserzeichen bleiben integriert
## AI-Konfiguration
- Plattform, Provider und Modell
- Sprache und Anzahl der Varianten
- Vorlagenauswahl
- Verkäufernotizen mit Zeichenzähler
- Vorlagen übernehmen Plattform, Sprache, Hinweise und Standard-Tags
- global hinterlegte Verkäuferhinweise, Vorlagenhinweise und Artikelhinweise werden kontrolliert zusammengeführt
## Vorschau & Bearbeitung
- permanenter, kontextbezogener Ergebnisbereich
- Live-Zähler für Titel, Beschreibung und Tags
- editierbare erkannte Attribute
- Kategorie-Picker, Preis und Lagerort
- dynamische Gebührenvorschau
- nachvollziehbarer Qualitätswert
- HTML- und Plattformvorschau als optional aufklappbarer Bereich
- Speichern und Kopieren ohne Fensterwechsel
## API-Erweiterung
`POST /api/generate` akzeptiert zusätzlich:
```json
{
"template_id": 1,
"seller_notes": "Artikelspezifische Hinweise"
}
```
Standard-Tags der gewählten Vorlage werden dedupliziert mit den AI-Tags zusammengeführt.
## Qualitätsregeln
- keine neuen Frameworks
- keine neuen Datenbankspalten
- bestehende IDs und Generatorfunktionen bleiben kompatibel
- alle Farben und Zustände nutzen die Vendoo-CSS-Variablen
- Dark Mode und responsive Darstellung sind Bestandteil des Slices
@@ -0,0 +1,76 @@
# Vendoo 1.34.0 GitHub Deployment
## Repository
- Repository: `Masterluke77/vendoo`
- Sichtbarkeit: privat
- Stabiler Branch: `main`
- Entwicklungsbranch: `develop`
- Erstimport-Branch: `release/1.34.0-initial-import`
## Kontrollierter Erstimport
Unter Windows wird `GitHub-Deploy-Assistent.bat` gestartet. Der Assistent:
1. prüft beziehungsweise installiert Git für Windows über `winget`,
2. klont die vorhandene GitHub-Baseline in einen temporären Arbeitsordner,
3. verwendet oder erstellt `release/1.34.0-initial-import`,
4. kopiert nur den bereinigten Vendoo-Quellstand,
5. blockiert `.env`, Datenbanken, Uploads, Backups, Logs, Laufzeitdaten und Modelle,
6. führt nach Möglichkeit `tools/verify-git-safety.mjs` aus,
7. zeigt alle Änderungen vor dem Commit,
8. verlangt zur Freigabe die exakte Eingabe `PUSH`,
9. pusht ausschließlich den Release-Branch,
10. öffnet den vorbereiteten Pull-Request-Vergleich im Browser.
Der Assistent löscht oder verändert keine produktiven Vendoo-Daten. Der temporäre Git-Arbeitsordner wird nach Abschluss entfernt.
## Pull Request und Merge
Der Pull Request wird gegen `main` erstellt. Vor dem Merge müssen die GitHub-Actions-Prüfungen erfolgreich sein:
- reproduzierbare Installation über `npm ci`,
- Git-Sicherheitsgate,
- JavaScript-/MJS-Syntax,
- Deployment-Gate 1.34.0,
- Datenbankmigrationstest,
- Compose-Prüfung für lokal, NAS und VPS,
- Docker-Testbuild.
Empfohlen ist ein Squash-Merge. Erst danach wird ein GitHub Release `v1.34.0` veröffentlicht.
## Release-Automation
Beim Veröffentlichen eines GitHub Releases:
- wird ein bereinigtes Release-Staging erzeugt,
- werden Einzeldatei-SHA-256-Prüfsummen erzeugt,
- wird `Vendoo_1.34.0.zip` gebaut,
- wird eine SHA-256-Datei für das ZIP erzeugt,
- werden beide Dateien an das GitHub Release angehängt,
- wird ein Multi-Arch-Container für `linux/amd64` und `linux/arm64` gebaut,
- wird das Image als `ghcr.io/masterluke77/vendoo` in die GitHub Container Registry veröffentlicht,
- wird der veröffentlichte Image-Digest mit einer GitHub-Provenienz-Attestierung versehen.
Das Release-ZIP wird nicht dauerhaft in die Git-Historie committed.
## Secrets
Produktive Secrets gehören ausschließlich in:
- die lokale `.env`, die der Installer automatisch erzeugt,
- den persistenten Runtime-Konfigurationsspeicher von Vendoo,
- gegebenenfalls geschützte GitHub Environments für spätere Deployments.
Nicht zulässig sind Secrets in Quellcode, Issues, Pull Requests, Workflow-Ausgaben oder Release-Paketen.
## Späteres Produktionsdeployment
Ein automatisches Deployment auf NAS oder VPS wird erst freigeschaltet, wenn diese Gates praktisch bestätigt sind:
- Backup und Restore auf dem Zielsystem,
- Readiness nach Update,
- Rollback auf die vorherige Container-Version,
- TLS und Domainprüfung,
- getrennte Staging- und Produktionsumgebung,
- manuelle Freigabe des GitHub Environments `production`.
@@ -0,0 +1,10 @@
# Vendoo GitHub-Importstatus
- Zielrelease: `1.36.0`
- Importbranch: `release/1.36.0-theme-manager`
- Zielbranch: `main`
- Draft Pull Request: `#9`
Der vollständige Quellstand wird über `GitHub-Deploy-Assistent.bat` beziehungsweise `scripts/github-deploy.sh` übertragen. Vor dem Merge müssen Git-Sicherheitsgate, Theme-Manager-Gate, Architektur-Gate, Datenbankmigrationen und GitHub Actions erfolgreich sein.
Nicht nach GitHub gelangen dürfen `.env`, Datenbanken, Uploads, Backups, Logs, Operations-/Update-Artefakte oder FLUX-/ComfyUI-Modelle.
@@ -0,0 +1,10 @@
# Vendoo 1.39.0 GitHub-Importstatus
- Repository: `Masterluke77/vendoo`
- Importbranch: `release/1.39.0-catalog-media`
- Zielbranch: `main`
- Draft Pull Request: `#12`
Der vollständige Quellstand wird über `GitHub-Deploy-Assistent.bat` beziehungsweise `scripts/github-deploy.sh` übertragen. Der Assistent erstellt ein bereinigtes Staging, prüft Secrets und Laufzeitdaten und pusht erst nach der exakten Bestätigung `PUSH`.
Pull Request #12 darf erst nach geprüftem Diff und vollständig erfolgreicher GitHub CI zusammengeführt werden.
@@ -0,0 +1,20 @@
# Vendoo 1.23.1 Editor-/Vinted-Hotfix
## Behobene Fehler
1. Der Advanced Image Editor war nur über ein kleines Stift-Symbol erreichbar und konnte bei alten Browser-Assets scheinbar vollständig fehlen.
2. Die Vinted-Auswahl für Zustand, Marke, Größe oder Farbe konnte durch einen zu breiten DOM-Fallback das Titelfeld als erstes Eingabefeld auswählen und überschreiben.
## Umsetzung
- Sichtbarer Button **Advanced Editor öffnen** im Generator.
- Versionsparameter für `app.js` und `style.css`.
- `Cache-Control: no-store` für HTML, JavaScript und CSS.
- Build-Kennung 1.23.1 im HTML und beim Browserstart.
- Strikte, labelgebundene Feldauflösung in allen Chrome-, Edge- und Firefox-Paketen.
- Zusätzlicher Titelfeldschutz für Choice-Felder.
- Extension-Version 1.6.1.
## Nutzeraktion nach Installation
Die Browser-Erweiterung muss in der Erweiterungsverwaltung einmal über **Neu laden** aktualisiert werden. Danach die Vinted-Verkaufsseite vollständig neu laden.
@@ -0,0 +1,23 @@
# Vendoo 1.23.2 FLUX-/Editor-Hotfix
## FLUX Studio
- `System & ComfyUI` befindet sich unterhalb von `Prompt & Auftrag`.
- Die angeheftete Bildvorschau enthält keine darunterliegende Systemkarte mehr und kann dadurch die Bildaktionen nicht überdecken.
- Das komplette Job-Center kann ein- oder ausgeklappt werden.
- Jeder Auftrag besitzt eine kompakte Kopfzeile und einen einzeln ein-/ausklappbaren Detailbereich.
- Aktive Aufträge werden beim ersten Laden geöffnet; terminale Aufträge bleiben kompakt.
## Advanced Image Editor
- Hintergrundentfernung ist als Editor-Operation integriert.
- Wasserzeichen unterstützt Text, Deckkraft sowie oben/unten links/rechts und Mitte.
- Beide Werkzeuge werden nicht destruktiv als neue Version gespeichert.
- Die bisherigen separaten Buttons wurden entfernt.
- Die Werkzeuge funktionieren in Generator, Listing-Editor und FLUX Studio.
## Unveränderte Schutzregeln
- Kein VTO/FASHN.
- Keine produktiven Daten oder Modelle im Paket.
- Vendoo Link bleibt 1.6.1; der Vinted-Feldschutz wird nicht zurückgenommen.
@@ -0,0 +1,16 @@
# Hotfix Studio Flow Detailnavigation
## Fehler
Der Button **Prüfen & bearbeiten** lud die Listing-Detailansicht, ohne zuvor den Listings-Tab sichtbar zu schalten. Der Editor wurde dadurch in einem ausgeblendeten Bereich aufgebaut.
## Korrektur
`showDetail(id)` prüft nun zentral, ob der Listings-/Historie-Tab aktiv ist. Falls nicht, wird dieser vor dem Laden des Listings aktiviert. Damit funktionieren Detailaufrufe aus:
- Studio Flow
- Attention Queue
- Listings-Tabelle
- weiteren internen Bereichen
Zusätzlich werden ungültige Listing-IDs abgefangen.
@@ -0,0 +1,134 @@
# Vendoo 1.32.0 Installation, Update und Prüfung
## A. Windows-Update von 1.31.0
1. Vendoo sowie offene Setup-, Node- und FLUX-Fenster schließen.
2. Das Release-ZIP vollständig in einen temporären Ordner entpacken.
3. Im entpackten Paket den Ordner `vendoo` öffnen.
4. Den **Inhalt** dieses Ordners nach `W:\ChatGPT\Vendoo` kopieren.
5. Windows-Abfrage **Dateien im Ziel ersetzen** bestätigen.
6. `W:\ChatGPT\Vendoo` vorher **nicht löschen, leeren oder umbenennen**.
7. `.env`, `db\vendoo.db`, `uploads`, `backups`, `operations`, lokale FLUX-Modelle und ComfyUI-Daten nicht löschen.
8. `W:\ChatGPT\Vendoo\setup.bat` starten.
9. Menüpunkt **3 Update** ausführen.
10. Danach Menüpunkt **2 Starten** ausführen.
11. `http://127.0.0.1:8124/healthz` und `http://127.0.0.1:8124/readyz` prüfen.
Windows benötigt die neuen Pfadvariablen nicht. Ohne Eintrag bleiben DB, Uploads und Backups exakt an ihren bisherigen Orten.
## B. Docker-Neuinstallation
1. Release entpacken und in den gewünschten Server-/NAS-Ordner wechseln.
2. `.env.example` als `.env` kopieren.
3. Einen starken Einrichtungs-Code erzeugen, mindestens 32 zufällige Zeichen, und als `VENDOO_SETUP_TOKEN` setzen. Beispiele:
```bash
openssl rand -hex 32
```
PowerShell:
```powershell
[Convert]::ToHexString([Security.Cryptography.RandomNumberGenerator]::GetBytes(32)).ToLower()
```
Die `.env` anschließend nur für den Administrator lesbar machen (`chmod 600 .env` auf Linux/NAS).
4. Für lokalen Test `PUBLIC_BASE_URL` zunächst leer lassen. Für Produktion die echte HTTPS-URL und Host-/Origin-Allowlist setzen.
5. Starten:
```bash
docker compose config
docker compose build --pull
docker compose up -d
```
6. Zustand prüfen:
```bash
docker compose ps
docker compose logs --tail=200 vendoo
```
7. Lokal `http://127.0.0.1:8124/readyz` öffnen. Erwartet wird HTTP 200 und `"ok": true`.
8. Vendoo öffnen, ersten Administrator anlegen und dabei den `VENDOO_SETUP_TOKEN` als Einrichtungs-Code eingeben.
9. Danach Reverse Proxy und HTTPS konfigurieren. Port 8124 nicht direkt aus dem Internet veröffentlichen.
10. Testbackup erstellen und Prüfsumme kontrollieren.
## C. Portainer/NAS
### Empfohlen: Named Volumes
`compose.yaml` direkt als Stack verwenden. Portainer legt fünf persistente Volumes an. Das Image läuft ohne Rootrechte.
### Option: sichtbare NAS-Ordner
1. Einen dedizierten Zielordner verwenden, zum Beispiel `/volume1/docker/vendoo`, und darunter anlegen:
```text
runtime/db
runtime/uploads
runtime/backups
runtime/operations
runtime/logs
```
2. Diese Ordner UID/GID 1000 schreibbar machen. Den Vendoo-Container nicht als Root starten.
3. Compose mit Override starten:
```bash
docker compose -f compose.yaml -f compose.bind-mounts.example.yaml up -d --build
```
Bei `Kein Schreibzugriff ... (Container-UID 1000)` keine Root-Ausführung aktivieren, sondern die Ordnerrechte korrigieren. `LOCAL_IMAGE_ENABLED` bleibt im Hauptcontainer standardmäßig `false`; ein vorhandenes FLUX/ComfyUI wird separat betrieben und über `LOCAL_IMAGE_URL` angebunden.
## D. Docker-Update
```bash
./scripts/docker-backup.sh
# neuen Vendoo-Code über den alten Codeordner kopieren; .env nicht ersetzen
docker compose config
docker compose build --pull
docker compose up -d --force-recreate
docker compose ps
docker compose logs --tail=200 vendoo
```
Anschließend `/readyz`, Login, Artikelübersicht, ein vorhandenes Bild, Speichern eines Testartikels, SmartCopy und Publish-Center ohne echte Veröffentlichung prüfen.
### Rollback
1. Container stoppen.
2. Vorheriges Image beziehungsweise vorherigen Code wieder verwenden.
3. Volumes nicht löschen.
4. Container starten und Readiness prüfen.
5. Nur wenn eine Datenmigration das verlangt, das zuvor erzeugte gemeinsame DB-/Upload-Backup in einen sicheren Testpfad zurückspielen und erst danach produktiv restaurieren.
## E. Backup und Restore
Backup mit kurzem geordnetem Stopp:
```bash
./scripts/docker-backup.sh
```
Restore ersetzt die aktuell gemounteten DB-, Upload-, Backup-, Operations- und Logdaten. Das Skript prüft eine vorhandene SHA-256-Datei und erstellt vorab automatisch ein zusätzliches Sicherheitsbackup:
```bash
./scripts/docker-restore.sh /pfad/zum/vendoo-data.tar.gz --confirm
```
Danach zwingend `/readyz`, Login, Benutzer, Artikel, Bilder und Backup-Liste prüfen.
## F. Funktionsprüfung
- Login, Logout und erneute Anmeldung
- Rollen-/Adminschutz
- Artikel laden, erstellen, bearbeiten und speichern
- Bild hochladen und erneut abrufen
- Galerie-Viewer und Zoom
- SmartCopy öffnen und Inhalte kopieren
- Publish-Center laden, ohne echte Veröffentlichung auszulösen
- `/healthz` und `/readyz`
- Containerneustart; Artikel und Bilder müssen erhalten bleiben
- Backup erzeugen und SHA-256 prüfen
- FLUX-Ausfall: Vendoo muss weiter starten und Kernfunktionen bereitstellen
@@ -0,0 +1,105 @@
# Vendoo 1.33.0 Installation und Abnahme
## 1. Bestehende Windows-Installation aktualisieren
1. Vendoo und FLUX schließen.
2. Release entpacken.
3. Den Inhalt von `vendoo` über den vorhandenen Projektordner kopieren.
4. Vorhandene Dateien ersetzen, den Zielordner nicht vorher leeren.
5. `.env`, Datenbank, Uploads, Backups, Operations, lokale Modelle und ComfyUI-Daten nicht löschen.
6. `setup.bat` starten.
7. **3 Update** ausführen.
8. **2 Starten** ausführen.
## 2. Neue Windows-Installation
`setup.bat` starten und unter **1 Installieren / Installationsziel wählen** auswählen:
- **Windows lokal:** Node.js, npm und lokale Projektordner
- **Docker Desktop:** Compose-Build, getrennte Volumes und automatischer Setup-Code
- **NAS/Portainer:** Übergabe an den Linux-/NAS-Assistenten
- **VPS/Linux:** Installation direkt auf dem Zielserver
Der gewählte aktive Modus wird in `.vendoo-install-mode` gespeichert. Diese Datei enthält keine Geheimnisse.
## 3. Linux, NAS oder VPS
```bash
chmod +x setup.sh
./setup.sh
```
Auswahl:
1. Docker auf diesem Linux-/Docker-Host mit Named Volumes
2. NAS/Portainer mit sichtbaren `runtime`-Bind-Mounts
3. VPS hinter HTTPS-Reverse-Proxy
Der Assistent prüft Docker und das Compose-Plugin, erzeugt bei Bedarf `.env` sowie einen starken `VENDOO_SETUP_TOKEN`, validiert Compose und startet Vendoo.
### NAS
Der NAS-Modus legt folgende Ordner an:
```text
runtime/db
runtime/uploads
runtime/backups
runtime/operations
runtime/logs
```
Port 8124 wird im LAN veröffentlicht. Keine direkte Internet-Portfreigabe verwenden.
### VPS
- echte öffentliche `https://`-URL angeben
- DNS und TLS vorab oder anschließend korrekt konfigurieren
- Reverse Proxy auf `127.0.0.1:8124` weiterleiten
- Port 8124 nicht öffentlich freigeben
- `VENDOO_TRUST_PROXY=true` nur hinter dem eigenen Proxy verwenden
## 4. FLUX im Docker-Betrieb
FLUX bleibt ein getrennter Dienst. Im Docker-Container wird ein Host-Dienst über folgende URL erreicht:
```env
LOCAL_IMAGE_URL=http://host.docker.internal:8188
```
`LOCAL_IMAGE_ENABLED` nur aktivieren, wenn FLUX/ComfyUI tatsächlich separat läuft und abgesichert ist.
## 5. Abnahme
### Deployment
- `/healthz` liefert HTTP 200
- `/readyz` liefert HTTP 200 und `ok: true`
- Neustart erhält Benutzer, Artikel und Bilder
- Backup wird erzeugt und hat SHA-256
- Docker-Status zeigt `healthy`
### FLUX Studio
- Seite öffnen: Vorschau **Auswahl & Varianten** bleibt leer
- Historie ist sichtbar, aber kein Bild ist automatisch markiert
- Historienbild anklicken: Vorschau erscheint
- **Arbeitsbereich zurücksetzen**: Auswahl und Formular werden geleert/zurückgesetzt
- Bilder, Verlauf und Job-Center bleiben erhalten
### Benutzerverwaltung
- Benutzerliste laden
- Bearbeiten-Button öffnet das richtige Benutzerkonto
- Name, Rolle und Status speichern
- ungültiges Passwort verhindert die gesamte Speicherung
- gültiges Passwort wird gesetzt
- letzter aktiver Administrator kann nicht deaktiviert oder herabgestuft werden
## 6. Rollback
1. Vorheriges Vendoo-Paket über den Code kopieren.
2. `.env`, DB, Uploads und Volumes nicht ersetzen oder löschen.
3. Windows: `setup.bat` → Update → Starten.
4. Docker: `./setup.sh` → Aktualisieren oder vorheriges Image/Code bauen.
5. Readiness und Datenbestand prüfen.
@@ -0,0 +1,112 @@
# Vendoo 1.34.0 Zero-Edit-Installation
## Grundsatz
Für keine unterstützte Betriebsart muss eine `.env`, Compose-Datei oder Proxy-Konfiguration manuell bearbeitet werden. Der Installer sammelt nur notwendige Angaben, validiert sie und schreibt die Konfiguration automatisch.
AI-, SMTP- und Marktplatz-Zugangsdaten werden nach dem ersten Login unter **Vendoo → Einstellungen** gepflegt. Im Docker-/NAS-/VPS-Betrieb werden diese Werte in einem persistenten Konfigurationsvolume gespeichert und nach Neustarts wieder geladen.
## Windows lokal
1. `setup.bat` doppelklicken.
2. **Lokal auf diesem Windows-PC** wählen.
3. Erreichbarkeit festlegen:
- nur dieser PC,
- privates LAN.
4. Port bestätigen oder ändern.
5. optional eine LAN-Basisadresse für QR-Uploads eingeben.
6. optional FLUX aktivieren.
7. **Installieren** anklicken.
8. Erst-Admin-Code aus der Zwischenablage bei der ersten Einrichtung einfügen.
Node.js wird geprüft. Fehlt Node.js, bietet der bestehende Installer eine automatische Installation an.
## Windows mit Docker Desktop
1. Docker Desktop starten.
2. `setup.bat` doppelklicken.
3. **Docker Desktop auf diesem Windows-PC** wählen.
4. Zugriff nur lokal oder im privaten LAN festlegen.
5. Port und optional QR-Basisadresse festlegen.
6. **Installieren** anklicken.
Der Assistent erzeugt `.env`, Setup-Code und Installationsmodus automatisch. Die App bleibt standardmäßig nur auf `127.0.0.1` erreichbar.
## Linux oder macOS mit Docker
```sh
chmod +x setup.sh
./setup.sh
```
Im Menü **Docker auf Linux/macOS/Docker Desktop** wählen. Der Assistent fragt Port und FLUX-Konfiguration ab und startet anschließend Compose.
## NAS / Portainer
1. Vendoo-Ordner auf das NAS kopieren.
2. im Ordner `chmod +x setup.sh && ./setup.sh` ausführen.
3. **NAS / Portainer / privates LAN** wählen.
4. Port und LAN-Basisadresse eingeben.
5. Installation starten.
Der Assistent legt automatisch folgende sichtbare Runtime-Verzeichnisse an:
- `runtime/db`
- `runtime/uploads`
- `runtime/backups`
- `runtime/operations`
- `runtime/logs`
- `runtime/config`
Diese Verzeichnisse werden bei Updates nicht gelöscht.
## VPS mit automatischem HTTPS
Voraussetzungen:
- Domain zeigt per DNS auf den VPS,
- Ports 80 und 443 sind erreichbar,
- Docker Engine und Compose-Plugin sind installiert.
Ablauf:
```sh
chmod +x setup.sh
./setup.sh
```
Dann **VPS / öffentlicher Server mit automatischem HTTPS** wählen und den Domainnamen ohne Protokoll eingeben. Der integrierte Caddy-Stack beantragt und erneuert TLS-Zertifikate automatisch. Vendoo selbst veröffentlicht Port 8124 nicht direkt ins Internet.
## Persistenter Konfigurationsspeicher
Im lokalen Windows-Betrieb verwendet Vendoo weiterhin die lokale `.env`. In Docker setzt der Installer automatisch:
```text
VENDOO_CONFIG_PATH=/app/data/config/vendoo.env
```
Die Eingabemasken schreiben dort ihre Werte mit restriktiven Dateirechten. Das Haupt-Dateisystem des Containers bleibt schreibgeschützt.
## Backup und sensible Konfiguration
Normale Docker-Backups enthalten Datenbank, Uploads, Backups, Operations und Logs. Der persistente Runtime-Konfigurationsspeicher mit API-/SMTP-/Marktplatzschlüsseln wird bewusst nicht in das normale Datenarchiv aufgenommen, damit ein weitergegebenes Backup nicht automatisch alle Zugangsdaten enthält.
Bei einer Wiederherstellung auf einem neuen System werden Betriebswerte durch den Installationsassistenten neu erzeugt und externe Zugangsdaten anschließend über **Vendoo → Einstellungen** erneut eingetragen. Dazu muss keine Datei manuell bearbeitet werden.
## Updates
Im Linux-/NAS-/VPS-Assistenten erstellt **Aktualisieren** zuerst automatisch ein Sicherheitsbackup. Danach werden Image beziehungsweise Quellcontainer neu gebaut, gestartet und über `/readyz` geprüft.
Unter Windows bleibt der bestehende Update- und Rollback-Ablauf erhalten.
## Nicht automatisch verändert
- Datenbank
- Uploads und Originalbilder
- Benutzer
- Artikel
- Backups
- Operations-Daten
- FLUX-Modelle
- ComfyUI-Daten
- API-Schlüssel
@@ -0,0 +1,31 @@
# Vendoo Listings UI 2026
## Ziel
Die Listings-/Historie-Seite bildet die operative Übersicht aller Artikel. Sie folgt der freigegebenen Vendoo-Designsprache und ersetzt die alte Kartenliste durch eine dichte, bildorientierte Arbeitsliste.
## Funktionsumfang
- Volltextsuche über bestehende Listing-Suche
- Plattform- und Statusfilter
- Zeiträume 7, 30 und 90 Tage, aktuelles Jahr, gesamter Zeitraum und benutzerdefinierte Daten
- Spaltenkonfiguration mit Speicherung im Browser
- Seitengrößen 10, 20, 50 oder alle
- Seitennavigation mit direkten Seitenschaltflächen
- Auswahl einzelner Listings und Auswahl der aktuellen Seite
- Batch Publish, Nachbearbeiten, Preisänderung, Statusänderung, Duplizieren, Etikettendruck und Löschen
- CSV- und JSON-Export
- Direktänderung des Status pro Tabellenzeile
- Zeilenaktionen Öffnen, Duplizieren und Löschen
- Publish-Status-Badges je Plattform
## Technische Regeln
Die Umsetzung bleibt vollständig in der bestehenden Vanilla-Architektur:
- Markup: `public/index.html`
- Verhalten: `public/app.js`
- Design: `public/style.css`
- keine neuen Frameworks
- keine Änderungen am Datenbankschema erforderlich
- vorhandene API-Endpunkte und CSRF-Absicherung werden weiterverwendet
@@ -0,0 +1,28 @@
# Vendoo Publish-Center 2026
## Ziel
Das Publish-Center bündelt alle Arbeitsschritte zwischen fertigem Listing und Veröffentlichung in einer einzigen, kontextstabilen Oberfläche.
## Bereiche
- **Smart Copy:** Felder, HTML/Text, Fotos und Plattformwechsel
- **Direkt veröffentlichen:** Etsy- und eBay-API mit vorheriger Datenprüfung
- **eBay Queue:** Status, Fehler, Wiederholungen und Verarbeitung
- **Geplant:** zeitgesteuerte Veröffentlichungen mit Plattform und Zeitpunkt
## UX-Regeln
- keine internen Arbeitsabläufe in neuen Browserfenstern
- Produktbild, Titel und SKU bleiben im Kontext sichtbar
- Fehler und fehlende Pflichtfelder sind direkt handlungsfähig
- externe Plattformen öffnen nur dann einen neuen Tab, wenn die Plattform selbst benötigt wird
- alle Statusfarben verwenden die zentralen Vendoo-Tokens
## Technische Grundlage
- Vanilla JavaScript in `public/app.js`
- Markup in `public/index.html`
- Design-Tokens und responsive Komponenten in `public/style.css`
- bestehende Endpunkte für Smart Copy, Etsy, eBay Queue und Scheduling
- Session-, Rollen- und CSRF-Schutz bleiben unverändert aktiv
@@ -0,0 +1,50 @@
# Vendoo 1.24.0 Responsive UI, FLUX-Auftragsarchiv und Bildergalerie
## Ziel
Version 1.24.0 schließt konkrete Bedienungs- und Verwaltungsprobleme zwischen Slice 31 und dem späteren Batch-Image-Slice. Der Release verändert keine bestehende FLUX-Modellinstallation und führt keine Virtual-Try-on-Funktion ein.
## Responsive Härtung
Die bisherige Listing-Tabelle erzwang auf kleineren Ansichten eine Mindestbreite von bis zu 1080 Pixeln. Unterhalb von 860 Pixeln wird sie nun als Kartenliste dargestellt. Plattform, Provider, Preis, Status, Lagerort und Aktualisierung bleiben als beschriftete Zeilen lesbar. Benutzerdefiniert ausgeblendete Spalten bleiben auch mobil ausgeblendet.
Zusätzlich wurden Breiten, Umbrüche und Overflow-Verhalten für Filterleisten, Batch-Aktionen, Pagination, FLUX-Job-Center, Galerie, Formulare und zentrale Arbeitsbereiche abgesichert.
## Hintergrundentfernung
`background_sensitivity` wird als Wert von 0 bis 100 in den nicht destruktiven Bearbeitungsparametern gespeichert. Vorschau und Sharp-Rendering verwenden dieselbe dynamische Schwellwert- und Feather-Logik.
- niedriger Wert: konservative Entfernung, mehr Kantenschutz
- hoher Wert: aggressivere Entfernung ähnlicher Hintergrundfarben
## FLUX-Auftragsarchiv
Die additive Spalte `flux_prompt_jobs.archived_at` trennt aktive Historie und Archiv. Nur terminale Aufträge können archiviert werden. Laufende, wartende oder abbrechende Aufträge werden serverseitig übersprungen.
Funktionen:
- einzeln oder gesammelt archivieren
- einzeln oder gesammelt wiederherstellen
- einzelne oder mehrere archivierte Aufträge löschen
- gesamtes Archiv löschen
- serverseitige Pagination und Statusfilter
- erzeugte Bilder bleiben beim Löschen von Auftragsmetadaten erhalten
## Bildergalerie
Der neue Navigationsbereich „Bilder“ aggregiert vorhandene Dateien aus:
- `flux_images`
- `image_edit_versions`
- `ai_model_photos`
- den Fotoverweisen aktiver Listings
Doppelte Dateipfade werden zusammengeführt und mit mehreren Quellen-Badges dargestellt. Die Galerie bietet Raster-/Listenansicht, Suche, Quellenfilter, Favoriten, Sortierung, Pagination, Mehrfachauswahl, ZIP-Download, Lightbox, Editor-Übergabe und Generator-Übernahme. Dateien aktiver Listings werden beim Löschen geschützt.
## Nicht enthalten
- keine FASHN- oder VTO-Engine
- keine Änderung an FLUX-Modellen
- keine Datenbank-, Upload-, Listing- oder Schlüsselbereinigung
- keine Hintergrundjobs außerhalb des bestehenden Vendoo-Prozesses
- keine reale Windows-, GPU- oder ComfyUI-Abnahme ohne Nutzerausgaben
@@ -0,0 +1,84 @@
{
"release": "1.24.0",
"date": "2026-07-08",
"checks": {
"javascript_and_esm_syntax": {
"status": "passed",
"files": 51
},
"json_validation": {
"status": "passed",
"files": 18
},
"html_ids": {
"status": "passed",
"total": 592,
"unique": 592,
"duplicates": 0
},
"css_structure": {
"status": "passed",
"opening_braces": 2471,
"closing_braces": 2471
},
"responsive_listing_rules": {
"status": "passed",
"mobile_card_layout": true,
"fixed_minimum_width_removed_below_1180": true,
"hidden_column_preferences_preserved": true
},
"background_removal_sensitivity": {
"status": "passed",
"low_sensitivity_transparent_pixels": 60256,
"high_sensitivity_transparent_pixels": 80660,
"higher_value_removes_more": true
},
"database_migration": {
"status": "passed",
"additive_column": "flux_prompt_jobs.archived_at",
"existing_flux_image_preserved": true
},
"flux_archive_semantics": {
"status": "passed",
"terminal_jobs_archivable": true,
"active_jobs_protected": true,
"restore": true,
"single_delete": true,
"multi_delete": true,
"delete_all": true,
"generated_images_retained_by_design": true
},
"media_library": {
"status": "passed",
"sources": ["flux", "edited", "ai", "listing"],
"search": true,
"filters": true,
"favorites": true,
"grid_and_list": true,
"pagination": true,
"multi_select": true,
"zip_download": true,
"lightbox": true,
"editor_handoff": true,
"listing_image_delete_protection": true
},
"vinted_extension_regression_guard": {
"status": "passed",
"variants": 5,
"title_field_protection_present": true,
"extension_version_changed": false
},
"package_sources": {
"status": "passed",
"registry": "https://registry.npmjs.org/",
"internal_openai_or_artifactory_sources": false
}
},
"not_claimed": [
"real Windows PowerShell 5.1 acceptance",
"real browser interaction on the user's installation",
"real NVIDIA GPU acceptance",
"real ComfyUI queue/history acceptance",
"real mapped-drive W: acceptance"
]
}
@@ -0,0 +1,59 @@
# Vendoo 1.25.0 Responsive Detail Editor, Gallery UX, Smart Copy und FLUX Prompt Lab
## Ziel
Version 1.25.0 korrigiert die verbliebenen Breitenprobleme in der Listing-Bearbeitung und überarbeitet mehrere Bedienwege, die im produktiven Einsatz unruhig, zu eng oder nicht mehr erreichbar waren. Der Release baut auf 1.24.0 auf und bleibt vollständig als Drüberkopier-Update installierbar.
## Listing-Bearbeitung
- Der Detail-Editor reagiert per Container Query auf die tatsächlich verfügbare Inhaltsbreite und nicht nur auf die gesamte Browserbreite.
- Fotoleiste, Listing-Daten, Beschreibung, Plattformvorschau und Kontextkarten reduzieren sich kontrolliert von drei auf zwei und schließlich eine Spalte.
- Formularfelder, Quill-Werkzeugleiste, Iframes, Textbereiche, Aktionsleisten und lange Inhalte besitzen konsequente `min-width: 0`- und Umbruchregeln.
- Zusätzliche Media-Query-Fallbacks halten den Editor auch in Browsern ohne aktive Container-Query-Auswertung bedienbar.
## Bildergalerie
- Auswahlfelder sind als präzise eigene Checkbox-Komponente umgesetzt und liegen sauber innerhalb der Bildfläche.
- Favoriten befinden sich als separates Overlay oben rechts.
- Die große Vorschauaktion liegt als eindeutige, zentrierte Leiste unten im Bild und kollidiert nicht mit Auswahl oder Favorit.
- Titel können über zwei Zeilen laufen; Metadaten werden sauber gekürzt.
- Bearbeiten, Verwenden, Download und Löschen stehen in einem stabilen 2×2-Aktionsraster.
- Raster- und Listenansicht sowie mobile Ein- und Zweispaltenansichten bleiben erhalten.
## Publish und Smart Copy
- Aktualisieren verwendet einen ruhigen Ladezustand mit Text und `aria-busy`; der gesamte Button rotiert nicht mehr.
- Smart Copy öffnet wieder in einem eigenen responsiven Modal.
- Das Modal enthält Titel, Beschreibung, Tags, Metadaten, Fotos, Kopieraktionen, Plattformstart und Veröffentlichungsstatus.
- Vorheriges/nächstes Listing kann direkt im Modal gewechselt werden.
- Nach dem Markieren als veröffentlicht wird das Modal sauber geschlossen und der Publish-Bereich neu geladen.
## FLUX Studio
### Ergebnisse & Favoriten
- Serverseitige Pagination mit 5, 10 oder 15 Bildern pro Seite.
- Vorherige-/Nächste-Navigation und aktuelle Seitenangabe.
- Favoritenfilter und Löschaktionen laden die korrekte Seite neu.
### Job-Center
- Aktive Aufträge und Archiv verwenden kompakte Seitengrößen von 5, 10 oder 15 Einträgen.
- Bestehende Archiv-, Wiederherstellungs-, Mehrfachauswahl- und Löschfunktionen bleiben erhalten.
### Prompt Lab
- Der bisherige einfache Prompt-Verbesserer öffnet ein eigenes Prompt Lab.
- Lokale Strukturierung funktioniert ohne API-Aufruf.
- AI-Veredelung nutzt den aktuell aktiven Text-Provider: Claude, OpenAI, OpenRouter oder Ollama.
- Profile: präzise, Produkt/Marketplace, kreativ und cinematisch.
- Optionaler Schutz der Motividentität sowie Vermeidung erfundener Texte, Logos und Wasserzeichen.
- Ergebnis, Provider, Modell und kurze AI-Hinweise werden sichtbar dargestellt.
- Der optimierte Prompt kann direkt zurück ins FLUX Studio übernommen werden.
## Unveränderte Sperrregeln
- Kein FASHN VTON und kein Virtual Try-on.
- FLUX bleibt ein freier Prompt-Bildgenerator.
- Keine Datenbank, Listings, Uploads, `.env`, Schlüssel, ComfyUI-Installation oder FLUX-Modelle werden entfernt.
- Keine internen Paketquellen.
@@ -0,0 +1,30 @@
{
"release": "1.25.0",
"static_checks": {
"javascript_esm_syntax_files": 51,
"json_files": 18,
"unique_html_ids": 612,
"duplicate_html_ids": 0,
"css_brace_depth": 0
},
"functional_mock_checks": {
"database_migrations": true,
"flux_slice30_mock": true,
"advanced_image_editor_render": true,
"background_sensitivity_low_vs_high": true,
"listing_editor_container_responsive": true,
"gallery_card_controls": true,
"smart_copy_modal": true,
"publish_refresh_without_whole_button_rotation": true,
"flux_history_page_sizes": [5, 10, 15],
"flux_job_page_sizes": [5, 10, 15],
"prompt_lab_providers": ["claude", "openai", "openrouter", "local"],
"vinted_title_guard_preserved": true
},
"not_claimed_as_real_acceptance": [
"Windows PowerShell 5.1 update on W drive",
"interactive browser acceptance with user data",
"real AI provider request",
"real NVIDIA GPU or ComfyUI render"
]
}
@@ -0,0 +1,5 @@
# Vendoo 1.25.1 Adaptive Bildergalerie
Dieser Hotfix ersetzt die bisherige Galerie-Kartenkomponente vollständig. Das Raster berechnet Kartenanzahl und Kartenbreite automatisch aus dem tatsächlich verfügbaren Platz. Die gesamte Bildfläche ist die Vorschauaktion. Auswahl und Favorit bleiben als kompakte, skalierende Overlays erhalten. Die vier Bildaktionen bilden ein responsives Aktionsdock. Die Seitennavigation ist oberhalb und unterhalb der Galerie vorhanden und erlaubt einen direkten Sprung zu jeder Seite.
Die Umsetzung orientiert sich an etablierten Karten-, Auswahl- und Paginierungsmustern: Inhalt und Aktionen gehören zu einer klar scanbaren Karte, Auswahl wird durch Checkbox plus Oberflächenzustand angezeigt und Pagination gibt sowohl Seitengröße als auch direkte Navigation vor.
@@ -0,0 +1,34 @@
{
"release": "1.25.1",
"package_type": "full_overlay_update",
"checks": {
"javascript_syntax": "passed",
"json_validity": "passed",
"html_unique_ids": "passed",
"css_parse": "passed",
"gallery_static_release_gate": "passed",
"database_migrations": "passed",
"existing_database_row_preserved": "passed",
"flux_archive_semantics": "passed",
"runtime_data_excluded": "passed"
},
"gallery": {
"adaptive_auto_fit_grid": true,
"card_container_queries": true,
"full_image_click_target": true,
"legacy_open_button_removed": true,
"adaptive_selection_overlay": true,
"adaptive_favorite_overlay": true,
"adaptive_action_dock": true,
"pagination_top_and_bottom": true,
"direct_page_jump": true,
"touch_behavior": true,
"keyboard_accessibility": true
},
"not_claimed": [
"real Windows update on W drive",
"interactive production browser acceptance",
"native npm regression suite in this build environment"
],
"note": "The native npm regression suite could not be reinstalled in the build environment because external better-sqlite3 build artifacts were temporarily unreachable. This hotfix changes only frontend HTML, CSS and gallery JavaScript; syntax, static release gates and additive database migration tests passed."
}

Some files were not shown because too many files have changed in this diff Show More