# API Spec Verification Pass

**Source:** `~/ALAI/products/Plock/docs/demo-readiness/06-api-spec-verification-pass.md`

---

# PLOCK — API Spec Verification Pass

**Date:** 2026-03-14  
**Reviewer:** John  
**Scope:** Narrow manual verification of `docs/API-SPEC.md` against the real Ktor route surface under `backend/src/main/kotlin/no/alai/plock/`.

---

## 1. Verdict

**Canonical verdict:** FAIL as a canonical API source  
**Reference verdict:** PASS WITH NOTES as API-intent/reference material

### Why

`docs/API-SPEC.md` contains useful product intent, but it does not currently match the real backend route surface closely enough to be treated as canonical.

The biggest problems are:

- org-centric model appears where repo reality is warehouse-centric
- several documented endpoint groups do not exist in the current Ktor app
- several real Ktor route groups are missing or materially different in the spec
- multiple path shapes differ even when the domain concept is roughly aligned

---

## 2. Verification Sources

Primary sources used for this pass:

- `backend/src/main/kotlin/no/alai/plock/plugins/Routing.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/AuthRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/WarehouseRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/LocationRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/ProductRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/InventoryRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/OrderRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/PickingRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/ReceivingRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/CarrierRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/CarrierIntegrationRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/ShipmentRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/RoleRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/UserRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/DashboardRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/routes/SseRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/integrations/fortnox/FortnoxOAuthRoutes.kt`
- `backend/src/main/kotlin/no/alai/plock/integrations/fortnox/FortnoxSyncRoutes.kt`

---

## 3. Real Route Surface Snapshot

`Routing.kt` mounts these main groups under `/api/v1` (plus unauthenticated Fortnox OAuth + health/auth):

- `/auth` and `/auth/me`
- `/products`
- `/users`
- `/dashboard`
- `/warehouses`
- `/locations`
- `/inventory`
- `/orders`
- `/picking`
- `/zones`
- `/suppliers`
- `/receiving`
- `/carriers`
- `/shipments`
- `/roles`
- `/audit`
- `/stock-movements`
- `/cycle-counts`
- `/returns`
- `/webhooks`
- `/events*`
- `/barcodes`
- `/integrations/fortnox/*`

This is already enough to show that the live API surface is broader in some places and materially different in others than `docs/API-SPEC.md` suggests.

---

## 4. Sections That Are Roughly Aligned

These areas are directionally aligned, even when path or payload details differ:

### 4.1 Auth

`docs/API-SPEC.md` documents auth/login concepts, and real routes do include:

- `POST /auth/register`
- `POST /auth/login`
- `GET /auth/me`

### 4.2 Warehouses / products / users / dashboard

These domains exist in the real backend and in the API spec at a high level.

### 4.3 Carrier + shipment integrations

The spec correctly signals that carrier and Fortnox integration domains exist, although the actual route design is different.

### 4.4 Real-time events

The spec includes SSE/event streaming, and the real backend does expose:

- `GET /events/stream`
- `GET /events` (legacy alias)
- `GET /events/connections`
- `POST /events/test`

---

## 5. Major Drift / Mismatch Areas

## 5.1 Tenancy model drift

**Spec problem:** org-centric model  
**Repo reality:** warehouse-centric model

Examples in `docs/API-SPEC.md`:

- `Organizations`
- `organization_name`
- `slug`
- organization object inside auth responses
- `/organizations/me`

Repo reality:

- real tenant model is `warehouse_id`
- auth/user DTOs expose `warehouseId`
- no `organization` route group exists in the Ktor app

**Impact:** High. This is not a cosmetic difference; it changes the domain model.

---

## 5.2 Auth flow drift

### Spec says

- `POST /auth/register` creates organization + admin user
- `POST /auth/refresh` exists
- `POST /auth/logout` exists

### Actual routes

- `POST /auth/register`
- `POST /auth/login`
- `GET /auth/me`

### Mismatch

Real auth routes do **not** currently expose documented refresh/logout endpoints, and register/login response shapes differ from the org-centric API spec.

**Verdict:** partial alignment only

---

## 5.3 Warehouses and locations path drift

### Spec says

- `/warehouses/:warehouseId/zones`
- `/warehouses/:warehouseId/bins`
- nested warehouse-scoped bin endpoints

### Actual routes

- `/warehouses`
- `/warehouses/{id}`
- `/locations`
- `/locations/{id}`
- `/zones`
- `/zones/{id}`
- `/put-away/suggest`

### Mismatch

The real backend models zones and locations as first-class route groups, not nested warehouse bin endpoints as described in the spec.

---

## 5.4 Inventory route drift

### Spec says

- `GET /inventory`
- `POST /inventory/adjustments`
- `GET /inventory/transactions`
- `POST /inventory/cycle-count`
- `GET /inventory/anomalies`

### Actual routes

- `GET /inventory`
- `GET /inventory/balance`
- `GET /inventory/summary`
- `GET /inventory/search`
- `POST /inventory`
- `POST /inventory/recalculate`
- `GET /inventory/{id}`
- `POST /inventory/{id}/adjust`
- `DELETE /inventory/{id}`

### Mismatch

The real system exposes different operational endpoints and splits stock adjustment and audit trail differently. Inventory transaction history is represented more directly via `/stock-movements`, not the spec’s `/inventory/transactions` route.

---

## 5.5 Receiving / inbound drift

### Spec says

- `/inbound/purchase-orders`
- `/inbound/purchase-orders/:poId/receive`

