From octo-api
Shopware 6.7 Plugin "FfOctoApi" — Ventrata OCTO API für Tourismus-Ticketing (GoldenTours, GoCity, RheinKurier, Demo). Nutze diesen Skill bei: "OctoApi", "OCTO", "Ventrata", "FfOctoApi", "GoldenTours", "GoCity", "RheinKurier", "ff_octo_product", "Ticket-Booking", "Availability-Check", "Booking-Reservation" — auch bei kleinen Bugfixes, Features oder Code-Reviews. Auch bei Fragen zu konkreten Tickets/Pässen/Touren von GoldenTours/GoCity (z.B. "Was kostet der London Explorer Pass?") — dann Ticket-ID aus den Referenzdateien nachschlagen und gezielten API-Request ausführen. Auch bei der dazugehörigen Shopware-App "FfResubmission" und dem "ResubmissionAppServer": "Wiedervorlage", "Resubmission", "Offline-Produkt", "RheinKurier-Produkt anlegen", "AppServer", "Iframe-Modul", "customProductTemplate", "manifest.xml" (siehe references/appserver-integration.md). Nutze context7 für aktuelle Shopware-6.7-/Symfony-Doku.
How this skill is triggered — by the user, by Claude, or both
Slash command
/octo-api:ff-octo-apiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Das Plugin **FfOctoApi** (Composer: `ff/octo-api`, Version 1.0.26) integriert die **Ventrata OCTO API** (Open Connectivity for Tourism & Experiences) in Shopware 6.7. Es ermöglicht:
references/administration.mdreferences/api-clients.mdreferences/api/ids/gocity.jsonreferences/api/ids/goldentours.jsonreferences/appserver-integration.mdreferences/architecture.mdreferences/booking-flow.mdreferences/configuration-services.mdreferences/controllers-routes.mdreferences/database-entities.mdreferences/deep/_index.mdreferences/deep/app-manifest__manifest_xml.mdreferences/deep/appserver__assets__vue__controllers__custom-product__add_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__components__CollapsibleSection_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__components__DaySelector_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__components__DurationInput_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__components__StartTimeSelector_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__components__UnitForm_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__custom-product-form_vue.mdreferences/deep/appserver__assets__vue__controllers__custom-product__edit_vue.mdDas Plugin FfOctoApi (Composer: ff/octo-api, Version 1.0.26) integriert die Ventrata OCTO API (Open Connectivity for Tourism & Experiences) in Shopware 6.7. Es ermöglicht:
symfony/uid ^7.3FfOctoApi\Das Plugin heißt immer FfOctoApi. Es kann an verschiedenen Orten liegen:
custom/static-plugins/FfOctoApi/custom/plugins/FfOctoApi/ff/octo-apiSuche nach dem Plugin mit: find . -name "FfOctoApi.php" -path "*/FfOctoApi/*" oder grep -r "FfOctoApi" composer.json
FfOctoApi/
├── src/
│ ├── FfOctoApi.php # Plugin-Hauptklasse
│ ├── Client/Octo/ # Supplier-spezifische Clients
│ │ ├── GoldenToursClient.php # London-Touren (Ventrata)
│ │ ├── GoCityClient.php # City-Pässe (GoCity Staging)
│ │ ├── RheinKurierClient.php # OFFLINE — Shopware-App-basiert
│ │ └── DemoClient.php # Test-Client (Ventrata)
│ ├── Core/Api/Octo/ # API-Client-Infrastruktur
│ │ ├── AbstractOctoApiClient.php # Basis: HTTP, Auth, Caching, Headers
│ │ ├── OctoApiClient.php # OCTO-Methoden (Products, Availability, Bookings)
│ │ ├── CachedOctoApiClient.php # PSR-6 Cache-Decorator
│ │ ├── OctoApiClientRegistry.php # Tagged-Iterator-Registry aller Clients
│ │ ├── OctoApiClientInterface.php # Client-Interface
│ │ ├── CachedOctoApiClientInterface.php
│ │ └── OctoErrorResponse.php # API-Fehler-Wrapper
│ ├── Controller/ # API-Routen (Admin + Storefront)
│ │ ├── OctoProductController.php # GET/POST /api/octo/products
│ │ ├── PropertyController.php # POST /api/property-group/create
│ │ ├── VariantController.php # POST /api/product-variants/create
│ │ ├── MediaController.php # POST /api/product-media/assign
│ │ ├── PriceController.php # POST /api/product-price/update
│ │ ├── AvailbilityController.php # POST /octo-api/availability/*
│ │ ├── SessionController.php # POST /octo-api/session/*
│ │ ├── CartController.php # POST /checkout/line-item/add (Priority 100!)
│ │ └── NotificationController.php # POST /notification/notify
│ ├── Service/ # Business-Logic
│ │ ├── PriceService.php # Preisberechnung & Währungsumrechnung
│ │ ├── PropertyService.php # Property-Group-Erstellung aus API-Optionen
│ │ ├── MediaService.php # Medien-Download & -Zuweisung
│ │ ├── SessionService.php # Session-Datenverwaltung
│ │ ├── BookingService.php # Buchungsreservierung mit Validierung
│ │ ├── ValidationService.php # Constraint-basierte Validierung
│ │ ├── StateService.php # Order-State-Machine-Übergänge
│ │ ├── CheckoutService.php # Buchungsbestätigung/-stornierung
│ │ └── ScheduledTask/ # Geplante Aufgaben (alle 3h)
│ │ ├── OctoApiWarmCacheTask.php
│ │ ├── OctoApiWarmCacheHandler.php
│ │ ├── OctoApiPriceUpdaterTask.php
│ │ └── OctoApiPriceUpdaterHandler.php
│ ├── Subscriber/ # Event-Listener
│ │ ├── OrderSubscriber.php # Bestätigung/Stornierung bei Zahlungsstatus
│ │ ├── ProductSaveSubscriber.php # Preis-Update bei Produkt-Speicherung
│ │ ├── ProductDetailSubscriber.php # Criteria-Erweiterung für PDP
│ │ └── ProductDeleteSubscriber.php # Orphan-Cleanup
│ ├── Core/Content/OctoProduct/ # Custom Entity
│ │ ├── OctoProductDefinition.php # Entity: ff_octo_product
│ │ ├── OctoProductEntity.php # uuid, identifier, product (JSON)
│ │ └── OctoProductCollection.php
│ ├── Extension/Content/Product/ # Shopware Product-Extension
│ │ └── ProductExtension.php # ff_octo_product_id FK + ffOctoProduct Relation
│ ├── Constraint/ # Validierung
│ │ ├── ConstraintCollectionRegistry.php
│ │ ├── ValidationResponse.php
│ │ ├── Availability/
│ │ │ ├── AvailabilityCheckConstraintCollection.php
│ │ │ └── AvailabilityCalendarConstraintCollection.php
│ │ └── Booking/
│ │ └── ReservationConstraintCollection.php
│ ├── Enum/ConstraintCollectionEnum.php
│ ├── Constant/OctoErrorCode.php
│ ├── Helper/ClassHelper.php
│ ├── Struct/MediaFile.php
│ ├── Twig/TwigFilters.php # json_decode Filter + ff_octo_listing_price Function
│ ├── Command/
│ │ ├── LogTestCommand.php # ff:log:test
│ │ └── PropertyGroupCleanupCommand.php # ff:property-group:cleanup (DDEV only)
│ ├── Migration/
│ │ ├── Migration1755686022CreateOctoProductTable.php
│ │ ├── Migration1757686022CreateProductExtension.php
│ │ └── Migration1768988700AddOctoProductIdentifierIndex.php
│ └── Resources/
│ ├── config/ # DI, Routen, Plugin-Config
│ ├── app/storefront/src/ # JS-Plugins, Services, SCSS
│ ├── app/administration/src/ # Admin-Komponenten
│ ├── views/storefront/ # Twig-Templates
│ └── snippet/ # DE/EN Übersetzungen
└── docs/ # Ausführliche Dokumentation
OctoApiClientRegistry — Verwaltet alle OCTO-Clients via Tagged Iterator (octo.api.client)ConstraintCollectionRegistry — Verwaltet Validierungs-Constraints (octo.validation.constraint-collection)OctoApiClientInterface
└── AbstractOctoApiClient (HTTP, Auth, Headers, Config)
└── OctoApiClient (OCTO API Methoden)
└── CachedOctoApiClient (PSR-6 Caching Decorator)
├── GoldenToursClient
├── GoCityClient
├── RheinKurierClient (OFFLINE = true)
└── DemoClient
Ein zentrales Konzept: Clients mit OFFLINE = true (RheinKurier) machen keine API-Calls. In jedem Code-Pfad, der API-Aufrufe macht, muss geprüft werden:
if ($client->isOffline()) {
return []; // oder: Preis aus pricingFrom berechnen
}
Betroffene Stellen: AbstractOctoApiClient::request(), AvailbilityController, CartController, BookingService, CheckoutService, OrderSubscriber, OctoApiWarmCacheHandler, OctoApiPriceUpdaterHandler
RheinKurier ≠ rein manuell. Die RheinKurier-Produkte werden NICHT von Hand als Shopware-Produkt gepflegt, sondern über den separaten ResubmissionAppServer (Shopware App, eigenes Repo) angelegt. Dieser schreibt per Admin-API ein
productmitffOctoProduct-Association (identifier='rheinkurier',reference='GTP2') in dieff_octo_product-Entity und ruft zur Variantenerzeugung sogar den FfOctoApi-VariantController(/api/product-variants/create) auf.OFFLINE = trueheißt nur: zur Laufzeit kein OCTO-API-Call. Details:references/appserver-integration.md.
Das Plugin nutzt Symfony\Component\Uid\Uuid::fromStringToHex() um reproduzierbare IDs zu erzeugen:
// Property Group ID
Uuid::fromStringToHex("{apiProductId}-property-group")
// Property Group Option ID
Uuid::fromStringToHex("{apiProductId}-{optionReference}-{identifier}-property-group-option")
// Unique Line-Item ID (identisch in 3 Klassen!)
$unitString = implode('__', array_map(fn($u) => "{$u['id']}_q{$u['quantity']}", $units));
Uuid::fromStringToHex($productId . $unitString)
OctoCartCollector implementiert CartProcessorInterface + CartCollectorInterface mit Priority 6000 und überschreibt die Shopware-Preisberechnung für OCTO-Produkte komplett.
ProductSaveSubscriber setzt eine Context-Extension octo_price_update um Endlosschleifen bei Preis-Updates zu verhindern.
| Supplier | Identifier | API | Produkte | Status |
|---|---|---|---|---|
| GoldenTours | goldentours | Ventrata (api.ventrata.com/octo/) | 278 (London) | Online |
| GoCity | gocity | GoCity Staging (api.staging.gocity.tech/octo/) | 49 (25 Städte) | Online |
| RheinKurier | rheinkurier | — | via Shopware App | OFFLINE |
| Demo | demo | Ventrata | Test-Produkte | Online |
FfOctoApi.config.*)| Key | Typ | Default | Beschreibung |
|---|---|---|---|
expirationTime | Select | 10800 | Cache-TTL in Sekunden (0/3600/7200/10800) |
bookingReservationTime | Select | 30 | Reservierungsdauer in Minuten (5-60) |
goldentoursApiKey | Password | — | GoldenTours API Key |
gocityApiKey | Password | — | GoCity API Key |
demoApiKey | Password | — | Demo API Key |
provisionValue | Float | 10 | Provision in % (vom Netto abgezogen) |
testingEnvironment | Bool | true | Octo-Env: test Header senden |
OCTO_API_KEY_GOLDEN_TOURSOCTO_API_KEY_GO_CITYOCTO_API_KEY_DEMOrk_product_provision_value — Produkt-spezifische Provision (überschreibt globale)Octo-Env: test ist IMMER Pflicht. Es darf NIEMALS ein Request ohne diesen Header oder mit Octo-Env: live ausgeführt werden.curl -s -X GET "https://api.ventrata.com/octo/products" \
-H "Authorization: Bearer $OCTO_API_KEY_GOLDEN_TOURS" \
-H "Octo-Capabilities: octo/pricing, octo/content" \
-H "Accept-Language: de-DE, en-GB" \
-H "Octo-Available-Languages: de, en" \
-H "Content-Type: application/json" \
-H "Octo-Env: test" | jq .
curl -s -X GET "https://api.staging.gocity.tech/octo/products" \
-H "Authorization: Bearer $OCTO_API_KEY_GO_CITY" \
-H "Octo-Capabilities: octo/pricing, octo/content" \
-H "Accept-Language: de-DE, en-GB" \
-H "Octo-Available-Languages: de, en" \
-H "Content-Type: application/json" \
-H "Octo-Env: test" | jq .
Nutze diesen Request wenn Informationen zu einem bestimmten Ticket benötigt werden, statt alle Produkte zu laden. Die <TICKET-ID> ist die UUID des Produkts (siehe references/api/ids/goldentours.json).
curl -s -X GET "https://api.ventrata.com/octo/products/<TICKET-ID>" \
-H "Authorization: Bearer $OCTO_API_KEY_GOLDEN_TOURS" \
-H "Octo-Capabilities: octo/pricing, octo/content" \
-H "Accept-Language: de-DE, en-GB" \
-H "Octo-Available-Languages: de, en" \
-H "Content-Type: application/json" \
-H "Octo-Env: test" | jq .
Nutze diesen Request wenn Informationen zu einem bestimmten Ticket benötigt werden, statt alle Produkte zu laden. Die <TICKET-ID> ist die UUID des Produkts (siehe references/api/ids/gocity.json).
curl -s -X GET "https://api.staging.gocity.tech/octo/products/<TICKET-ID>" \
-H "Authorization: Bearer $OCTO_API_KEY_GO_CITY" \
-H "Octo-Capabilities: octo/pricing, octo/content" \
-H "Accept-Language: de-DE, en-GB" \
-H "Octo-Available-Languages: de, en" \
-H "Content-Type: application/json" \
-H "Octo-Env: test" | jq .
Die API-Keys werden über Umgebungsvariablen bereitgestellt:
OCTO_API_KEY_GOLDEN_TOURS — GoldenTours API KeyOCTO_API_KEY_GO_CITY — GoCity API KeyWenn der User eine Frage zu einem bestimmten Ticket, Pass, Tour oder Attraktion von GoldenTours oder GoCity stellt, folge diesem Ablauf:
Lies die entsprechende ID-Datei und suche den passenden Eintrag per Name (Fuzzy-Match auf den Suchbegriff des Users):
references/api/ids/goldentours.jsonreferences/api/ids/gocity.jsonFalls der User keinen Supplier nennt, durchsuche beide Dateien. Falls mehrere Treffer möglich sind, zeige dem User die Kandidaten und frage welches gemeint ist.
Führe einen gezielten Request mit der gefundenen <TICKET-ID> aus (siehe "Einzelnes Ticket abfragen" oben). Niemals alle Produkte laden wenn nur ein einzelnes Ticket gefragt ist.
Analysiere den API-Response und beantworte die Frage des Users. Typische Fragen und wo die Antworten im Response liegen:
| Frage | Response-Feld |
|---|---|
| Preis / Was kostet...? | options[].units[].pricingFrom[] (retailPrice, originalPrice) |
| Optionen / Varianten | options[] (id, internalName, availabilityType) |
| Beschreibung / Was ist...? | description, shortDescription, content.*.description |
| Verfügbare Einheiten (Erwachsene, Kinder...) | options[].units[] (internalName, type, pricingFrom) |
| Öffnungszeiten / Wann? | availabilityType, options[].availabilityLocalStartTimes |
| Stornierungsbedingungen | options[].cancellationCutoff, options[].cancellationCutoffAmount |
| Bilder | content.*.images[], options[].content.*.images[] |
| Treffpunkt / Wo? | content.*.meetingPoint, content.*.location |
| Dauer | options[].durationAmount, options[].durationUnit |
| Enthaltene Leistungen | content.*.inclusions, content.*.exclusions |
| Highlights | content.*.highlights |
User fragt: "Was kostet der Dubai Explorer Pass?"
gocity.json → Treffer: {"name": "Dubai Explorer Pass", "id": "ae508b91-8017-3476-be44-b652f1c0fe19"}curl -s -X GET "https://api.staging.gocity.tech/octo/products/ae508b91-8017-3476-be44-b652f1c0fe19" \
-H "Authorization: Bearer $OCTO_API_KEY_GO_CITY" \
-H "Octo-Capabilities: octo/pricing, octo/content" \
-H "Accept-Language: de-DE, en-GB" \
-H "Octo-Available-Languages: de, en" \
-H "Content-Type: application/json" \
-H "Octo-Env: test" | jq .
options[].units[].pricingFrom[] extrahieren und dem User aufbereitet präsentieren.Für detaillierte Implementierungsdetails lies die entsprechenden Referenzdateien:
| Thema | Datei | Wann lesen |
|---|---|---|
| Architektur & Design Patterns | references/architecture.md | Bei Architektur-Fragen, Verzeichnisstruktur |
| API-Client-Architektur & Methoden | references/api-clients.md | Bei Client-Änderungen, neuen Suppliern, API-Calls |
| Booking-Workflow (5 Phasen) | references/booking-flow.md | Bei Buchungs-/Checkout-Änderungen |
| Preisberechnung (statisch + dynamisch) | references/price-calculation.md | Bei Preis-/Währungs-/Provisions-Anpassungen |
| Session-Management & Keys | references/session-management.md | Bei Session-/Cart-Problemen |
| Controller & Routen | references/controllers-routes.md | Bei neuen/geänderten API-Endpunkten |
| Database-Entities & Schema | references/database-entities.md | Bei Migrationen, Entity-Änderungen |
| Storefront-JavaScript | references/storefront-javascript.md | Bei Frontend-Plugin-Änderungen |
| Twig-Templates | references/twig-templates.md | Bei Template-Anpassungen |
| Admin-Komponenten | references/administration.md | Bei Admin-UI-Änderungen |
| Scheduled Tasks & Subscribers | references/scheduled-tasks-subscribers.md | Bei Event-/Task-Anpassungen |
| Ventrata OCTO API Referenz | references/ventrata-octo-api.md | Bei API-Fragen, neuen Capabilities |
| GoCity API & Produkte | references/gocity-api.md | Bei GoCity-spezifischem Code, Datum-Format |
| GoldenTours Produktdaten | references/goldentours-products.md | Bei GoldenTours-Produkten, Feldern, Preisen |
| Supplier-Vergleich | references/supplier-comparison.md | Bei supplier-spezifischem Code |
| Konfiguration & Services | references/configuration-services.md | Bei Config-/DI-Änderungen |
| GoldenTours Produkt-IDs | references/api/ids/goldentours.json | Schnellreferenz: Name → ID aller GoldenTours-Attraktionen |
| GoCity Produkt-IDs | references/api/ids/gocity.json | Schnellreferenz: Name → ID aller GoCity-Attraktionen |
| ResubmissionAppServer-Integration | references/appserver-integration.md | Bei RheinKurier-Produktanlage, Wiedervorlagen, AppServer ↔ ff_octo_product, Cross-Repo-Vertrag (VariantController) |
| Deep Reference (Per-Datei) | references/deep/_index.md | Vollständige methodengenaue Doku JEDER Quelldatei (220 Dateien: Plugin + Tests + AppServer + Manifest). Nachschlagen, wenn exakte Signatur/Methode/Route/Fallstrick einer konkreten Datei gebraucht wird. |
readonly deklariertprivate readonly ...)#[Route(...)])octo (Datei: var/log/octo-{env}.log)PluginManager.register() in main.jsFfBuyBox auf [data-ff-buy-box]document.$emitterStateService mit Proxy-PatternShopware.Service()sw-product-api-product-form für Produktzuweisungsw-product-detail und sw-product-detail-baseproduct.extensions.foreignKeys.ffOctoProductId != nullapp.request.session.get('octo-product-session-' ~ product.id)|json_decode{{ jsonString|json_decode }}OctoApi.* Namespacesrc/Client/Octo/ — CachedOctoApiClient erweiternIDENTIFIER, SUPPLIER_ID, DESTINATION_ID, BASE_URL, COLOR, API_KEY_CONFIG_KEY, API_ENV_KEYclients.xml mit Tag octo.api.clientconfig.xmlsrc/Controller/ erstellen oder erweitern#[Route(path: '...', name: '...', methods: ['POST'], defaults: ['_routeScope' => ['storefront'|'api']])]controllers.xml registrieren (mit Dependencies)octo.validation.constraint-collection)XmlHttpRequest und _httpCache Defaults beachten# Alle Quality-Checks
composer quality-gate # psalm + ecs + phpcs
composer all-checks # psalm + ecs + phpcs + rector
# Einzeln
composer psalm # Statische Analyse (Level 4)
composer ecs # Easy Coding Standard
composer phpcs # PHP CodeSniffer (PSR-12)
composer rector # Code-Modernisierung (Shopware 6.7)
Wenn du Anpassungen am FfOctoApi-Plugin vornimmst, aktualisiere immer auch die entsprechenden Skill-Referenzdateien unter ~/.claude/skills/ff-octo-api/references/. Der Skill muss jederzeit den aktuellen Stand des Plugins widerspiegeln.
controllers-routes.md, api-clients.md) und architecture.mdcontrollers-routes.mdscheduled-tasks-subscribers.mdapi-clients.md, supplier-comparison.md, architecture.mddatabase-entities.mdtwig-templates.mdstorefront-javascript.mdadministration.mdprice-calculation.md und/oder booking-flow.mdconfiguration-services.mdsession-management.mdarchitecture.md einNutze context7 für aktuelle Dokumentation zu:
# Beispiel context7-Queries:
- "shopware entity definition custom entity"
- "shopware cart processor interface"
- "shopware scheduled task handler"
- "symfony validator constraint collection"
- "symfony http client options"
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub zone1987/claude-a-dev-team --plugin octo-api