# Backend handoff — start here Single entry point for a backend developer picking this up cold. Written 2026-08-18. ## 1. What this is `marketplaces` is a multi-tenant marketplace platform frontend (Angular 22). The frontend is built and waiting; **there is no backend yet**. Every wire contract the backend needs to implement is already written and sitting in this directory — see [README.md](README.md) for the full index and build order. ## 1a. Multi-tenancy — the thing that shapes every endpoint One deployed bundle serves **every customer domain**. There is no per-tenant build. The chain is: 1. [`TenantResolverService`](../../src/app/core/config/tenant-resolver.service.ts) derives a `tenantKey` from `window.location.hostname` (first label; `www.` skipped; localhost falls back to a configured key). 2. [`ApiConfigService`](../../src/app/core/config/api-config.service.ts) turns that key into the API base URL — via an explicit per-tenant map or a `{tenant}` URL template. 3. `ApiBootstrapProvider` fetches that tenant's **bootstrap config**, which drives branding, theme, locales, currencies, navigation, footer, and which pages exist. 4. nginx is `default_server` / `server_name _`, so any domain pointed at the server IP gets the same bundle and self-resolves. **What this means for you:** the bootstrap endpoint is the single most important thing to build after auth. Every request must be tenant-scoped server-side, and a tenant must never be able to read another tenant's data — return `403`, not an empty result (see [TRACK-S §2](TRACK-S-SECURITY-RBAC-CONTRACT.md)). The frontend supplies the tenant identity from the hostname; the backend must treat that as an untrusted hint and derive real scope from the authenticated session. Constraints already fixed by the frontend design (see the platform-vision facts in `docs/context/`): no marketplace-specific code or hardcoded marketplace data in the frontend; bootstrap carries only what is needed before app start (branding, languages, homepage layout, navigation, enabled widgets, footer pages) and **never** products, orders, cart, or users. [PHASE-9](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) covers the marketplace registry, domain attachment, and publish/revision model. ## 2. Read in this order 1. [README.md](README.md) — index of all contracts, build order, and what's deliberately excluded. 2. [PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) — start here. Everything after depends on the money model. 3. Phases 2→4 — the rest of the launch gate (orders, catalog, connectors). 4. [TRACK-S-SECURITY-RBAC-CONTRACT.md](TRACK-S-SECURITY-RBAC-CONTRACT.md) — **gates the launch.** Today the admin role model is decorative: nothing server-side enforces any permission. §8 covers per-marketplace bootstrap admin accounts and self-service sub-admin management. 5. [TRACK-A-ANALYTICS-CONTRACT.md](TRACK-A-ANALYTICS-CONTRACT.md) — longest lead time, start it in parallel with Phase 1. 6. Phases 5→10 — post-launch-gate. 7. [PARTNER-PROVISIONING-API-CONTRACT.md](PARTNER-PROVISIONING-API-CONTRACT.md) — the inbound partner API. Read it **before implementing Phase 1**, not after: it adds `RoutingContext` to `CheckoutSession`/`PaymentIntent`/`Payment` ([Phase 1 §6.5](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md)) and two levels above `Marketplace` ([Phase 9 §1](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md)). Building the partner API itself can wait; carrying its routing dimension in the payments tables cannot. [../../BACKEND-API-REFERENCE.md](../../BACKEND-API-REFERENCE.md) documents the *current* live API surface (legacy endpoints, error envelope, mock-only areas). New endpoints use `/api/v2/...` namespaces; legacy endpoints are not being migrated. ## 3. Auth — read before writing any endpoint Auth is no longer part of this repo. It lives in `@marketplaces/auth`, published from [vitanovaPackages](https://sources.vitanova.network/sdarbinyan/vitanovaPackages.git). See [../PACKAGES-USAGE.md](../PACKAGES-USAGE.md) for the full client surface. What matters on the backend side: **Two mechanisms exist client-side.** - **Telegram QR/session (live).** Endpoints under `{authApiUrl}/users/sessions` — `POST` to create, `GET /{id}` to poll, `DELETE /{id}` to log out. Both customer and admin login call the *same* endpoints; only client-side storage differs. The response shape is normalized permissively client-side (many key spellings accepted), but a clean implementation should return `{ webSessionID, user: { userId, username, firstName, lastName }, status, expiresAt }`. - **Ed25519 challenge/response (not built).** `GET /api/admin/auth/challenge`, `POST /api/admin/auth/verify`, `POST /api/admin/auth/refresh`, `POST /api/admin/auth/logout`. Contracts in [TRACK-S](TRACK-S-SECURITY-RBAC-CONTRACT.md) and the package's `ed25519/models/auth-api.model.ts`. Until these ship, the client shows a `backend-unavailable` screen — nothing is mocked. **The critical gap:** the session API has no concept of "admin." The frontend cannot distinguish an admin session from a customer one — it only chooses where to *store* the result. **Every admin endpoint must independently verify authorization server-side.** Client-side guards are UI convenience, never security. This is the single most serious open issue in the system. Admin requests carry `AdminWebSessionID: ` (and `Authorization: Bearer ` once admin JWTs exist) on paths containing `/admin/`, `/backoffice/`, `/builder/`, `/media/`. ## 4. Environment / infrastructure state Dev server `213.21.246.138` (user `seto`, sudo, SSH key provided separately). | Thing | State | |---|---| | nginx 1.24 | **Installed, running.** Config at `/etc/nginx/sites-enabled/marketplaces-dev.conf`. Serves frontend from `/srv/marketplaces/current/frontend`, backoffice from `/srv/marketplaces/current/backoffice`, proxies `/api/` → `127.0.0.1:8080`. `/health` returns `ok`. | | Go toolchain | Installed (`/usr/local/bin/go`). | | Backend service on :8080 | **Not running.** Nothing is listening. `/srv/marketplaces/current/api` is an empty shell. nginx's `/api/` proxy currently 502s. | | PostgreSQL | **Installed but inactive.** Needs starting, a database, a user, and schema before anything works. | | Shared packages | `@marketplaces/auth` installs over plain git from a release branch — no registry, token, or tunnel needed. `npm install` works out of the box. | | Verdaccio (npm registry) | Running in Docker on port 4873, but **superseded and unused** — nothing depends on it. See [../PACKAGE-EXTRACTION.md](../PACKAGE-EXTRACTION.md) §5. | | Firewall (ufw) | Active. 80/tcp, 443/tcp, OpenSSH. | | TLS / certbot | **Not installed.** No certificates. Everything is plain HTTP today. For multi-tenant this is real work: every customer domain needs a certificate (per-domain issuance, or a wildcard if all tenants sit under one apex). | | DNS / dynamic subdomains | **Not set up.** No domain currently points at the server (reverse DNS is the provider default `silky-bronze.ptr.network`). No wildcard record, no per-tenant subdomain automation, no Hostinger DNS integration. The *application* is fully multi-tenant (§1a) — this is the missing infrastructure underneath it. [PHASE-9](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) specifies the target. | | Frontend deploy (CD) | **None.** Pushing to `main` deploys nothing. `architecture-governance.yml` builds and checks boundaries but has no deploy step, and nothing writes to `/srv/marketplaces/current/frontend`. Deploys are manual today. | | CI runner | None on this server; `sources.vitanova.network` CI runs elsewhere. | ## 5. To get a working dev environment Nothing here is done yet — this is the setup a backend dev does on day one. 1. Start and configure PostgreSQL; create the database and application user. 2. Design the schema from the Phase 1–4 contracts (schema design is explicitly the backend's own call — the contracts specify entities, endpoints, and invariants, never tables). Tenant scoping belongs in the schema from day one; retrofitting it is painful. 3. Build the API service, listen on `127.0.0.1:8080`. nginx already proxies `/api/` to it. 4. Implement the **bootstrap config endpoint** (§1a) — without it the frontend cannot render for any tenant. 5. Implement the Telegram session endpoints — the login flow is fully built client-side and blocked only on these. 6. Implement `GET /api/identity/v1/session/permissions` ([TRACK-S §2](TRACK-S-SECURITY-RBAC-CONTRACT.md)) — frontend route guards derive from it. 7. Seed per-marketplace bootstrap admins ([TRACK-S §8](TRACK-S-SECURITY-RBAC-CONTRACT.md)): login = marketplace slug, password = `{slug}2026$`, `mustChangePassword: true`. Steps 4–6 unblock the entire frontend. Everything after is feature work. ## 6. Frontend deploy ```bash git clone npm install # pulls @marketplaces/auth over git, no credentials needed npm run build # -> dist/dexarmarket ``` Angular 22, Node 20+. nginx serves `/srv/marketplaces/current/frontend`, so deploying means copying `dist/dexarmarket` there — **manually, today.** There is no CD pipeline. Because of the multi-tenant design (§1a), one such deploy updates every domain at once. ## 7. Known open decisions - Registry reachability for CI (reverse proxy + TLS, or a different registry entirely). - ~~Backend ownership.~~ Answered 2026-08-18: implemented by a separate backend developer against this contract set. - Additional payment providers (wallets, BNPL) — [Phase 7 §4](PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md). - Per-connector marketplace adapters — written per partner at onboarding, [Phase 4 §8](PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md). - Backfill of `Company`/`Project`/`PaymentPoint` for existing marketplaces — sequence specified in [Phase 9 §1.2](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md), not yet scheduled.