303 lines
21 KiB
Markdown
303 lines
21 KiB
Markdown
<!-- status: build -->
|
|
<!-- started: 2026-04-26 -->
|
|
<!-- pivoted: 2026-04-28 (OAuth -> Personal Access Token) -->
|
|
<!-- pivoted: 2026-04-28 (Mail-Endpoint nicht PAT-faehig -> Calendar als zweiter aktiver Service) -->
|
|
<!-- pivoted: 2026-04-28 (Contacts-PIM-Endpoint funktioniert -> Contacts als dritter aktiver Service) -->
|
|
<!-- pivoted: 2026-04-29 (kDrive-Listing fuer non-admin-User leer -> `/2/drive/init?with=drives` als Discovery) -->
|
|
<!-- component: gateway, frontend-nyla -->
|
|
|
|
# Infomaniak Connector (kDrive + Calendar + Contacts today; Mail reserved) + UDB-Integration
|
|
|
|
## Beschreibung und Kontext
|
|
|
|
PowerOn besitzt das Provider-Connector-Pattern fuer externe Datenanbindungen
|
|
(Microsoft, Google, ClickUp). Infomaniak war bisher nicht angebunden. Ziel: ein
|
|
neuer `InfomaniakConnector`, der Daten aus den Infomaniak-Services
|
|
bereitstellt. Heute aktiv:
|
|
|
|
- **kDrive** (Pendant zu OneDrive / Google Drive)
|
|
- **Calendar** (Pendant zu Outlook-Kalender / Google Calendar; .ics-Download)
|
|
- **Contacts** (Pendant zu Outlook-Kontakte / Google Contacts; .vcf-Download)
|
|
|
|
Blockiert (Scope ist auf der PAT, Adapter wartet auf Vendor):
|
|
|
|
- **Mail** -- alle erschoepfend getesteten Pfade scheitern. Final-Befund
|
|
vom 2026-04-28:
|
|
|
|
| Pfad | Status |
|
|
|---|---|
|
|
| `api.infomaniak.com/1/mail` | 404 nginx (existiert nicht) |
|
|
| `api.infomaniak.com/2/mail?account_id=...` | 404 nginx (existiert nicht) |
|
|
| `mail.infomaniak.com/api/mail?account_id=...` | 302 -> `login.infomaniak.com/authorize` (OAuth Web-Session, nicht PAT) |
|
|
| `mail.infomaniak.com/api/mail/?account_id=...` | 301 -> `http://mail.infomaniak.com:5000` (interner Cyrus-IMAP-API-Port, von aussen nicht erreichbar) |
|
|
| `mail.infomaniak.com/api/pim/mail` | 302 -> OAuth |
|
|
| `mail.infomaniak.com/api/pim/mailbox` | 302 -> OAuth |
|
|
| `mail.infomaniak.com/api/pim/folder` | 302 -> OAuth |
|
|
|
|
Konsequenz: PowerOn kann mit dem heutigen PAT-Mechanismus die
|
|
Infomaniak-Mailbox **nicht** ansprechen. Der Scope `workspace:mail`
|
|
bleibt im Standard-PAT-Setup, sodass der MailAdapter ohne
|
|
Token-Rotation aufgeschaltet werden kann, sobald Infomaniak einen
|
|
PAT-tauglichen Endpoint freischaltet (oder wir entscheiden, die
|
|
Mail-Connection ueber einen separaten OAuth-Flow oder ein App-Passwort
|
|
ueber IMAP/SMTP einzubinden -- separater Build).
|
|
|
|
Die Verbindung ist eine reine **Daten-Connection** (`TokenPurpose.DATA_CONNECTION`).
|
|
Infomaniak ist explizit **kein** Login-Provider fuer PowerOn.
|
|
|
|
Zusaetzlich wurden zwei kleine Inkonsistenzen in der ClickUp-UDB-Anzeige
|
|
behoben (`_SERVICE_ICONS` + `_SERVICE_TO_SOURCE_TYPE`).
|
|
|
|
## Architektur-Pivot 2026-04-28: OAuth -> Personal Access Token
|
|
|
|
**Befund**: Infomaniaks `login.infomaniak.com/authorize` akzeptiert nur
|
|
Identity-Scopes (`openid`, `profile`, `email`, `phone`). Bearer-Tokens, die
|
|
gegen die Daten-APIs (`/2/drive/...`, `/1/mail/...`) funktionieren, koennen
|
|
ueber OAuth nicht ausgestellt werden -- der Versuch quittiert mit
|
|
`error=invalid_scope`. Datenzugriff laeuft bei Infomaniak ausschliesslich
|
|
ueber **Personal Access Tokens (PATs)**, die der Endnutzer manuell im
|
|
Infomaniak-Manager erstellt.
|
|
|
|
**Konsequenz**: kompletter Umbau des Auth-Teils des Connectors. Das
|
|
Provider-Connector-Pattern und die Adapter (`KdriveAdapter`, `MailAdapter`)
|
|
bleiben unveraendert -- sie konsumieren ohnehin nur einen Bearer-Token. Was
|
|
aussortiert wurde:
|
|
|
|
- OAuth-Routen (`/api/infomaniak/auth/connect[/callback]`) -> entfernt.
|
|
- Token-Refresh-Logik (`refreshInfomaniakToken`, Background-Refresh-Branch)
|
|
-> entfernt; PATs sind langlebig, kein Rotations-Lifecycle.
|
|
- Scope-Definition `infomaniakDataScopes` -> entfernt.
|
|
- `Service_INFOMANIAK_*` Env-Variablen (Client-ID/Secret/Redirect-URI)
|
|
-> entfernt; PowerOn benoetigt keine Infomaniak-App-Registrierung mehr.
|
|
- Frontend-OAuth-Popup -> ersetzt durch Modal mit Token-Eingabe + Deeplink
|
|
zum Infomaniak-Manager.
|
|
|
|
**Neuer Auth-Flow**:
|
|
|
|
1. FE: User klickt "Infomaniak" -> `POST /api/connections/` mit
|
|
`authority=infomaniak` legt PENDING-Connection an.
|
|
2. FE: Modal oeffnet sich mit Schritt-fuer-Schritt-Anleitung + Link
|
|
`https://manager.infomaniak.com/v3/ng/accounts/token/list` und
|
|
Token-Eingabefeld.
|
|
3. FE: User fuegt PAT ein -> `POST /api/infomaniak/connections/{id}/token`.
|
|
4. BE: Validiert PAT in zwei Schritten:
|
|
- `resolveOwnerIdentity()` ruft PIM Calendar (Scope
|
|
`workspace:calendar`) auf, faellt bei leerer Owner-Liste auf PIM
|
|
Contacts zurueck (Scope `workspace:contact`). Beide Endpoints
|
|
liefern den ersten Owner-Record als `{account_id, name, user_id}`.
|
|
Wenn keiner antwortet -> 400 fail-loud (PAT ist fuer kDrive
|
|
unbrauchbar, weil `/2/drive` `account_id` zwingend braucht und kein
|
|
Drive-Endpoint die Identity ohne `user_info`-Scope rausgibt).
|
|
- `GET /2/drive?account_id={resolved}` -- erwartet 200, andernfalls
|
|
400 (`drive`-Scope fehlt) bzw. 502 (Infomaniak antwortet
|
|
unerwartet). Mit der vorab resolvten `account_id` ist der Probe
|
|
deterministisch und braucht keine 422-Tolerance mehr.
|
|
Token landet als `Token` mit 10-Jahres-Horizont (`tokenStatus`-Anzeige,
|
|
analog ClickUp). `externalUsername` und `externalId` werden fuer die
|
|
UI-Anzeige gesetzt; **`externalId` ist nicht Vertragspartner des
|
|
kDrive-Adapters** (siehe "Kritische Details").
|
|
5. FE: bei Erfolg -> Modal schliesst, Liste refresht; bei Fehler ->
|
|
Connection bleibt PENDING, Modal zeigt Fehlermeldung; bei Cancel ->
|
|
Connection wird via DELETE wieder entfernt.
|
|
|
|
## Fokus und kritische Details
|
|
|
|
- **API-Pfad-Konvention** (Adapter-Path != API-Path):
|
|
- kDrive (`api.infomaniak.com`): Adapter-Path `/{driveId}/{fileId}`,
|
|
API `/2/drive/{driveId}/files/{fileId}`. **Wichtig**: das
|
|
naheliegende `/2/drive?account_id=...`-Listing ist filtered auf
|
|
Drive-Manager-Admins (`account_admin: true`) und liefert fuer
|
|
normale kSuite-Member (`role: 'user'`) sauber `200 []`, obwohl
|
|
sie das Drive lesen koennen. Der korrekte User-zentrische
|
|
Endpoint ist `GET /2/drive/init?with=drives`, der ALLE Drives
|
|
des PAT-Owners zurueckgibt -- inklusive `id`, `name`, `account_id`,
|
|
`role`. Der Adapter cached die Liste auf der Instanz
|
|
(`_ensureDrives`); ein Browse zahlt also pro Request maximal einen
|
|
`init`-Call. `/2/drive/init?with=drives` braucht NUR den `drive`-
|
|
Scope, kein `accounts` oder `user_info`.
|
|
- Calendar (`calendar.infomaniak.com/api/pim`): Adapter-Path
|
|
`/{calendarId}/{eventId}`. **Achtung**: die naheliegenden
|
|
Nested-Routes (`/calendar/{id}/event`, `/calendar/{id}/event/{id}`,
|
|
`/calendar/{id}/event/{id}/export`) sind **NICHT** PAT-faehig --
|
|
sie 302-en zur OAuth-Login-Seite. Korrekte PAT-Pfade:
|
|
- Listing: `/api/pim/event?calendar_id={id}&from=YYYY-MM-DD HH:MM:SS&to=...`
|
|
mit Pflicht-Range, max **3 Monate** (Vendor-Constraint).
|
|
Adapter wahlt fix 90-Tage-Window (heute -30 / +60).
|
|
- Detail: `/api/pim/event/{eventId}` (ohne calendar-Praefix)
|
|
- Export `.ics`: `/api/pim/event/{eventId}/export`
|
|
- Contacts (`contacts.infomaniak.com/api/pim`): Adapter-Path
|
|
`/{addressBookId}/{contactId}`. Listing der AddressBooks und der
|
|
Contacts geht via PAT, **aber Detail- und Export-Endpoints
|
|
(`/addressbook/{book}/contact/{id}` und `.../export`) sind nicht
|
|
PAT-faehig** (500 bzw. 302 OAuth). Konsequenzen:
|
|
- Listing braucht zwingend
|
|
`&with=emails,phones,addresses,details`, sonst kommen die
|
|
relevanten Felder leer (Default-Response listet nur Stammdaten).
|
|
- `.vcf`-Download wird im Adapter **selbst synthetisiert** aus dem
|
|
Listing-Record (vCard 3.0). Implementierung in
|
|
`_renderInfomaniakVcard()`.
|
|
- Geteilte Organisations-Adressbuecher haben einen leeren Namen --
|
|
der Adapter setzt dort einen Platzhalter "Organisation".
|
|
`ServiceAdapter.browse` unterscheidet die Tiefe via Segment-Count.
|
|
- **Multi-Host**: `_infomaniakGet` / `_infomaniakDownload` akzeptieren ein
|
|
optionales `baseUrl`, sodass Calendar gegen `calendar.infomaniak.com`,
|
|
Contacts gegen `contacts.infomaniak.com` und kDrive gegen
|
|
`api.infomaniak.com` laufen.
|
|
- **Zwei Resolver, getrennte Verantwortung**:
|
|
- `resolveOwnerIdentity(token)` -> Display-Name + kSuite-`account_id`,
|
|
rein fuer das UI-Label der Connection. Erste Quelle PIM Calendar,
|
|
Fallback PIM Contacts; nimmt den ersten Owner-Record (`user_id > 0`
|
|
und `isinstance(account_id, int)`).
|
|
- `listAccessibleDrives(token)` -> Liste **aller** Drives, die der
|
|
PAT-Owner sehen kann (egal mit welcher Rolle). Ein einzelner
|
|
`GET /2/drive/init?with=drives`-Call, vom `KdriveAdapter` benutzt
|
|
statt des admin-only `/2/drive?account_id=...` Listings.
|
|
Beide raisen `InfomaniakIdentityError` mit einer scope-spezifischen
|
|
Fehlermeldung, sodass der Submit-Endpoint pro fehlendem Scope eine
|
|
eigene 400-Message zurueckgeben kann.
|
|
- **`externalId` ist UI-State, kein Adapter-Vertragspartner**: Submit
|
|
speichert `externalId = str(kSuiteAccountId)` fuer die ConnectionsPage
|
|
(Anzeige + Konsistenz mit anderen Providern), aber der KdriveAdapter
|
|
liest ihn nie -- er fragt zur Laufzeit `/2/drive/init?with=drives`.
|
|
- **Antwort-Wrapping**: Erfolgreiche Responses sind als
|
|
`{result: 'success', data: ...}` gewrappt -- `_unwrapData()` normalisiert.
|
|
- **Token-Validation** im Submit-Endpoint: zwei harte 200-Schritte,
|
|
jeder probet genau einen Scope:
|
|
1. `listAccessibleDrives` -> probet `drive`-Scope und stellt sicher,
|
|
dass mindestens ein erreichbarer kDrive existiert.
|
|
2. `resolveOwnerIdentity` -> probet `workspace:calendar` /
|
|
`workspace:contact`-Scope (mindestens einer noetig).
|
|
Jeder Schritt liefert eine eigene 400-Message, die exakt den fehlenden
|
|
Scope nennt.
|
|
- **Token-Persistenz**: `expiresAt = now + 10*365*24*3600`, `tokenRefresh = None`;
|
|
`getTokenStatusForConnection` zeigt damit `active`, kein "none".
|
|
|
|
## Ziel und Nicht-Ziele
|
|
|
|
- Ziel: Infomaniak-Daten (kDrive + Mail) wie MSFT/Google im UDB browsbar.
|
|
- Ziel: ConnectionsPage hat Button "Infomaniak" mit PAT-Modal.
|
|
- Ziel: Setup ohne Operator-Interaktion (keine globale App-Registrierung).
|
|
- Ziel: ClickUp-UDB-Inkonsistenz beheben (Service-Icon + Source-Type-Mapping).
|
|
- NICHT: Infomaniak als PowerOn-Login.
|
|
- NICHT: Upload-Implementierung in kDrive/Mail.
|
|
- NICHT: Auto-Refresh fuer Infomaniak (PATs sind langlebig; bei Ablauf legt
|
|
der User eine neue Connection an).
|
|
|
|
## Betroffene Module
|
|
|
|
- Gateway:
|
|
- `modules/datamodels/datamodelUam.py` (Enum erweitert)
|
|
- `modules/auth/oauthProviderConfig.py` (Infomaniak-Scopes raus)
|
|
- `modules/auth/tokenManager.py` (Infomaniak-Init + Refresh raus)
|
|
- `modules/auth/tokenRefreshService.py` (Infomaniak aus Background-Refresh raus)
|
|
- `modules/connectors/providerInfomaniak/connectorInfomaniak.py` (Adapter unveraendert)
|
|
- `modules/connectors/connectorResolver.py` (Registry, unveraendert)
|
|
- `modules/routes/routeSecurityInfomaniak.py` (komplett neu: PAT-Submit-Endpoint)
|
|
- `modules/routes/routeDataConnections.py` (`connect_service` antwortet bei
|
|
Infomaniak mit 400 + Hinweis)
|
|
- `gateway/.env` + `env_dev/int/prod[_forgejo].env` (Service_INFOMANIAK_* raus)
|
|
- Frontend:
|
|
- `src/api/connectionApi.ts` (`submitInfomaniakToken` neu)
|
|
- `src/hooks/useConnections.ts` (`createInfomaniakConnection` +
|
|
`submitInfomaniakToken` ersetzen `createInfomaniakConnectionAndAuth`,
|
|
OAuth-Popup-Branch fuer Infomaniak entfernt)
|
|
- `src/pages/basedata/ConnectionsPage.tsx` (PAT-Modal)
|
|
- `src/components/UnifiedDataBar/SourcesTab.tsx` (unveraendert seit Phase 1)
|
|
- Doku:
|
|
- `wiki/d-guides/infomaniak-oauth-setup.md` -> geloescht
|
|
- `wiki/d-guides/infomaniak-token-setup.md` -> neu
|
|
- DB-Migration: nein.
|
|
|
|
## Entscheidungen
|
|
|
|
| Datum | Entscheidung | Begruendung |
|
|
|------------|--------------|-------------|
|
|
| 2026-04-26 | Self-contained Connector (httpx im Modul, kein eigener Service) | Folgt Google/MSFT-Pattern, nicht ClickUp-Pattern |
|
|
| 2026-04-26 | Nur DATA_CONNECTION, kein Login | User explicitly: "wir benoetigen nur den userconnection auth" |
|
|
| 2026-04-26 | `kdrive` + `mail` als Service-Namen | Konsistent mit Infomaniak-Branding |
|
|
| 2026-04-28 | OAuth raus, Personal Access Token rein | Infomaniak's `/authorize` unterstuetzt fuer Datenzugriff keine Scopes; nur PATs liefern brauchbare Bearer-Tokens (`error=invalid_scope` bei OAuth-Versuch) |
|
|
| 2026-04-28 | Token-Validierung gegen `/1/profile` | Leichter Endpoint, liefert User-Identity (`id`, `login`, `email`) zur Anzeige im FE; gibt 401 bei ungueltigem PAT |
|
|
| 2026-04-28 | `/1/profile` raus, Validierung gegen `/2/drive` + `/1/mail` | Profile braucht zusaetzlich Scope `user_info`; mit Drive- + Mail-Probes verifizieren wir nur die fuer Adapter benoetigten Scopes |
|
|
| 2026-04-28 | `/1/mail` raus, Validierung gegen `calendar.infomaniak.com` + `/2/drive` | `/1/mail` existiert nicht (404 nginx); `mail.infomaniak.com/api/mail` redirected zu OAuth (302). Calendar-PIM-Endpoint funktioniert mit PAT und liefert Identity (account_id/user_id/name) gleich mit. |
|
|
| 2026-04-28 | `account_id` in `UserConnection.externalId` persistieren (zurueckgenommen 2026-04-28 abends) | War als Cache-Optimierung gedacht, hat aber zwei Concerns vermischt: (1) UI-Anzeige der Connection und (2) Adapter-Vertragspartner. Existierende Connections konnten dadurch mit einem Token-Fingerprint statt account_id korrumpiert werden, was im kDrive-Browse zu 422 fuehrte. |
|
|
| 2026-04-28 | `KdriveAdapter` resolvt `account_id` zur Laufzeit selbst (`_ensureAccountId`) ueber `resolveOwnerIdentity()` | Saubere Trennung: `externalId` ist nur UI-State, der Adapter ist self-contained und braucht keine Connection-Felder zu lesen. Damit gibt es keinen Migrationspfad und keine Korruption mehr -- der Adapter heilt sich automatisch. Cache auf Adapter-Instanz vermeidet wiederholte API-Calls innerhalb desselben Requests. |
|
|
| 2026-04-28 | Identity-Resolver (Calendar -> Contacts) zentral in `resolveOwnerIdentity()` | Beide PIM-Endpoints liefern dieselbe Owner-Struktur (`user_id`/`account_id`/`name`); ein gemeinsamer Resolver verhindert, dass Submit und Adapter divergieren. Die Sequenz Calendar -> Contacts deckt alle realistischen Setups ab (mindestens einer der beiden Scopes muss auf der PAT sein, damit kDrive ueberhaupt nutzbar ist). |
|
|
| 2026-04-29 | Calendar-Events ueber `/api/pim/event?calendar_id=...` (nicht `/calendar/{id}/event`) | Live-Test 2026-04-29: nested Route 302 zu OAuth, flat Route 200. Die offizielle PAT-faehige Route fordert `from`/`to` als Y-m-d H:i:s mit max-3-Monats-Range -- Adapter waehlt fixes 90-Tage-Window. |
|
|
| 2026-04-29 | `.vcf`-Download per Hand synthetisieren (`_renderInfomaniakVcard`) | Alle Contacts-Detail-/Export-Endpoints sind nicht PAT-faehig (500 bzw. 302 OAuth). Wir holen das Listing mit `with=emails,phones,addresses,details` (PAT-faehig) und rendern vCard 3.0 selbst -- konsistent mit MSFT/Google-Contacts-Adapter, der dieselbe Synthese betreibt. |
|
|
| 2026-04-29 | `KdriveAdapter` discoverte Drives ueber `/2/drive/init?with=drives` statt `/2/drive?account_id=X` | Live-Beweis vom User: Drive 2980592 existiert in account 1696919 mit Files (PDF + 2 Folders), `/2/drive?account_id=1696919` antwortet trotzdem `200 []`, `/2/drive/2980592/files` zeigt alle Files. Diagnose: `/2/drive` ist Drive-Manager-Admin-Sicht (filtered auf `account_admin: true`), normaler kSuite-Member (`role: 'user'`) sieht dort nichts -- ist nicht Vendor-Bug, sondern Spec. Loesung gefunden via Endpoint-Probing: `/2/drive/init?with=drives` ist die User-zentrische Drive-Liste, die ALLE zugaenglichen Drives unabhaengig von der Admin-Rolle liefert (verifiziert mit PAT der `accounts`-Scope explizit nicht hat -> 200, alle Drives drin). Damit wird der zwischenzeitlich eingefuehrte `accounts`-Scope-Workaround wieder entfernt -- er war eine Sackgasse, weil `/1/accounts` die Manager-Organizations listet (1 pro User in den meisten Faellen), nicht die Drive-Accounts. Der `init`-Endpoint braucht nur den `drive`-Scope, der bereits im PAT-Standard-Setup ist; keine Token-Rotation noetig. |
|
|
| 2026-04-28 | MailAdapter und ContactAdapter NICHT registrieren bis Endpoint gefunden | 302-Redirects zu OAuth wuerden im UDB als kaputter Service erscheinen; lieber gar nicht zeigen. |
|
|
| 2026-04-28 | ContactAdapter aktivieren via `contacts.infomaniak.com/api/pim/addressbook` | Nachgereichter curl-Test zeigte 200 + JSON mit derselben Struktur wie Calendar (`addressbooks[].id/name/account_id/...`). Singular-Pfad funktioniert (`/contact` und `/contacts` reden weiter mit OAuth). Adapter ist 1:1 analog `CalendarAdapter`, nur mit `addressbook` statt `calendar` und `.vcf` statt `.ics`. |
|
|
| 2026-04-28 | `expiresAt = now + 10y` fuer PATs | Analog ClickUp, sonst markiert `getTokenStatusForConnection` die Connection als "none" |
|
|
| 2026-04-28 | Connection up-front, dann PAT-Submit (statt Submit-erst-dann-erstellen) | Nutzt vorhandenen `POST /api/connections/`-Pfad ohne Sonderbehandlung; Cancel rollback via DELETE auf Modal-Schliessen |
|
|
|
|
## Umsetzungs-Checkliste
|
|
|
|
- [x] AuthAuthority-Enum erweitert
|
|
- [x] InfomaniakConnector + KdriveAdapter (discovert Drives zur
|
|
Laufzeit ueber `listAccessibleDrives()` -> `/2/drive/init?with=drives`,
|
|
cached die Liste auf der Adapter-Instanz) + CalendarAdapter
|
|
+ ContactAdapter
|
|
- [x] `resolveOwnerIdentity()` als reiner UI-Identity-Helper
|
|
(Display-Name + kSuite-account_id fuer das Connection-Label)
|
|
- [x] `listAccessibleDrives()` als Drive-Discovery-Helper
|
|
(`/2/drive/init?with=drives`, `drive`-Scope-Probe, raised
|
|
`InfomaniakIdentityError` mit klarer Scope-Message)
|
|
- [x] ConnectorResolver-Registry (alle Adapter werden uniform mit
|
|
`accessToken` konstruiert; keine Sonderbehandlung in
|
|
`getServiceAdapter`)
|
|
- [x] Setup-Guide (PAT-basiert, Calendar + Contacts als zusaetzliche aktive Services)
|
|
- [x] PAT-Submit-Endpoint `POST /api/infomaniak/connections/{id}/token`
|
|
(Pre-Flight in 2 Schritten: `listAccessibleDrives` (`drive`-
|
|
Scope), `resolveOwnerIdentity` (`workspace:calendar` /
|
|
`workspace:contact`) -- jeder Schritt mit eigener 400-Message)
|
|
- [x] OAuth-Routen entfernt
|
|
- [x] Infomaniak-Refresh aus tokenManager + tokenRefreshService entfernt
|
|
- [x] Infomaniak-Scopes aus `oauthProviderConfig` entfernt
|
|
- [x] `Service_INFOMANIAK_*` aus allen .env-Dateien entfernt
|
|
- [x] DataConnections-Dispatch (Infomaniak-Branch in `connect_service` -> 400)
|
|
- [x] FE-Hook umgebaut (`createInfomaniakConnection` + `submitInfomaniakToken`)
|
|
- [x] FE-OAuth-Popup-Branch fuer Infomaniak entfernt
|
|
- [x] ConnectionsPage-PAT-Modal
|
|
- [x] UDB-Integration (Authority-Icon, Service-Icons, Source-Colors)
|
|
- [x] ClickUp-UDB-Fix
|
|
- [ ] Manueller End-to-End-Test (Token im Manager erstellen, in Modal
|
|
pasten, kDrive browsen, Calendar browsen, Contacts browsen,
|
|
Datei + .ics + .vcf downloaden)
|
|
- [x] Mail-API-Pfad verifiziert -- alle 7 erschoepfend getesteten Pfade
|
|
scheitern (siehe "Blockiert" oben). Adapter pausiert bis Infomaniak
|
|
einen PAT-faehigen Endpoint freischaltet.
|
|
- [ ] `wiki/b-reference/connectors.md` (falls vorhanden) ergaenzen
|
|
|
|
## Akzeptanzkriterien
|
|
|
|
| # | Kriterium (Given-When-Then) | Prio |
|
|
|---|-----------------------------|------|
|
|
| 1 | Given Nutzer auf ConnectionsPage, When er auf "Infomaniak" klickt, Then oeffnet sich ein Modal mit Token-Eingabe und Deeplink zu `manager.infomaniak.com/v3/ng/accounts/token/list` | must |
|
|
| 2 | Given gueltiger PAT mit Scopes `drive`+(`workspace:calendar` ODER `workspace:contact`) im Modal, When Submit, Then ist die UserConnection `ACTIVE`, Token gespeichert, `externalId=kSuiteAccountId`, `externalUsername=Owner-Anzeigename aus PIM` | must |
|
|
| 3 | Given ungueltiger PAT oder fehlender Scope (`drive` ODER weder `workspace:calendar` noch `workspace:contact`), When Submit, Then bleibt Connection PENDING, Modal zeigt 400-Detail das den fehlenden Scope namentlich nennt | must |
|
|
| 4 | Given aktive Connection, When im UDB die Authority expandiert wird, Then werden Services `kdrive`, `calendar` und `contact` mit Icons angezeigt | must |
|
|
| 4b | Given aktive Connection, When im UDB `kdrive` expandiert wird, Then erscheinen alle Drives die der User sehen kann -- auch wenn er dort nur `role: 'user'` hat (Adapter discovert ueber `/2/drive/init?with=drives`, nicht ueber das admin-only `/2/drive?account_id=...` Listing) | must |
|
|
| 4c | Given aktive Connection, When im UDB `calendar` expandiert wird, Then erscheinen Kalender, dann Events; Event-Download liefert `.ics` | must |
|
|
| 4d | Given aktive Connection, When im UDB `contact` expandiert wird, Then erscheinen Adressbuecher, dann Kontakte; Kontakt-Download liefert `.vcf` | must |
|
|
| 5 | Given Modal offen, When User auf Cancel/X klickt, Then wird die soeben erstellte PENDING-Connection wieder geloescht | should |
|
|
| 6 | Given ClickUp-Service-Node im UDB, Then ist das Service-Icon das Klemmbrett (Fix) | should |
|
|
|
|
## Testplan
|
|
|
|
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|
|
|----|----|-----|---------------|-----------|--------|
|
|
| T1 | 1-3 | manual | nein | UI: ConnectionsPage Modal | pending |
|
|
| T2 | 4 | manual | nein | UI: UDB SourcesTab | pending |
|
|
| T3 | 5 | manual | nein | UI: ConnectionsPage Modal Cancel | pending |
|
|
| T4 | 6 | manual | nein | UI: UDB SourcesTab | pending |
|
|
|
|
## Links
|
|
|
|
- PR: tbd
|
|
- Setup-Guide: `wiki/d-guides/infomaniak-token-setup.md`
|
|
|
|
## Abschluss
|
|
|
|
- [ ] `b-reference/` aktualisiert
|
|
- [ ] `TOPICS.md` aktualisiert
|
|
- [ ] Dokument nach `z-archive/` verschoben
|