Data Rules
Which tables a connector may create, which it may never touch, and how the core points at a connector's rows.
The core owns the rows that describe a membership: installations, identities, spaces, grants, members, subscriptions and payments. A connector owns only what the platform makes it keep, such as a bot row with its token or a cached chat title, and keeps it in tables of its own. The rules below make it possible to remove a connector from the codebase without breaking the core, and to uninstall one from a project without cascading into anything a member paid for.
The rules
- Prefix every table with the connector key. A connector whose key is
examplecreatesexample_bots,example_chats, neverbots. The kit reads the migration sources and fails aSchema::createwithout the prefix before anything runs. - Never alter a core table. No
Schema::table,drop,dropIfExistsorrenameon a table the connector does not own. Anything a connector needs to record about a project, a member or a grant goes through the Core API into the core's tables. - Foreign keys point inward only. A connector table may hold
project_id,installation_idoridentity_idwithcascadeOnDelete, so a project's deletion tidies the connector's rows. The core never holds a foreign key into a connector table: the core rows carry a softstorage_refstring that names the connector's row, and the connector resolves it. - Additive after first publish. Once a version has been installed anywhere, later migrations add. A change of shape is expand → verify → contract: add the new column or table, move the data and prove it moved, and drop the old shape in a later release, never the same one.
- Tenant filtering is explicit. The core's tenant scope is inert for connector ingress, so a connector repository filters by project or installation itself (
forProject(),forInstallation()) rather than trusting a global scope.
The kit checks the sources, not the database
MigrationRules::violations($connector, $migrationsPath) scans database/migrations for Schema::create and Schema::table|drop|dropIfExists|rename calls and reports every table without the prefix as file: what. It runs inside the conformance suite as migrations.own_tables_only, so the rule fails on the developer's machine.
What the core keeps for you
| Core table | What it holds | Reached through |
|---|---|---|
connector_installations | One row per installation: project or platform scope, live or standby role, state, encrypted credentials, health, storage_ref. | Core\Installations |
connector_identities | One row per account the connector has seen, with the installation that saw it and storage_ref. | Core\Identities |
connector_spaces | One row per gated place, with kind, parent and health. | Core\Spaces |
access_grants | One row per (subscription, resource, window): mode, state, the connector's reference, failure kind. | Core\Grants |
connector_inbound_events | The idempotency keys of inbound events, pruned after seven days. | The core, before your port |
Credentials are encrypted at rest in connector_installations.credentials and handed to your ports as a CredentialBag; do not copy a token into your own table unless the platform's client library forces it, and never log one.
Uninstall, reinstall and purge
- Disconnect wipes the installation's credentials and stops it acting. Your tables are untouched.
- Uninstall revokes the connector's grants, detaches its resources (external ids kept) and keeps the installation row, identities and your tables. Nothing is deleted, so a reinstall re-links detached places and can restore access.
- Purge (run by Subscriby's operators for a retention rule or an erasure request, and only after the connector was uninstalled) deletes, for one project on that connector, the core's grants (their creator tasks with them), the spaces the project's resources point at, the member identity links, and the uninstalled installation rows; your own rows go with the installation rows through the
installation_idcascades rule 3 asks for. Identities, members, subscriptions, payments, support threads and the resource rows themselves stay, because they are the audit trail; a member's own erasure goes through the identity unlink path. Operators rehearse it first, which prints the same per-table counts and deletes nothing. It deletes data, never schema.
How is this guide?
Getting Started
The layout of a connector package, the service provider that wires it in, and the ports every connector binds.
Testing a Connector
The fakes the SDK ships, the assertions they offer, what a connector's own test suite should cover port by port, how the kit runs against a package, and what only a real platform can prove.