Island Boundaries, Package Policy, and Performance Baseline¶
Purpose¶
Define strict guardrails so the migration stays modular without becoming fragmented into dozens of services/bundles/packages, while meeting performance needs for:
- ~285,000 products
- ~20,000 vehicles with fitment mappings
- ~50 suppliers (stock/price imports)
- ~60 platforms (orders/stock/tracking/invoices)
- Composite wheel sets without native SKU
Decision Summary¶
- Use a small fixed island set (max 5 deployables in Day 1, including existing ERP middleware).
- Do not create a service per supplier/platform. Use a connector plugin model inside integration islands.
- Keep shared code to max 3 internal Composer packages; avoid shared domain-entity bundles across islands.
- Use precomputed read models for stock, fitment, and wheel sets; do not compute these from raw tables on every storefront request.
- Prefer asynchronous integration flows (queues + outbox) and synchronous APIs only for low-latency reads.
Day 1 Deployable Topology¶
| Deployable | Scope | Why Separate |
|---|---|---|
webshop |
Catalog read APIs, cart/checkout, orders, customers, admin | Core transactional domain and storefront latency |
stock-import |
Supplier file/API ingestion, article matching, stock normalization | Security isolation + bursty import workload |
platform-export |
Platform connectors, exports, order import, tracking/invoice push | High IO workload and connector-specific retries |
vehicle-data |
Vehicle source sync, fitment rules, mapping/projections | Independent data lifecycle and compute |
erp-middleware (existing) |
Odoo sync boundary | Already isolated and operational |
Constraint: no additional deployables unless the split criteria in this document are met.
Anti-Fragmentation Rules¶
When to create a new Symfony application¶
Create a new app only when at least 2 are true:
- Distinct trust/security boundary (for example, isolated FTP ingress).
- Distinct scaling profile (5x+ higher CPU/IO needs than current host app).
- Distinct release cadence requiring independent deploy windows.
- Clear data ownership with low synchronous coupling to existing app.
If fewer than 2 are true, keep it as a module in an existing island.
When to create a shared Composer package¶
Create package only when all are true:
- Reused by at least 2 islands.
- Stable API expected for 6+ months.
- Contains no app-specific ORM entities or business workflows.
If not, keep code local to island.
Shared package cap¶
Cap internal shared packages at 3:
atraxion/contracts(cross-island event and API DTO contracts only)atraxion/integration-sdk(HTTP/FTP clients, retry/idempotency utilities)atraxion/foundation(value objects, ids, money, clock, shared primitives)
Avoid shared Symfony bundles with mutable domain models (Article, Order, Vehicle, etc.).
Integration Model (Suppliers + Platforms)¶
Use one connector runtime per island, not one service per connector:
stock-import: supplier adapters implementSupplierFeedAdapterInterface.platform-export: platform adapters implementPlatformConnectorInterface.- Connector config stored in DB (credentials, schedule, format, retry policy, throttling).
- All connector jobs run through queue workers with:
- idempotency key per inbound/outbound message
- exponential backoff
- dead-letter queue and operator replay tooling
This keeps 50 suppliers and 60 platforms in configuration + plugins, not deployables.
Data Ownership and Contracts¶
- Each island owns its schema and migrations.
- No direct cross-island DB reads.
- Cross-island communication uses synchronous REST for user-facing reads needing immediate response.
- Cross-island communication uses asynchronous events for stock, fitment, platform orders, tracking, and invoice updates.
- Apply outbox/inbox pattern for at-least-once delivery without double-processing.
Performance Baseline¶
Catalog and Stock (Webshop)¶
Use projection tables optimized for storefront reads:
article_availability_projection- article id
- sellable qty
- best price
- next delivery date
- updated timestamp
Updated by stock events from stock-import.
Target:
- Product/search read endpoints p95 < 200 ms (cached/optimized queries).
Vehicle Fitment (Vehicle Data + Webshop Read Model)¶
Store precomputed fitment in projection:
product_vehicle_mappingkeyed by(vehicle_variant_id, article_id)- include score, front/rear position, OE marker
Rebuild incrementally on:
- vehicle source changes
- product spec changes
- manual fitment rule changes
Target:
- Vehicle-to-product lookup p95 < 250 ms.
Wheel Sets (Composite Article Without Native SKU)¶
Introduce deterministic virtual set key:
set_key = hash(wheel_id, tyre_id, tpms_id, mounting_type, axle_config)
Projection table:
wheel_set_projectionset_key- component ids
- computed sellable qty
- computed price
- vehicle scope
- updated timestamp
Quantity rule (standard set):
sellable_qty = floor(min(wheel_qty, tyre_qty) / 4)
For staggered sets, use axle-aware component pairs with explicit front/rear calculation rules.
Target:
- Set list/detail p95 < 300 ms without runtime brute-force joins.
Export and Import Throughput (Integration Islands)¶
- Use batch processing (chunked reads/writes).
- Keep per-connector watermark/checkpoint state for resumable processing.
- Use read replicas for heavy export reads when needed.
- Separate queues by workload class:
high-priorityfor order imports/status updates,bulkfor stock exports/full feed generation.
Runtime and Scalability Defaults¶
- Scale workers horizontally before splitting services.
- Use Redis for cache + transient locks.
- Use queue-backed async jobs for non-request work (Symfony Messenger).
- Keep one relational DB engine family across islands (MySQL/MariaDB) for operational simplicity.
- Add a dedicated search engine only when measured query latency/filter complexity exceeds relational targets.
Rollout Strategy¶
- Build all Day 1 islands in one monorepo with strict module boundaries.
- Implement contracts + projections first (stock, fitment, sets), then UI/features.
- Run dual-write/dual-read validation for stock and set quantities before cutover.
- Enforce split/package guardrails in architecture review checklist.
Acceptance Criteria¶
- No more than 5 deployables in Day 1 landscape.
- No per-supplier/per-platform deployables created.
- Internal shared package count <= 3.
- Stock, fitment, and set projections implemented with measurable SLIs.
- All cross-island writes are API/event based (no direct DB coupling).