Commit ce06efbe authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

docs: add initial portal documentation with overview, requirements, and implementation details

parent 8413625d
Loading
Loading
Loading
Loading

portal/index.md

0 → 100644
+7 −0
Changes for portal/index.md: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Portal

Three-part spec; read in order.

* [Overview & Architecture](overview-and-architecture.md) — what the portal is, who sees what, boundaries, scope
* [Requirements & Design](requirements-and-design.md) — requirements, backend routes, login and session design, API clients, data model, flows
* [Implementation & Delivery](implementation-and-delivery.md) — code layout, configuration, deployment, testing, and what comes in the next release
+186 −0
Changes for portal/overview-and-architecture.md: 186 added lines, 0 removed lines.
Original line number Diff line number Diff line
---
type: Architecture Spec
title: "Portal — Overview & Architecture"
description: "What the OOP Portal is and is not, the backend that acts for the browser, who sees which page, the portal's boundaries with OEG, Keycloak and AI², and open questions."
tags: [portal, bff, architecture]
timestamp: 2026-10-07T00:00:00Z
component: Portal
version: "2.0"
status: "ETSI SDG OOP — first specification of a component already in use"
---

# Portal — Overview & Architecture

**Companion documents:**
[portal/requirements-and-design.md](/portal/requirements-and-design.md),
[portal/implementation-and-delivery.md](/portal/implementation-and-delivery.md)

**Closest neighbours:**
[platform/architecture.md](/platform/architecture.md),
[oeg/architecture.md](/oeg/architecture.md),
[ADR-0048](/decisions/0048-platform-roles.md)

---

## Mental Model

**The portal is a window onto the platform, not part of it.** People use it to find APIs,
try them, run edge applications, get credentials for their own software and, as operators,
federate with partners. Every action ends up as a call to OEG, Keycloak or the AI² agent.
The portal itself keeps only what it needs to log people in and to remember who owns which
API client.

**The browser never holds a token.** It holds cookies. The portal backend keeps the user's
tokens, encrypted, and makes each call for the user.

```text
  +-----------------------------+
  | Browser (React app)         |
  | holds cookies, never tokens |
  +--------------+--------------+
                 |  /        the app
                 |  /api/*   the backend
                 v
  +-----------------------------+  /api/auth/*         +-----------+
  | Portal backend (FastAPI)    |--------------------->|           |
  | one container               |  /api/api-clients/*  | Keycloak  |
  |                             |--------------------->|           |
  |                             |                      +-----------+
  |                             |  /api/oeg/*          +-----------+
  |                             |--------------------->| OEG       |
  |                             |                      +-----------+
  |                             |  /api/ai2/chat       +-----------+
  |                             |--------------------->| AI2 agent |
  +--------------+--------------+                      +-----------+
                 |
                 v
  +-----------------------------+
  | PostgreSQL `portal`         |
  | sessions, login attempts,   |
  | API clients, entitlements   |
  +-----------------------------+
```

---

## A. Summary

**Success definition.** A person with an OOP account can log in, see only the pages their
roles allow, and do through the browser what OEG lets them do, without any token reaching the
browser.

### A.1 Scope and ownership

| Concern | Position | Record |
|---|---|---|
| Shape | One container: a FastAPI backend that serves the built React app at `/` and its own API at `/api/*` | [ADR-0064](/decisions/0064-portal-is-one-container-with-a-thin-backend.md) |
| Backend role | Forwards calls | [ADR-0064](/decisions/0064-portal-is-one-container-with-a-thin-backend.md) |
| Login | OpenID Connect with Keycloak; tokens stay in the backend, encrypted with a key only the user's cookie holds | [ADR-0065](/decisions/0065-portal-sessions-keyed-by-the-cookie.md) |
| Roles | The three realm roles; the portal hides what a role may not use | [ADR-0048](/decisions/0048-platform-roles.md) |
| API access | OEG checks every call; the portal never decides on OEG's behalf | [ADR-0048](/decisions/0048-platform-roles.md) |
| API clients | Registered in Keycloak by the portal, for the products the developer already holds | [ADR-0066](/decisions/0066-api-clients-through-keycloak-client-registration.md) |
| Federation | Operator pages over OEG's federation API; the portal never calls FM | [ADR-0043](/decisions/0043-oeg-proxied-federation-establishment.md) |


### A.2 Who sees what

Every new user gets `app-provider` (ADR-0048). A page a role may not use is hidden from the
menu and refused if opened by its address.

Roles add up: a user sees every page any of their roles allows. Operators keep the
`app-provider` role every user gets, so they see the API clients page too.

