Initial Commit
This commit is contained in:
116
packages/api/api-plugin-banking/src/plugin/plugin.md
Normal file
116
packages/api/api-plugin-banking/src/plugin/plugin.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Banking plugin factory
|
||||
|
||||
## Purpose
|
||||
|
||||
`createBankingPlugin(options?)` is the package's primary entry point —
|
||||
it Zod-validates the supplied options, builds the `BankingService`
|
||||
inside the descriptor's `onInit`, bootstraps the default bank inside
|
||||
`onReady`, mounts the OpenAPIHono route tree on the host `app` under
|
||||
the configured `routePrefix`, and drops every cached reference inside
|
||||
`onClose`. The descriptor is shaped against the canonical
|
||||
`@suaveplan/api-plugin` `PluginDescriptor` so any host that consumes
|
||||
that contract can register the banking plugin without bespoke wiring.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod boundary at `createBankingPlugin(options)` — invalid input
|
||||
rejects with `BankingError(BANKING.INVALID_OPTIONS)` carrying the
|
||||
`ZodError` as `cause`.
|
||||
- Declared dependency on the `database` plugin so the topological
|
||||
loader runs the database plugin first and the `db` slot is
|
||||
populated before `onInit` resolves it.
|
||||
- Optional dependencies on `auth`, `audit`, `rate-limit` so a host
|
||||
that registers those plugins gets them loaded before banking
|
||||
(matching the enterprise audit's future-work additions); when
|
||||
absent, the plugin still works (the optional dep contract).
|
||||
- Idempotent `initializeDefaultBank` invoked from `onReady` — safe on
|
||||
every host start.
|
||||
- `decommissionBankingTenant(service, tenantId)` helper exported for
|
||||
hosts that orchestrate tenant lifecycle externally (since the
|
||||
current `PluginDescriptor` does not yet declare tenant hooks).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createBankingPlugin } from "@suaveplan/api-plugin-banking";
|
||||
|
||||
const plugin = createBankingPlugin();
|
||||
registry.register(plugin);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Customise the configuration:
|
||||
|
||||
```ts
|
||||
import { createBankingPlugin } from "@suaveplan/api-plugin-banking";
|
||||
|
||||
const plugin = createBankingPlugin({
|
||||
routePrefix: "/api/v1/banking",
|
||||
maxAccountsPerUser: 25,
|
||||
enableOverdraft: true,
|
||||
enableTransfers: true,
|
||||
defaultBankName: "Acme Trust",
|
||||
defaultSortCode: 234567,
|
||||
});
|
||||
|
||||
await registry.register(plugin);
|
||||
await registry.initAll();
|
||||
await registry.readyAll();
|
||||
```
|
||||
|
||||
Tenant decommission:
|
||||
|
||||
```ts
|
||||
import {
|
||||
decommissionBankingTenant,
|
||||
type BankingService,
|
||||
} from "@suaveplan/api-plugin-banking";
|
||||
|
||||
const service = ctx.getService("bankingService") as BankingService;
|
||||
const { banks, accounts } = await decommissionBankingTenant(
|
||||
service,
|
||||
tenantId
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `createBankingPlugin(options?: BankingPluginOptionsInput): PluginDescriptor<BankingPluginConfig>`
|
||||
|
||||
Returns a frozen descriptor. The descriptor exposes:
|
||||
|
||||
- `name: "banking"`
|
||||
- `version: "0.1.0"`
|
||||
- `dependencies: ["database"]`
|
||||
- `optionalDependencies: ["auth", "audit", "rate-limit"]`
|
||||
- `tags: ["banking", "accounts", "finance"]`
|
||||
- `defaults`: the parsed `BankingPluginConfig`
|
||||
- `onInit`, `onReady`, `onClose`
|
||||
|
||||
### `decommissionBankingTenant(service, tenantId): Promise<{ banks; accounts }>`
|
||||
|
||||
Convenience wrapper that delegates to
|
||||
`BankingService.deleteTenantData`. Returns the count of soft-deleted
|
||||
banks and hard-deleted accounts. The deletes are not atomic — if the
|
||||
underlying SurQL throws between the two, `BANKING.TENANT_CLEANUP_FAILED`
|
||||
surfaces with the partial state visible to the next call.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The plugin uses `dependencies: ["database"]`, not
|
||||
`optionalDependencies` — banking is meaningless without a database,
|
||||
and surfacing a typed `BANKING.SERVICE_NOT_AVAILABLE` for the missing-slot
|
||||
case at `onInit` time is the canonical genesis pattern (instead of
|
||||
silently no-oping).
|
||||
|
||||
The `emit` helper carries a typed-payload signature constrained by
|
||||
`BankingEventMap`. It runtime-casts to the loose `EventBusLike.emit`
|
||||
shape because `@suaveplan/types`' `EventBusLike` is intentionally
|
||||
untyped — strong typing lives on the per-plugin event map, not the
|
||||
bus. The cast is at one place and narrow.
|
||||
|
||||
`onTenantCreate` is intentionally absent because the upstream
|
||||
package's version was a no-op stub. Hosts that need per-tenant
|
||||
default-bank provisioning call `service.createBank({ ... site_id })`
|
||||
from their own tenant lifecycle hook.
|
||||
Reference in New Issue
Block a user