### Actual routes

- `/receiving`
- `/receiving/{id}`
- `/receiving/{id}/receive-item`
- `/receiving/{id}/complete`
- `/receiving/{id}/cancel`
- `/receiving/{id}/process`
- `/receiving/{id}/discrepancies`
- `/receiving/discrepancies/{discrepancyId}/resolve`

### Mismatch

The real backend has a receiving-order workflow, not the purchase-order route structure described in the spec.

---

## 5.6 Orders / outbound drift

### Spec says

- `/outbound/orders`
- `/outbound/orders/release`
- `/outbound/orders/:orderId/status`

### Actual routes

- `/orders`
- `/orders/{id}`
- `/orders/{id}/allocate`
- `/orders/{id}/deallocate`
- `/orders/{id}/ship`

### Mismatch

The domain overlaps, but path structure and supported actions differ materially.

---

## 5.7 Picking drift

### Spec says

- `/picking/routes`
- `/picking/routes/:routeId/confirm-pick`
- `/picking/routes/:routeId/assign`

### Actual routes

- `/picking/waves`
- `/picking/waves/{id}`
- `/picking/waves/{id}/start`
- `/picking/waves/{id}/pick-item`
- `/picking/{pickListId}/items/{itemId}/confirm`

### Mismatch

The live system is pick-wave/pick-item oriented, not route-assignment oriented in the way the spec describes.

---

## 5.8 Carrier / shipment drift

### Spec says

- `/carriers/labels/generate`
- `/carriers/labels/:trackingNumber/status`
- `/carriers/services`
- `/carriers/labels/:trackingNumber/void`

### Actual routes include

- carrier CRUD under `/carriers`
- shipment CRUD and lifecycle under `/shipments`
- provider-specific endpoints under `/carriers/postnord/*`, `/carriers/dhl/*`, `/carriers/instabee/*`
- generic integration shipment routes under `/shipments` in `CarrierIntegrationRoutes.kt`

### Mismatch

The spec compresses real shipping/carrier behavior into a simplified label-oriented interface that does not match the current route surface.

---

## 5.9 Dashboard / reports drift

### Spec says

- `/dashboard/stats`
- `/reports/inventory-health`
- `/reports/performance`
- `/reports/export`

### Actual routes

- `/dashboard/stats`
- `/inventory/low-stock`

### Mismatch

Only `dashboard/stats` is clearly aligned. The `/reports/*` route group is not present in the current Ktor app.

---

## 5.10 AI route drift

### Spec says

- `/ai/chat`
- `/ai/actions/confirm`
- `/ai/chat/history`
- `/ai/pick-route/optimize`
- `/ai/pick-route/job/:jobId`

### Actual routes

- no `/ai/*` route group was found in the current backend route surface

### Mismatch

This is major product-intent content, not current API reality.

---

## 5.11 Integrations drift

### Spec says

- `GET /integrations`
- `GET /integrations/fortnox/connect`
- `GET /integrations/fortnox/callback`
- `POST /integrations/fortnox/sync`
- `DELETE /integrations/:provider`
- webhooks under integrations

### Actual routes include

- `GET /integrations/fortnox/auth`
- `GET /integrations/fortnox/callback`
- `GET /integrations/fortnox/status`
- `POST /integrations/fortnox/sync/articles`
- `POST /integrations/fortnox/sync/orders`
- `POST /integrations/fortnox/sync/stock`
- `POST /integrations/fortnox/sync/products`
- `POST /integrations/fortnox/confirm-shipment/{orderId}`

### Mismatch

The real Fortnox integration surface is more concrete and warehouse-scoped than the generic integration control plane described in the spec.

---

## 5.12 Users / RBAC drift

### Spec says

- `POST /users/invite`
- `PATCH /users/:userId`
- `GET /users/me`
- mostly flat user-role assumptions

### Actual routes include

- `/users`
- `/users/{id}` with `GET`, `PUT`, `DELETE`
- `/roles`
- `/roles/assign`
- `/roles/user/{userId}`
- `/roles/user/{userId}/permissions`
- `GET /auth/me`

### Mismatch

RBAC is present, but it is organized differently and more explicitly in the real backend than in the spec.

---

## 6. Important Real Route Groups Missing from the Spec

These live route groups exist in the backend but are not represented well, or at all, in `docs/API-SPEC.md`:

- `/audit`
- `/stock-movements`
- `/cycle-counts`
- `/returns`
- `/webhooks`
- `/barcodes`
- `/suppliers`
- `/zones`
- `/put-away/suggest`
- `/events/connections`
- `/events/test`
- `/health` and `/health/ready`

---

## 7. Practical Conclusion

Use `docs/API-SPEC.md` only for:

- product/API intent
- domain discovery hints
- identifying candidate workflows to verify against code

Do **not** use it for:

- canonical route inventory
- API QA signoff
- implementation planning without code check
- tenant-model assumptions

---

## 8. Recommended Next Narrow Step

Do **not** rewrite the full API spec yet.

Instead, use this sequence:

1. keep the current warning on `docs/API-SPEC.md`
2. use this verification note as the current interpretation layer
3. later perform a targeted API-spec correction pass section-by-section, starting with: 
    - tenancy/auth
    - inventory
    - receiving/orders/picking
    - carriers/integrations

---

## 9. Decision

`docs/API-SPEC.md` is now a **verified non-canonical reference**.

Until corrected, the canonical API truth for PLOCK remains:

- the actual Ktor route files, and
- the canonical demo-readiness baseline package.