Extending Tidemark
Tidemark is designed to be extended by a separate Composer package, for example a hosted service that adds billing. Packages use these hooks and never need to edit Tidemark itself.
Entitlements
App\Contracts\Entitlements decides what an account may do:
interface Entitlements
{
public function canCreateSite(User $user): true|string; // true, or a message shown to the user
public function allowsRecording(array $site): bool; // called for every event; keep it fast
}
The default implementation only applies TIDEMARK_MAX_SITES . A package binds its own in its service provider with $this->app->singleton(Entitlements::class, MyEntitlements::class) . When allowsRecording() returns false , the event is dropped but the tracker still receives 202 ok , so visitors' browsers never see an error. $site contains id , domain and owner_id .
Events
| Event | When |
|---|---|
App\Events\SiteCreated |
A user added a site ($site, $owner) |
Illuminate\Auth\Events\Registered |
A new account registered |
Dashboard modules
Add the URL of a JavaScript module to config('tidemark.extensions') . Its default export runs before the dashboard renders and receives an api object:
export default function (api) {
const { html } = api;
api.registerAccountTab({ key: 'billing', label: 'Billing', component: Billing, dot: (user) => user.past_due });
api.registerBanner(({ user }) => html`<div class="banner">Your trial ends soon</div>`);
api.registerRoute('/pricing', PricingPage);
}
api.lib , api.ui and api.chart give access to the dashboard's helpers and components (Preact + htm, no build step needed). Account tabs appear in Account settings. The extension API is versioned (api.version ).