LogShip ERP - System Architecture

Amazon SP-API Security Assessment — Prepared for Amazon Developer Assessment Team

Confidential EU Region v1.0 - March 2026
🏢 Business & System Overview

Company

LogYou GmbH — Logistics, warehouse management, and ERP solutions provider based in Germany.

Product: LogShip ERP — A multi-tenant web-based ERP platform. Our customers (Amazon sellers/merchants) use LogShip to manage their orders, create accounting invoices, generate shipping labels, and handle multi-channel e-commerce operations.

Amazon Integration Purpose

LogShip integrates with the Amazon Selling Partner API (SP-API) to provide our customers (Amazon sellers) with:

  • Import Amazon orders with customer data for fulfillment processing
  • Create accounting invoices for their Amazon orders
  • Upload VAT invoices to Amazon for EU marketplace compliance
  • Generate shipping labels (DHL/Sendcloud) with customer delivery addresses
  • Report delivery confirmations and tracking back to Amazon
  • Support EU marketplaces: DE, FR, IT, ES, NL, BE, UK, PL, SE, AT

Hosting

🇩🇪

Hetzner (Germany/EU)

Proxmox VE • OPNsense Firewall • Debian

Users

👥

Internal team & authorized customers

Role-based access control

Data Scope

📄

Customer PII for fulfillment & invoicing

Encrypted AES-256 • No payment data

