# Pakajo Dashboard · Backend Integration for Developers

As of: 10 Oct 2026 · Mockup build 2026-10-10-48

This document describes **where the frontend mockup connects to the Pakajo backend**, which modules belong to whom and which data contracts apply. Goal: the developers replace **one file** (the adapter) with real endpoints – the modules (single shipment, bulk shipping, shipping rules, pickup, subscription, …) remain unchanged.

---

## 1. Architecture: `window.PakajoBackend` (adapter)

The adapter lives in the mockup as its own script block (`PAKAJO BACKEND ADAPTER`, directly before the app modules). Today every function is backed by mock data (localStorage, demo lists). The modules call **only** `PakajoBackend.*`.

| Namespace | Functions | Production (proposal) |
|---|---|---|
| `config` | `vatRate()`, `currency()`, `pointValueEur()`, `minTopupEur()` | `GET /config` |
| `countries` | `iso2(any)`, `iso3(iso2)`, `name(iso2)`, `flag(iso2)`, `label(iso2)`, `isEU(iso2)`, `eu()`, `list()` | static / `GET /countries` |
| `carriers` | `all()`, `byId(id)`, `byName(name)`, `idOf(x)`, `forScreen()`, `forCountry(iso2)` → `{local, global, all}`, `bulkNames()` | `GET /carriers?country=ES` |
| `products` | `all()` (codes 1–7), `byCode(code)`, `codeFromText(txt)`, `pickup(mode)` (pickup/dropoff/retoure) | `GET /products`, `GET /products/pickup` |
| `pricing` | `quote(ctx)` → `{carrierId, net, vat, gross, service, days}`, `quoteAll(ctx, list)`, `fmt(n)` | `POST /quote` |
| `customers` | `list()`, `get(mid)`, `active()`, `save(mid, data)` | `GET/PUT /customers/{mid}` |
| `users` | `list()`, `current()` | `GET /users`, `GET /me` |
| `subscriptions` | `plans()`, `features(plan)`, `active()`, `offerGroup(mid)` | `GET /subscriptions`, offer groups |
| `billing` | `get(mid)`, `invoices()` (ESN data) | `GET /billing/{mid}`, `GET /invoices` |
| `shipments` | `orders()`, `imported()` | `GET /orders`, `POST /shipments/import` |
| `tracking` | `events(nr)` | AI tracking (existing) |
| `returns` | `list()` | returns function (existing) |
| `orders` | `shopOrders()`, `articles()` | shop/marketplace, articles (existing) |
| `performance` | `query(sql)` | SQL editor → frontend |
| `rules` | `list()`, `save(list)`, `aiSuggestions()` | `GET/PUT /rules`, AI suggestions |
| `glocal` | `countries()` | Glocal product group |
| `claims` | `tickets()`, `webhook(ev)` | Bitrix24 (ONTASKADD / ONTASKUPDATE / ONTASKCOMMENTADD) |
| `addressbook`, `boxPresets`, `branding`, `points`, `pricingTool`, `currency`, `integrations`, `apiDocs`, `chatbot`, `profile`, `security` | see adapter | |
| `importTax(iso)` | import tax per country (CH 8.1 % / 2.6 % printed matter) | `GET /customs/import-tax/{iso}` |

`PakajoBackend.meta.ownership` holds the responsibility per module (backend / mixed / frontend) – available via `PakajoBackend.ownerOf('rules')`.

---

## 2. Responsibilities per module

| Module | Responsibility | Note |
|---|---|---|
| Carriers / shipping products (incl. pickup, drop-off, return) | **Backend** | Single source `carriers` + `products`; the frontend identifies carriers by `carrierId`, never by display name |
| Customer data / clients | **Backend** | Existing customers from the backend; new customers via self-registration (master client) or directly in the backend (e.g. Enterprise) |
| Users & roles, integrations, profile data (user) | **Backend** | |
| Shop/marketplace orders, article overview | **Backend** | already existing |
| AI tracking | **Backend** | already existing, frontend only displays |
| Returns | **Backend** | already existing, frontend renders |
| Glocal countries | **Backend** (Glocal product group) | the Glocal overview itself = landing page (frontend) |
| API & docs | **Backend** | largely existing |
| Bulk shipping | mixed | import/validation/calculation partly backend; rows carry `data-dest`, `data-gewicht`, `data-produkt`, `data-carrier-id` |
| Shipping rules | mixed | rules per customer; carriers/services from the backend; matching via ISO-2 + product code |
| Shipping performance | mixed | shipping data via SQL editor (`performance.query`) |
| Subscriptions / offer groups / discounts | mixed | display frontend, logic backend; plan gating (`ABO_FEATURES`) must be mirrored server-side |
| Commercial invoice | mixed | from customer input |
| Invoice data | mixed | from ESN shipping data |
| Claims / damage cases | mixed | Bitrix24 CRM (ticket by service, customer = participant, webhooks) |
| Chatbot | embedded | |
| Address book | display frontend, data backend | |
| Branding, Paku Points, pricing tool, multi-currency, archiving | mixed | Paku Points only Free/Bronze/Silver/Gold (not Enterprise) |
| Box presets, 2FA/security, registration UI | **Frontend** | |

---

## 3. Data contracts (mockup form = target form)

