No shared IntegrationAdapter interface — every provider reinvents credentials/provisioning/management
Imported from GitHub issue El-SaMa/oma#101 by @El-SaMa.
Enhance, cPanel, and Hetzner each independently implement: a credential store, an API client with its own error/retry conventions, a provisioning flow, and (Enhance only) a customer-facing management-action surface. ~200+ duplicated lines between Enhance's and Hetzner's provisioning flows alone (payment-deferred handling, service-row creation, status/last_error writing, site-preview queueing).
Proposed shared contract (`packages/core-api/src/adapters/base.ts`):
```ts export interface IntegrationAdapter { readonly key: "enhance" | "cpanel" | "hetzner" | "proxmox"; credentials: { testConnection(): Promise<{ ok: boolean; error?: string }>; getDecrypted(): Promise<CredentialStoreResult | null>; save(params): Promise<void>; }; provisioning: { createService(params): Promise<{ ok: boolean; serviceId?: string; awaitingPayment?: boolean; error?: string }>; lookupProvisioned(serviceId: string): Promise<ProvisionedResourceRef | null>; }; management?: { listActions(ref): Promise<string[]>; executeAction(ref, action, params?): Promise<{ ok: boolean; error?: string }>; }; sync?: { discoverResources(): Promise<ProvisionedResourceRef[]> }; errors: { ApiError: typeof Error; TimeoutError: typeof Error }; } ```
Each adapter registers itself; `manage-actions.ts` dispatches by `service.adapter_key` instead of hardcoding `EnhanceClient`. This is the highest-leverage change for making the next integration (or next Kanta-sized feature) fast to ship.
Pairs with #99 (shared ProvisionedResource table shape) on the DB side.