🗺 High-Level Architecture Diagram
graph TB subgraph INTERNET["🌐 Internet / Public Zone"] USER["💻 End User Browser"] AMAZON["📦 Amazon SP-API
sellingpartnerapi-eu.amazon.com"] AMAZON_LWA["🔑 Amazon LWA
api.amazon.com/auth/o2/token"] DHL["🚚 DHL API
api-eu.dhl.com"] SENDCLOUD["📨 Sendcloud API
panel.sendcloud.sc"] SHOPIFY["🛒 Shopify API
GraphQL v2025-10"] end subgraph FWZONE["🛡 OPNsense Firewall Appliance"] OPNSENSE["OPNsense
Stateful Packet Inspection
IDS/IPS • Auto-Updated"] end subgraph SERVER["🖥 Dedicated Server - Debian (EU/Germany)"] subgraph PROXY["Nginx Reverse Proxy"] NGINX["⚙ Nginx
TLS Termination
Port 443 → localhost:3001"] end subgraph FRONTEND["Nuxt 3 Application (Port 3001)"] SSR["SSR Server
Node.js v20 / PM2 Cluster x2"] API_ROUTES["Server API Routes
/server/api/*"] end subgraph BACKEND["Internal Backend Services (localhost only)"] IDEMPIERE["🏢 iDempiere ERP
REST API"] POSTGREST["📊 PostgREST
Direct DB API"] ELASTIC["🔎 Elasticsearch 8
Search Engine"] STRAPI["📝 Strapi CMS
Media Management"] end subgraph DATABASE["Database Layer"] POSTGRES[("💾 PostgreSQL
iDempiere Database
Encrypted at Rest")] end end subgraph SUBNET["🖧 Private Subnet (Same Network)"] LARAVEL["🔧 Laravel Server
Internal API
Not Public"] end USER -->|"HTTPS/TLS 1.2+"| OPNSENSE OPNSENSE -->|"Filtered Traffic"| NGINX NGINX -->|"HTTP localhost"| SSR SSR --> API_ROUTES API_ROUTES -->|"localhost"| IDEMPIERE API_ROUTES -->|"private subnet"| LARAVEL API_ROUTES -->|"localhost"| POSTGREST API_ROUTES -->|"localhost"| ELASTIC API_ROUTES -->|"localhost"| STRAPI IDEMPIERE --> POSTGRES API_ROUTES -->|"HTTPS"| AMAZON API_ROUTES -->|"HTTPS"| AMAZON_LWA API_ROUTES -->|"HTTPS"| DHL API_ROUTES -->|"HTTPS"| SENDCLOUD API_ROUTES -->|"HTTPS"| SHOPIFY style INTERNET fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style FWZONE fill:#1e293b,stroke:#ef4444,color:#f1f5f9,stroke-width:3px style SERVER fill:#0f172a,stroke:#3b82f6,color:#f1f5f9,stroke-width:3px style PROXY fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style FRONTEND fill:#1e3a5f,stroke:#3b82f6,color:#f1f5f9 style BACKEND fill:#1a2e1a,stroke:#10b981,color:#f1f5f9 style DATABASE fill:#2d1f3d,stroke:#8b5cf6,color:#f1f5f9 style SUBNET fill:#1a2e1a,stroke:#10b981,color:#f1f5f9 style POSTGRES fill:#2d1f3d,stroke:#8b5cf6,color:#f1f5f9 style NGINX fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style OPNSENSE fill:#1e293b,stroke:#ef4444,color:#f1f5f9
Application Layer
Internal Backend (localhost only)
Database Layer
Firewall / Reverse Proxy
External / Internet Zone

Key Architecture Decisions

  • OPNsense firewall appliance — All traffic passes through an OPNsense firewall with stateful packet inspection and IDS/IPS capabilities. Firmware is regularly auto-updated.
  • Debian dedicated server — The application server runs Debian Linux with automated security updates (unattended-upgrades). All services except Nginx are bound to localhost.
  • Nginx as sole entry point — Only HTTPS (port 443) is permitted through the firewall. Nginx terminates TLS and proxies to the Nuxt app on localhost:3001.
  • All backend services isolated — iDempiere, PostgREST, Elasticsearch, Strapi, and PostgreSQL run on localhost only. Laravel runs on a separate server in the same private subnet, also not publicly accessible.
  • Server-side API calls only — The browser never communicates directly with backend services or Amazon. All external API calls (Amazon SP-API, DHL, Sendcloud, Shopify) happen server-side in Nuxt API routes.
  • Encryption at rest — Database credentials and API keys are stored encrypted. PostgreSQL data resides on the server's encrypted filesystem.
🖥 Server Component Layout

OPNsense Firewall Appliance

All inbound and outbound traffic passes through an OPNsense firewall appliance with stateful packet inspection, intrusion detection/prevention (IDS/IPS), and automatic firmware updates. Only HTTPS (port 443) is allowed inbound to the application server. All other ports are blocked by default-deny rules.

Nginx
Reverse Proxy & TLS
:443 → :3001
🟢
Nuxt 3 (PM2)
SSR + API Routes
localhost:3001 (x2 cluster)
🏢
iDempiere
ERP Backend (Java)
localhost only
📊
PostgREST
DB REST Interface
localhost only
🔎
Elasticsearch 8
Search & Indexing
localhost only
📝
Strapi CMS
Media & Content
localhost only
💾
PostgreSQL
Primary Database (Encrypted)
localhost:5432

Network Isolation

Only Nginx on port 443 is accessible from the internet, and only after passing through the OPNsense firewall. All other services bind to localhost / 127.0.0.1 and are not reachable from outside the server. The Debian server runs unattended-upgrades for automatic security patching.

🔧
Laravel
Internal PHP API
Private subnet IP only

Private Subnet Only

The Laravel server is on the same private subnet as the application server. It is not accessible from the public internet. Communication between the Nuxt server and Laravel happens over the private network within the same datacenter.

🔄 General Data Flow
sequenceDiagram participant U as 💻 User Browser participant N as ⚙ Nginx (TLS) participant A as 🟢 Nuxt Server participant I as 🏢 iDempiere participant D as 💾 PostgreSQL Note over U,N: HTTPS / TLS 1.2+ U->>N: HTTPS Request (cookie auth) N->>A: HTTP Proxy (localhost:3001) Note over A: Server-side API route
validates JWT token from cookie A->>I: REST API call (Bearer token, localhost) I->>D: SQL Query D-->>I: Query Result I-->>A: JSON Response Note over A: Maps iDempiere PascalCase
to frontend camelCase A-->>N: JSON / SSR HTML N-->>U: HTTPS Response Note over U,D: All backend communication
stays within the server (localhost)

Data Flow Principles

  • Browser ↔ Server: All communication encrypted with TLS 1.2+. Authentication via HTTP-only cookies containing JWT tokens.
  • Nuxt ↔ Backend Services: All calls over localhost or private subnet. No data traverses the public network.
  • Nuxt ↔ External APIs: Server-side only. Browser never contacts external services directly. All outbound calls use HTTPS.
  • Amazon PII encrypted at rest: Customer data (names, addresses, emails, phone numbers) from Amazon orders is stored encrypted (AES-256) in the iDempiere database. PII is used exclusively for shipping label creation and invoice generation. Data is retained for the business lifecycle and can be deleted upon request.
  • PII shared with carriers only: Customer name, address, email, and phone are transmitted to shipping carriers (DHL/Sendcloud) via HTTPS exclusively for label creation. No Amazon data is shared with analytics, marketing, or non-operational services.
📦 Amazon SP-API Data Flow
sequenceDiagram participant U as 💻 User (LogShip ERP) participant N as 🟢 Nuxt Server API participant I as 🏢 iDempiere DB participant LWA as 🔑 Amazon LWA participant SP as 📦 Amazon SP-API participant DHL as 🚚 DHL/Sendcloud rect rgb(45, 25, 25) Note over U,SP: 1. Order Import Flow (PII Collection) U->>N: POST /api/orders/import
(Amazon order data) Note over N: Extract customer PII:
name, email, phone,
shipping + billing address N->>I: Create Business Partner
(name, email - encrypted AES-256) N->>I: Create Location
(address - encrypted AES-256) N->>I: Create Order
(amazon_order_id reference) I-->>N: Records created N-->>U: Order imported end rect rgb(25, 40, 25) Note over U,DHL: 2. Shipping Label Creation (PII Usage) U->>N: POST /api/commission/parcels/dhl
(shipment data) N->>I: Fetch customer data
(decrypt PII in memory) I-->>N: Name, address, email, phone N->>DHL: POST label request via HTTPS
(customer name, address, email, phone) DHL-->>N: Shipping label + tracking number N->>I: Store tracking number N-->>U: Label created end rect rgb(30, 58, 95) Note over U,SP: 3. Invoice Upload Flow (UPLOAD_VAT_INVOICE) U->>N: POST /api/invoices/amazon-upload
(invoice IDs) N->>I: Fetch invoice + order data
(localhost) I-->>N: Invoice + Amazon Order ID N->>I: Fetch SP-API credentials
(decrypt in memory) I-->>N: client_id, client_secret, refresh_token N->>LWA: POST /auth/o2/token LWA-->>N: Access Token (short-lived) Note over N: Generate invoice PDF
server-side (pdfmake) N->>SP: Upload PDF to pre-signed S3 URL N->>SP: POST /feeds (UPLOAD_VAT_INVOICE) SP-->>N: Feed ID confirmed N->>I: Mark invoice as uploaded N-->>U: Upload result end rect rgb(26, 46, 26) Note over U,SP: 4. Delivery Confirmation N->>SP: Report tracking + delivery status
(via Laravel, HTTPS) SP-->>N: Confirmed end

Amazon Data We Store (PII)

Data TypeStorage LocationPurposeEncrypted
Customer NameC_BPartner (encrypted)Shipping labels, invoicesYes (AES-256)
Email AddressC_BPartner (encrypted)Shipping notificationsYes (AES-256)
Phone NumberAD_User (encrypted)Shipping labels, delivery contactYes (AES-256)
Shipping AddressC_Location (encrypted)Shipping labels, invoicesYes (AES-256)
Billing AddressC_Location (encrypted)InvoicesYes (AES-256)
Amazon Order IDC_OrderOrder linking & trackingYes

Amazon Data We Do NOT Access or Store

Payment or financial data (credit cards, bank accounts)
Product catalog or listing data
Seller performance metrics
Advertising or analytics data
Customer purchase history beyond the specific order

PII is stored only for operational necessity: creating shipping labels and uploading VAT invoices. All PII is encrypted at rest (AES-256) in the database.

Credential Handling for SP-API

  • Storage: SP-API credentials (Client ID, Client Secret, Refresh Token) are stored encrypted in the iDempiere database within the c_ordersource table, accessible only to authorized admin users.
  • Encryption: Credentials are encrypted at rest using AES-256 encryption before being persisted to the database. Decryption occurs server-side only at the moment of use.
  • Access: Credentials are fetched and decrypted server-side only when an upload is triggered. They never reach the browser.
  • Token lifecycle: LWA access tokens are short-lived and obtained per-operation. They are held in memory only and never persisted to disk.
  • Database access: PostgreSQL is on localhost only, behind OPNsense firewall and Proxmox isolation. No external network access to credentials is possible.
🔒 Security Layers
graph LR subgraph L1["Layer 1: Network"] FW["Firewall
Only 443 + SSH"] TLS["TLS 1.2+
Certificate"] end subgraph L2["Layer 2: Reverse Proxy"] NG["Nginx
Rate limiting
Header security"] end subgraph L3["Layer 3: Application"] AUTH["JWT Auth
Cookie-based"] RBAC["Role-Based
Access Control"] MW["Auth Middleware
Route protection"] end subgraph L4["Layer 4: Backend"] LH["Localhost Only
No external access"] BEARER["Bearer Token
per request"] end subgraph L5["Layer 5: Database"] PG["PostgreSQL
localhost:5432"] ROLE["DB Roles &
Permissions"] end L1 --> L2 --> L3 --> L4 --> L5 style L1 fill:#1e293b,stroke:#ef4444,color:#f1f5f9 style L2 fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style L3 fill:#1e293b,stroke:#3b82f6,color:#f1f5f9 style L4 fill:#1e293b,stroke:#10b981,color:#f1f5f9 style L5 fill:#1e293b,stroke:#8b5cf6,color:#f1f5f9
🛡 OPNsense Firewall
Dedicated OPNsense firewall appliance with stateful packet inspection, IDS/IPS, and automatic firmware updates. Default-deny policy — only HTTPS (443) allowed inbound.
🖥 Proxmox Hypervisor
All servers run as virtual machines on a Proxmox VE hypervisor. The Proxmox management interface is not accessible from the public internet — admin access restricted to internal network only.
🔐 TLS Encryption
All browser-to-server traffic encrypted with TLS 1.2+. Certificate managed via Let's Encrypt / Certbot auto-renewal.
⚙ Nginx Proxy
Reverse proxy terminates TLS, adds security headers, and forwards only to localhost:3001.
💾 Encryption at Rest
Database credentials and API secrets stored encrypted. SP-API credentials encrypted in the application database. Sensitive configuration stored in encrypted environment files.
🔑 JWT Authentication
Cookie-based JWT tokens. Access token + refresh token with automatic renewal. Token validation on every request.
👥 Role-Based Access
iDempiere RBAC system controls which users can access which data and operations. Admin roles required for SP-API config.
🚧 Auth Middleware
Every protected page checks authentication server-side. Unauthorized users redirected to login.
💻 Localhost Isolation
All backend services (iDempiere, PostgreSQL, Elasticsearch) bound to localhost. Laravel on separate server in private subnet. Zero public exposure.
📤 Server-Side API Calls
All external API calls (Amazon, DHL, etc.) made server-side. Browser never contacts third-party services.
🌐 Network Topology
graph TB subgraph PUBLIC["Public Internet"] BROWSER["💻 User Browsers"] EXTAPI["🌐 External APIs
(Amazon, DHL, Sendcloud, Shopify)"] end subgraph FWZONE2["OPNsense Firewall Appliance"] FW["🛡 OPNsense
IDS/IPS • Stateful Inspection
Port 443 only inbound"] end subgraph PRIVATE["Private Network (Datacenter Subnet)"] subgraph APPSERVER["Debian Application Server"] subgraph PROXY2["Reverse Proxy Layer"] NGINX2["Nginx :443
TLS termination"] end subgraph APP["Application Layer"] NUXT["Nuxt :3001
PM2 cluster (2x)"] end subgraph SERVICES["Service Layer (localhost)"] direction LR ID2["iDempiere"] PR2["PostgREST"] EL2["Elastic"] ST2["Strapi"] end subgraph DATA["Data Layer (localhost)"] PG2[("PostgreSQL :5432
Encrypted at Rest")] end end subgraph LARAVELSVR["Laravel Server (Private Subnet)"] LA2["Laravel API"] end end BROWSER -->|"HTTPS :443"| FW FW --> NGINX2 NGINX2 -->|":3001"| NUXT NUXT -->|"localhost"| ID2 NUXT -->|"private subnet"| LA2 NUXT -->|"localhost"| PR2 NUXT -->|"localhost"| EL2 NUXT -->|"localhost"| ST2 ID2 --> PG2 NUXT -.->|"HTTPS outbound"| EXTAPI style PUBLIC fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style FWZONE2 fill:#1e293b,stroke:#ef4444,color:#f1f5f9,stroke-width:3px style PRIVATE fill:#0f172a,stroke:#3b82f6,color:#f1f5f9,stroke-width:3px style APPSERVER fill:#0f172a,stroke:#3b82f6,color:#f1f5f9 style PROXY2 fill:#1e293b,stroke:#f59e0b,color:#f1f5f9 style APP fill:#1e3a5f,stroke:#3b82f6,color:#f1f5f9 style SERVICES fill:#1a2e1a,stroke:#10b981,color:#f1f5f9 style DATA fill:#2d1f3d,stroke:#8b5cf6,color:#f1f5f9 style LARAVELSVR fill:#1a2e1a,stroke:#10b981,color:#f1f5f9

Network Security Summary

DirectionProtocolPortsPurpose
InboundHTTPS443 (via OPNsense)User access via Nginx
OutboundHTTPS443Amazon SP-API, DHL, Sendcloud, Shopify
InternalHTTPlocalhost onlyNuxt ↔ iDempiere, PostgREST, Elastic, Strapi
InternalHTTPPrivate subnetNuxt ↔ Laravel (separate server)
InternalPostgreSQLlocalhost:5432iDempiere ↔ Database
ManagementHTTPSInternal onlyProxmox & OPNsense admin (not public)
Blocked*All otherOPNsense default deny
🔗 External Service Integrations
📦 Amazon SP-API
sellingpartnerapi-eu.amazon.com
VAT invoice uploads via Feeds API. EU region endpoint. Server-side only.
🔑 Amazon LWA
api.amazon.com/auth/o2/token
OAuth token exchange. Refresh token → short-lived access token per operation.
🚚 DHL Parcel API
api-eu.dhl.com
Shipping label creation. Receives customer name, address, phone, email for label generation. OAuth password grant. HTTPS. Server-side only.
📨 Sendcloud
panel.sendcloud.sc/api/v2
Multi-carrier shipping. Receives customer name and address for label generation. Basic auth over HTTPS. Server-side only.
🛒 Shopify
GraphQL API v2025-10
E-commerce integration. OAuth client credentials. Server-side only.
📝 Strapi CMS
localhost (same server)
Media and content management. Internal only. Bearer token auth.

Third-Party Data Sharing Policy

Amazon customer PII is shared with shipping carriers only (DHL, Sendcloud) for the sole purpose of creating shipping labels — this is operationally required to fulfill orders. Invoice PDFs (containing customer billing details) are uploaded back to Amazon via SP-API. No Amazon data is shared with analytics, marketing, or any other non-operational service. All outbound transmissions use HTTPS/TLS encryption.

💾 Data Storage & Retention

What Amazon Data We Store

DataLocationEncryptionRetention
Customer NameC_BPartnerAES-256Business lifecycle / on deletion request
Email AddressC_BPartnerAES-256Business lifecycle / on deletion request
Phone NumberAD_UserAES-256Business lifecycle / on deletion request
Shipping & Billing AddressC_LocationAES-256Business lifecycle / on deletion request
Amazon Order IDC_OrderAES-256Business lifecycle
Upload Status FlagC_InvoiceN/ABusiness lifecycle
SP-API CredentialsC_OrderSourceAES-256Until deleted by admin

All PII fields are encrypted at rest using AES-256. Data is retained only for the duration of the business relationship and can be deleted upon request.

What We Do NOT Store

Payment or financial data (credit cards, bank accounts)
Amazon access tokens (short-lived, in-memory only)
Amazon product catalog data
Amazon seller performance data
Customer purchase history beyond the specific order

Data Deletion Process

Amazon customer PII can be deleted upon request through the iDempiere admin interface. When a seller revokes authorization or the business relationship ends, all associated customer records, order data, and marketplace credentials are removed from the system. Individual customer records (business partners, locations, contacts) can be deactivated or fully purged by authorized admin users. Database backups follow a rolling retention policy with encrypted storage.

LogYou GmbH — LogShip ERP System Architecture Documentation

Prepared for Amazon SP-API Developer Security Assessment — March 2026

This document is confidential and intended solely for the Amazon assessment process.