| Page | Needs |
|---|---|
| Home, Profile | Logged in |
| API Catalog, API overview and "try it" | Logged in |
| Edge Application Management: profiles, instances, deployments, zones | Logged in |
| AI² chat | Logged in |
| API clients | `app-provider` |
| Federation, and the federation API in the catalog | `operator` |

What a call may actually do is OEG's decision. A user without the `edge-application-management`
product sees the Edge Application Management pages, but OEG refuses their calls.

`platform-admin` has no page yet: user administration comes in the next release
([implementation-and-delivery.md §U](/portal/implementation-and-delivery.md)).

---

## B. Terms

Platform-wide terms: [platform/glossary.md](/platform/glossary.md).

| Term | Meaning here |
|---|---|
| **Portal backend** | The FastAPI service. It is the only part that talks to OEG, Keycloak and AI². Elsewhere called the BFF (Backend for Frontend) |
| **Login session** | One logged-in browser: a cookie, plus a database row with that browser's tokens, encrypted |
| **API product** | One CAMARA API offered as a unit, with its scopes ([glossary](/platform/glossary.md)) |
| **Product grant** | Permission to use one API product ([glossary](/platform/glossary.md)) |
| **API client** | Credentials a developer creates in the portal so their own software can call OEG. A Keycloak confidential client with its own secret |
| **Provisioner** | The Keycloak client the backend uses to create API clients. It has only the rights that needs |

---

## C. Features

| ID | Feature | Who |
|---|---|---|
| UC-PORTAL-01 | Log in and sign up on Keycloak's own pages; log out of both portal and Keycloak | Everyone |
| UC-PORTAL-02 | Browse the API catalog, read each API's guide, try its operations in the browser | Everyone |
| UC-PORTAL-03 | Onboard application profiles, start and stop instances, deploy to edge cloud zones, list zones | Everyone, as far as OEG allows |
| UC-PORTAL-04 | Create and delete API clients for the products they hold; see the secret once | `app-provider` |
| UC-PORTAL-05 | Register and update partner operators, create and end federations, subscribe to partner zones | `operator` |
| UC-PORTAL-06 | Ask the AI² agent to do things on the platform | Everyone |
| UC-PORTAL-07 | See their own account: username, email, organization, roles | Everyone |

---

## D. Boundaries

**Upstream: people, through a browser.** The portal's API accepts only the session cookie,
never a bearer token, so software cannot call it. Software calls OEG directly with its own
Keycloak client, normally an API client a developer created in the portal.

**OEG: every platform action.** The portal forwards calls to OEG with the user's own access
token, so OEG sees the real user and applies its own role and scope checks. The portal does not
call SRM or FM.

**Keycloak: identity.** Keycloak owns users, passwords, roles and grants. The portal logs users
in through it, reads what it says about a user, and registers API clients in it. Sign-up and
password pages are Keycloak's, so the portal never handles a password.

**AI²: the agent.** The portal forwards chat messages with the user's token, so the agent acts
as the user. The agent's address is backend configuration; the browser does not know which
model runs behind it.

---

## E. Assumptions

| ID | Assumption | Risk if wrong |
|---|---|---|
| E1 | People open the portal on the address its login redirect names (`publicUrl` in Helm, `OIDC__REDIRECT_URI` in development) | The login cookie set on one address is missing when Keycloak returns to the other, so every login fails as "expired" |
| E2 | Keycloak issues the portal's tokens for OEG too (`oeg` audience, the CAMARA scopes of the user's grants), and OEG trusts the same public issuer | OEG refuses every forwarded token; every OEG page shows 502 "OEG did not accept the credentials" |
| E3 | Keycloak refuses a refresh once a user is disabled or their password is reset | A removed user keeps working until their session ends |
| E4 | OEG's `openapi.json` lists every API the catalog should show | The catalog misses APIs |

---

## F. Open Questions

**F1. Product lists live in two places.** The products and their scopes come from Helm's
`global.apiProducts`, which also builds Keycloak's roles. The catalog's grouping of OEG paths
into APIs is a separate list in the frontend. Adding a product means changing both.

**F2. AI² holds the user's full rights.** The agent gets the same access token the user's
browser session uses, so it can do anything the user can. A narrower token for the agent
would need a Keycloak token exchange or a separate client.

---

## Revision History

| Version | Date | Summary |
|---------|------|---------|
| 2.0 | 2026-10-07 | First Portal specification, describing the Release 2 implementation. Records ADR-0064 to ADR-0066. |