Skip to content

Technical Approach — New Platform

ZWE-394

Proposed technical approach for the Navision connection on the new Zwerfkei Backend, tracked on ZWE-394. Draft — pending review with Florian.

This page covers the new platform's approach (Laravel, DDD-structured backend). For how the current system works, see Legacy Integration.


Architecture layer

The backend has no SOAP client or Navision integration yet (checked composer.json and app/, both clean). Proposed placement, following the existing DDD structure (Domain/Application/Infrastructure/Presentation):

  • Infrastructure/Navision/ — shared SOAP client wrapper (connection, WSDL config for the three services LS/NAV/Kei), used by every domain that talks to Navision. Mirrors the existing pattern where domain-specific service providers live in Infrastructure/{Domain}/Providers/.
  • Domain-specific jobs — e.g. Application/Order/Jobs/SubmitOrderToNavision, dispatched from the existing Order domain when an order is confirmed. Same for Product, Customer once those flows are built.

Outbound (Web → NAV, e.g. SubmitOrder): a queued Job, not a cron-polled queue table like the legacy k3_synchronization pattern. QUEUE_CONNECTION=database is already configured — use Laravel's native queue instead of reimplementing the legacy's manual GET_LOCK + status-column queue.

Inbound (NAV → Web, e.g. price/stock sync): Laravel's scheduler (app/Console/Kernel.php) running a sync command at a fixed interval, replacing the legacy's continuous cron-loop polling.


Authentication & credentials

  • Same pattern as legacy: HTTP Basic Auth per WSDL service (LS/NAV/Kei each have their own username/password).
  • New config/navision.php, values from .env (NAVISION_LS_USERNAME, NAVISION_LS_PASSWORD, etc.) — never hardcoded, mirrors how the legacy K3retail_gateway config array works but through Laravel's config system instead of a raw PHP array in config.php.
  • NAV sandbox credentials for actually testing this are in 1Password — not yet shared with us (see comment on ZWE-459).

Error handling & retries

  • Catch SoapFault explicitly, log with full context (operation, request payload with sensitive fields redacted, fault message).
  • Use Laravel's built-in job retry mechanism ($tries, backoff()) instead of the legacy's manual 10-attempt counter + 5-minute error lock — same intent, native Laravel tooling.
  • Failed jobs land in Laravel's standard failed_jobs table, giving us a built-in audit trail without custom tables.
  • A rejected/failing submission must not leave the source record (order, etc.) in an inconsistent state — mirrors the same requirement already stated in ZWE-421's Definition of Done.

Synchronization strategy

  • Outbound (orders): immediate dispatch on order confirmation, not batched — matches the legacy's queue-then-cron pattern but removes the up-to-5-minute delay.
  • Inbound (price/stock): frequency is pending — the ZWE-389 open question on whether this is push or pull, and at what interval, hasn't been answered by the ERP administrator yet. Whatever frequency comes back, the scheduler-command approach above works unchanged; only the interval config value depends on the answer.
  • Avoid overloading NAV: reuse the legacy's $filter-style narrow queries where possible (see Business Central API README — filtering guidance for the future REST path too).

Monitoring

  • Failed jobs table + Laravel's queue failed event, wired to the same alerting channel already used elsewhere in the backend (Mailhog locally, whatever's configured for staging/production).
  • A scheduled health-check command that flags if inbound sync hasn't run successfully within N × the expected interval — same intent as the legacy's checkK3Sync, native Laravel implementation.

Risks

Risk Impact Mitigation
NAV downtime/timeout during checkout-time calls Order confirmation blocked or delayed Queue the submission async, don't block the customer-facing request on NAV's response
WSDL schema drift between environments (test vs. production NAV) Silent field mismatches, rejected submissions Pin WSDL version/cache per environment, alert on schema fetch changes
Duplicate order submission on retry Double order in NAV, financial impact Idempotency key (own nav_id counter, same pattern as legacy) checked before resubmission
Missing/unmapped field silently dropped Data loss, hard to detect Explicit mapping table (ZWE-391) with a "field without equivalent" section, not implicit dropping
Credential rotation Integration breaks unnoticed Credentials in .env/secrets manager, not hardcoded; failed-auth alert on the health check above
Rate limiting / overloading NAV with frequent polls NAV performance impact, Zwerfkei-side throttling Narrow $filter-style queries, conservative polling interval pending the ERP administrator's answer above
OCP sync queue growing unbounded (GetSyncBuffer/DeleteSyncBuffer) Orders and item-availability entries pile up in NAV's queue tables (11176106/11176114) if never processed, unbounded growth over time DeleteSyncBuffer must run on a schedule to actually commit queued entries to the Transaction Journal, not just read them — flagged by Jasper as a risk during review, the final flow (when/how often to call DeleteSyncBuffer) is still pending alignment

Open questions blocking full sign-off

  • Inbound sync frequency for price/stock (push vs. pull, interval) — pending ERP administrator answer, tracked on ZWE-389.
  • Review with Florian not yet done — this page is a draft proposal, not yet approved.

Legacy Integration SubmitOrder Core Webshop Endpoints