# Provider and Service Adapter Patterns

StratoFusion uses the word _adapter_ for two related but distinct module families. This guide explains both and, importantly, records which path the default service registry uses today.

Read [Provider Abstraction and Service Layer](./SERVICE_ABSTRACTION_LAYER.md) first for the contracts, canonical models, account boundary, and runtime flow.

## Current wiring

The default server path is:

```text
src/config/services/registration.ts
  -> src/services/ServiceRegistry.ts
  -> src/services/GoogleDriveService.ts
     src/services/OneDriveService.ts
     src/services/DropboxService.ts
```

The registry does not currently construct `src/infra/providers/*Provider` or automatically wrap every service with `src/services/adapters/CloudStorageAdapter`.

That distinction matters during maintenance: code existing in an adapter directory does not prove that production requests pass through it.

## Provider-specific adapters under `src/infra/providers`

Google Drive, OneDrive, and Dropbox each have a facade that implements the narrow `CloudStoragePort` and delegates to focused modules:

```text
<Provider>Provider
  -> <Provider>FileAdapter
  -> <Provider>FolderAdapter
  -> <Provider>SearchAdapter
  -> FileTransformer / ErrorTransformer
```

The concrete directories are:

- `src/infra/providers/google-drive/`;
- `src/infra/providers/onedrive/`; and
- `src/infra/providers/dropbox/`.

These facades are useful injection targets for application use cases and demonstrate the intended deep-module shape. They are not the implementation loaders used by `ServiceRegistry` today.

### Responsibilities

Provider adapters may:

- build native API requests;
- resolve roots, IDs, paths, namespaces, and paging cursors;
- translate native files and folders to `DriveItemUnion`;
- translate native errors to standard response envelopes; and
- expose configured capabilities and rclone behavior through `CloudStoragePort`.

They must not:

- expose SDK response objects as application models;
- rely on an unscoped resource ID without its provider/account context;
- put provider branching into React components;
- invent capabilities that the central provider config keeps disabled; or
- start byte-heavy rclone work inside a provider API adapter.

## Generic wrappers under `src/services/adapters`

`src/services/adapters/` is an opt-in toolkit around a full `CloudStorageService`. Its exported modules are:

| Module                    | Repository responsibility                                           |
| ------------------------- | ------------------------------------------------------------------- |
| `CloudStorageAdapter`     | Coordinates normalized execution around a supplied service instance |
| `ServiceAdapterRegistry`  | Stores explicitly registered adapter instances and their config     |
| `RequestNormalizer`       | Maps normalized operation input to configured request patterns      |
| `ResponseTransformer`     | Converts raw operation results through transformation context       |
| `AuthenticationAdapter`   | Manages adapter-level auth state and auth configuration             |
| `RetryPolicyManager`      | Applies configured retry and circuit-breaker behavior               |
| `ServiceMetricsCollector` | Keeps in-process operation metrics and evaluates thresholds         |

`createServiceAdapter(service, options)` in `src/services/adapters/index.ts` composes these pieces for a caller that explicitly opts in. `initializeAdapterEcosystem()` initializes the adapter registry but does not populate it with provider services.

Do not describe these wrappers as globally active monitoring, authentication, or retry infrastructure unless a production composition root actually registers and uses them.

## Choosing the correct extension point

| Change                                                   | Preferred boundary                                                        |
| -------------------------------------------------------- | ------------------------------------------------------------------------- |
| Add or change live provider behavior                     | The relevant `src/services/*Service.ts` implementation and central config |
| Add a provider implementation to the runtime registry    | `src/config/services/registration.ts`                                     |
| Add a narrow application use case                        | Inject `CloudStoragePort` and `RclonePort` as required                    |
| Split a provider facade into file/folder/search concerns | `src/infra/providers/<provider>/adapters/`                                |
| Normalize canonical files, folders, paths, or errors     | Provider service/transformer before returning to routes or UI             |
| Experiment with generic request/retry/metrics wrapping   | `src/services/adapters/`, with an explicit composition root               |
| Change feature availability                              | `src/config/services/<provider>.config.ts`                                |

Avoid adding a second implementation of the same rule to both adapter families. Prefer the boundary used by the live caller and migrate deliberately when consolidating architecture.

## Example: provider facade composition

```typescript
class ExampleProvider implements CloudStoragePort {
  constructor(
    private readonly files: ExampleFileAdapter,
    private readonly folders: ExampleFolderAdapter,
    private readonly searchAdapter: ExampleSearchAdapter,
  ) {}

  listFiles(accountId, options) {
    return this.files.listFiles(options ?? {});
  }

  search(accountId, options) {
    return this.searchAdapter.search(options);
  }

  // getFile, getCapabilities, and getRcloneBehavior complete the port.
}
```

The injected adapter instance must already be scoped to the correct account, or it must validate the method's `accountId`. Never silently discard a conflicting account value.

## Testing

Provider facade and base-adapter tests live beside `src/infra/providers/`. Generic wrapper tests live under `src/services/adapters/__tests__/`.

```powershell
pnpm test src/infra/providers
pnpm test src/services/adapters/__tests__
pnpm test src/config/services/__tests__/service-config.test.ts
pnpm check
```

Add provider-specific cases for native transformation, roots, missing metadata, pagination, account isolation, auth failures, throttling, timeouts, and unsupported capabilities. Keep external APIs mocked behind the service or adapter boundary.

## Related documentation

- [Provider Abstraction and Service Layer](./SERVICE_ABSTRACTION_LAYER.md)
- [Service Configuration](./SERVICE_CONFIGURATION.md)
- [Architecture](../../ARCHITECTURE.md)
- [Testing](../../TESTING.md)
