|
| 1 | +# ADR: Unified Drive Domain Architecture |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +**Proposed/Draft** |
| 6 | + |
| 7 | +## Context |
| 8 | + |
| 9 | +### Problem |
| 10 | + |
| 11 | +When UserA shares a file URL copied from the browser address bar with UserB, the link |
| 12 | +is bound to UserA's instance host and often fails for UserB. |
| 13 | + |
| 14 | +1. UserA copies `https://usera-drive.twake.app/drive/#/folder/251f...` |
| 15 | +2. UserA sends the URL to UserB |
| 16 | +3. UserB opens the link on the wrong instance host and access fails or the route no |
| 17 | + longer matches their context |
| 18 | + |
| 19 | +**Root cause:** the browser URL currently identifies a user's instance. The host is part |
| 20 | +of the data context, so copying the URL does not provide a stable organization-level |
| 21 | +entrypoint. |
| 22 | + |
| 23 | +### Current Architecture |
| 24 | + |
| 25 | +```text |
| 26 | +User A: https://usera.twake.app/drive/ |
| 27 | + -> instance A data |
| 28 | +
|
| 29 | +User B: https://userb.twake.app/drive/ |
| 30 | + -> instance B data |
| 31 | +``` |
| 32 | + |
| 33 | +### Constraints |
| 34 | + |
| 35 | +- No dedicated "Copy Link" button: users copy the browser URL directly |
| 36 | +- Keep the current hash-based Drive routing model where possible |
| 37 | +- Minimize extra user interaction during access |
| 38 | +- Cross-organization sharing is secondary priority |
| 39 | + |
| 40 | +## Proposal |
| 41 | + |
| 42 | +### Unified Drive Domain |
| 43 | + |
| 44 | +Replace user-specific browser hosts with a single Drive host per organization while |
| 45 | +keeping the current hash-based routing style. |
| 46 | + |
| 47 | +```text |
| 48 | +Current: https://alice-drive.twake.app/#/folder/251f... |
| 49 | +Proposed: https://drive.twake.app/#/folder/251f... |
| 50 | +``` |
| 51 | + |
| 52 | +The main change is the host. The route format remains familiar for the frontend and for |
| 53 | +users. `drive.<org-domain>` is the page host; after bootstrap, the resolved workplace |
| 54 | +instance becomes the API and realtime host. |
| 55 | + |
| 56 | +### Chosen Architecture: Browser-Direct Access |
| 57 | + |
| 58 | +`drive.<org-domain>` serves the Drive application shell and handles auth/bootstrap. |
| 59 | +After authentication, the browser resolves the user's workplace instance and talks |
| 60 | +directly to that instance for API and realtime traffic. |
| 61 | + |
| 62 | +High-level flow: |
| 63 | + |
| 64 | +1. User opens `drive.<org-domain>` |
| 65 | +2. Drive authenticates the user and resolves their workplace instance |
| 66 | +3. The frontend initializes Drive against that instance |
| 67 | +4. API and realtime requests go directly from the browser to the resolved instance |
| 68 | +5. If a route needs extra context, such as shared-drive context, the frontend resolves |
| 69 | + it after bootstrap |
| 70 | + |
| 71 | +### Scope |
| 72 | + |
| 73 | +This ADR covers authenticated Drive access inside one organization/site. It does not yet |
| 74 | +define the final handling for cross-organization sharing, public links, or the complete |
| 75 | +migration strategy from legacy URLs. |
| 76 | + |
| 77 | +## Alternatives |
| 78 | + |
| 79 | +### Alternative 1: Backend Routing Through cozy-stack |
| 80 | + |
| 81 | +Use the Unified Drive host as the main API origin and route each request internally to |
| 82 | +the correct instance inside cozy-stack. |
| 83 | + |
| 84 | +- Pros: closer to the current single-origin frontend model |
| 85 | +- Cons: keeps routing complexity in the backend hot path for every request and adds a |
| 86 | + backend routing/proxy layer |
| 87 | + |
| 88 | +### Alternative 2: Keep Per-Instance Drive URLs |
| 89 | + |
| 90 | +Keep the existing `user-drive...` hosts and improve only redirection or discovery. |
| 91 | + |
| 92 | +- Pros: smallest short-term change |
| 93 | +- Cons: does not solve the browser address-bar copy/paste problem |
| 94 | + |
| 95 | +### Alternative 3: Full OAuth-Style Browser Access |
| 96 | + |
| 97 | +Move to a more explicit browser auth model based on OAuth/OIDC tokens instead of |
| 98 | +the current app bootstrap model. |
| 99 | + |
| 100 | +- Pros: cleaner long-term browser auth model |
| 101 | +- Cons: larger auth redesign than needed for the first iteration |
| 102 | + |
| 103 | +## Decision |
| 104 | + |
| 105 | +**Adopt the Unified Drive domain with browser-direct access to the target instance.** |
| 106 | + |
| 107 | +## Consequences |
| 108 | + |
| 109 | +### Positive |
| 110 | + |
| 111 | +1. URL sharing becomes organization-centric instead of user-centric |
| 112 | +2. The browser URL can stay stable on `drive.<org-domain>` |
| 113 | +3. The frontend can keep the current hash-router approach |
| 114 | +4. File APIs and realtime stay close to the owning workplace instance |
| 115 | + |
| 116 | +### Negative |
| 117 | + |
| 118 | +1. Frontend/bootstrap logic becomes more complex than in the current single-origin model |
| 119 | +2. Token creation and refresh must become explicit instead of being tied to the target |
| 120 | + instance serving the app |
| 121 | +3. Some routes still need extra context resolution after startup, especially around |
| 122 | + shared drives |
| 123 | +4. Cross-organization sharing remains a follow-up topic |
| 124 | + |
| 125 | +## Implementation |
| 126 | + |
| 127 | +### Assumptions |
| 128 | +* We will have one Unified Drive host per organization, for example `drive.linagora.twake.app` |
| 129 | +* We have a clean way to resolve auth context configuration from `org_domain` |
| 130 | + |
| 131 | +### User Journey: User Opens Drive |
| 132 | + |
| 133 | +#### User opens `https://drive.acme.com/#/folder/...` |
| 134 | + - Add a Unified Drive host: new handler in `routing.go` and host recognition for |
| 135 | + `drive.<org-domain>` |
| 136 | + - Until Unified Drive session/bootstrap is complete, redirect to the auth/bootstrap |
| 137 | + flow instead of serving the authenticated Drive shell |
| 138 | + - After bootstrap, serve `index.html` and static Drive assets from the Unified Drive |
| 139 | + host |
| 140 | + - Asset bytes may still come from the resolved instance's Drive bundle |
| 141 | + |
| 142 | + |
| 143 | +#### If the user is not authenticated, Drive starts the auth/bootstrap flow |
| 144 | + - Resolve `org_domain` -> `auth context` |
| 145 | + - If OIDC is configured for that context, use the OIDC flow below |
| 146 | + - If no OIDC is configured, use the discovery/login fallback below |
| 147 | + - After either flow completes, create a Unified Drive session on `drive.<org-domain>` |
| 148 | + |
| 149 | +#### OIDC login flow (NEW!!) |
| 150 | + - Start a context-first OIDC flow from Unified Drive |
| 151 | + - Unified Drive callback resolves the user's workplace instance |
| 152 | + - Unified Drive creates a session on `drive.<org-domain>` |
| 153 | + - Store `workplaceFQDN` and the originally requested Drive URL in that session |
| 154 | + - Redirect back to the requested Unified Drive URL |
| 155 | + |
| 156 | +#### Login flow without OIDC (NEW!!) |
| 157 | + - Show a discovery page on Unified Drive |
| 158 | + - User enters email, workplace URL, or slug |
| 159 | + - Resolve the real workplace instance |
| 160 | + - Redirect to that instance's existing `/auth/login` |
| 161 | + - After successful instance login, return to Unified Drive |
| 162 | + - Unified Drive creates its own session, stores `workplaceFQDN`, and redirects back to |
| 163 | + the requested Drive URL |
| 164 | + |
| 165 | +#### After login, Unified Drive serves the Drive shell |
| 166 | + - Split page host from target backend host |
| 167 | + - Serve the page and static resources from `drive.<org-domain>` |
| 168 | + - Inject the minimal bootstrap contract: |
| 169 | + - resolved workplace instance host |
| 170 | + - token/bootstrap information for browser-direct calls to that instance |
| 171 | + - locale, flags, and capabilities from the resolved instance |
| 172 | + - a token refresh path or mechanism that does not rely on the current page origin |
| 173 | + |
| 174 | +#### The frontend initializes Drive against the resolved instance |
| 175 | + - Stop assuming the current page origin is the API origin |
| 176 | + - Initialize `cozy-client` with the resolved workplace instance |
| 177 | + - Prepare realtime initialization against the same target instance |
| 178 | + |
| 179 | +#### The frontend loads the requested route |
| 180 | + - Keep current route parsing in the browser |
| 181 | + - Add a lightweight route/context resolution step after shell load when extra sharing |
| 182 | + context is needed |
| 183 | + |
| 184 | +#### The browser sends API and realtime requests directly to the resolved instance |
| 185 | + - Update token/bootstrap and refresh flows for direct instance access |
| 186 | + - Adjust CORS and related auth configuration so `drive.<org-domain>` can be the |
| 187 | + frontend origin |
| 188 | + |
| 189 | +#### The user copies the URL from the browser |
| 190 | + - Ensure the browser always shows the Unified Drive host |
| 191 | + - Define migration and redirection from legacy per-instance Drive URLs(????) |
0 commit comments