```js
// Carrier
{ id: 'tipsa', name: 'Tipsa Parcel', service: 'PRIORITY'|'STANDARD'|'AUTO', days: '2-5 d',
  maxKg: 30, basePrice: 3.75 /* net EUR */, coverage: ['*'] | ['ES'], features: [...], screen: true, tag: 'local', virtual: false }

// Shipping product
{ code: '1'..'7', name: 'Parcel with tracking', priceMod: 0.00, label: 'with tracking' }

// Quote request / response
quote({ carrier: 'tipsa', iso2: 'ES', gewicht: 500 /* g */, laenge: 300, breite: 200, hoehe: 100 /* mm */,
        produkt: '2', insuranceFee: 0.99, express: false })
→ { carrierId: 'tipsa', carrier: 'Tipsa Parcel', net: 4.11, vat: 0.78, gross: 4.89, service: 'PRIORITY', days: '2-5 d' }

// Shipping rule
{ id: 'R-…', name: 'Spain → Tipsa', land: 'Spanien' | 'EU' | 'NONEU' | '', landIso: 'ES', produkt: '' | '1'..'7',
  wmin: 0, wmax: 1000 /* g */, mandant: '' | '3001', act: 'cheapest'|'carrier'|'fastest'|'service',
  carrier: 'Tipsa Parcel', carrierId: 'tipsa', service: 'STANDARD'|'PRIORITY', auto: true, active: true, ai: false, hits: 0 }

// Bulk row (data attributes on <tr>)
data-nr="572640" data-dest="DE" data-gewicht="480" data-produkt="2" data-carrier-id="dhl"

// Carrier card single shipment
data-carrier="Česká pošta" data-carrier-id="ceska" data-net="3.57" data-service="PRIORITY"
```

Conventions: countries **ISO 3166-1 alpha-2** as key (`countries.iso2()` normalises ISO-3, names, flags, "City · Country"); prices **net EUR**, gross display via `config.vatRate()`; status values as enums (see section 5).

---

## 4. What the refactoring (build -47) already implemented

1. **One carrier list** (`PakajoBackend.carriers`) replaces seven parallel lists (single shipment, shipment dialog local/global, bulk dropdown, rules). Carriers have IDs.
2. **One price formula** (`pricing.quote`) for single shipment, shipment dialog and shipping rules – previously three different formulas (different prices on card vs. dialog).
3. **Country normalisation** `countries.iso2()` – shipping rules and bulk shipping match via ISO-2 instead of German country names.
4. **Shipping products 1–7** from `products` (price modifiers central).
5. **data attributes** instead of text parsing: carrier cards (`data-carrier-id`, `data-net`) and bulk rows (`data-dest`, `data-gewicht`, `data-produkt`, `data-carrier-id`).
6. **VAT rate** from `config.vatRate()`.
7. Pickup/drop-off/return product lists reachable via `products.pickup(mode)`.

---

## 5. Open items for production integration (recommendation, descending priority)

1. **Business logic into the backend**: plan gating, client/user limits, prepaid balance, SEPA approval, Bronze trial, plan switch, prepaid credit, points rate/margins, customs rates, pickup quotas/fill rule. In the mockup this lives in localStorage (40 `pakajo-*` keys) and can be manipulated client-side.
2. **Security**: LLM keys (Anthropic/OpenAI) live in the browser and are called directly → proxy via backend. Login hand-over via `?selfreg=<base64>` in the URL (name/e-mail/company) → session token. Tracking lookup (`fetchOne`) → backend.
3. **IDs from the server**: tracking numbers, booking numbers, ticket IDs, credit note IDs are generated with `Math.random()` in the mockup.
4. **Unify enums**: status mixed (`offen`, `printed`, `pending`, `abgeschlossen`, `delivered`); plan internally `Platin`, displayed "Enterprise". Proposal: `SHIPMENT_STATUS`, `PLAN`, `PRODUCT` as central enums, labels via i18n.
5. **Remaining country selects** (`ship-zielland` ISO-2, `screen-versand-land` ISO-3, address book/client plain text) → ISO-2 values – `countries.iso2()` covers this today, a uniform `value` is cleaner.
6. **Static demo rows** in bulk shipping (2600–2607) → seed data from `shipments.orders()`; rule application still has a text fallback for them.
7. **Gross/net and currency conversion** (`convertCardsVat`, `convertPricesInDom`) currently render via MutationObserver over finished DOM prices. Target: render prices from `quote()` (`net`/`gross`) directly, remove the observers.

---

## 6. Storage keys in the mockup (mapping to backend)

| Key | Content | Target |
|---|---|---|
| `pakajo-selfreg` | accounts, logins, session (shared login ↔ dashboard) | auth service |
| `acct:<id>:…` | namespace per customer account for all following keys | server-side per customer |
| `pakajo-mandant-settings` | clients (`MANDANTEN_DEFAULTS`) | `customers` |
| `pakajo-users` | users & roles | `users` |
| `pakajo-billing-<mid>` | prepaid, payment method, SEPA, credit notes | `billing` |
| `pakajo-selected-plan:<mid>`, `pakajo-plan-since:<mid>`, `pakajo-plan-pending:<mid>` | subscription state | `subscriptions` |
| `pakajo-auftraege`, `pakajo-imported-shipments` | orders/shipments | `shipments` |
| `pakajo-ship-rules`, `pakajo-ship-rules-ai` | shipping rules, AI suggestion state | `rules` |
| `pakajo-rek-tickets` | claim tickets (Bitrix mirror) | `claims` |
| `pakajo-addressbook`, `pakajo-boxpresets`, `pakajo-branding-<mid>` | address book, box presets, branding | corresponding namespaces |
| `pakajo-points-<mid>`, `pakajo-pickups-<mid>` | Paku Points, pickup quota | `points`, pickup service |
| `pakajo-lang`, `pakajo-user-currency` | UI preferences | `profile` |
