-- Custom routes bind a script to (host, method, path) tuples. The -- orchestrator's in-memory matcher dispatches user-defined URLs to the -- right script; the internal /api/v1/execute/{id} endpoint stays as a -- bypass that always works. -- -- host_kind / path_kind drive matching and conflict-detection semantics; -- the orchestrator parses the stored TEXT into its internal pattern -- representation on table load. See docs/versioning.md and the -- orchestrator_core::routing module for the matching rules. -- -- host_param_name is reserved for the future `{subdomain}.example.com` -- syntax; the current parser only accepts `*.example.com` (wildcard, -- no capture). -- -- method = NULL means "any HTTP method"; NULL handling in the unique -- index uses COALESCE so two "any" rows still conflict. CREATE TABLE routes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), script_id UUID NOT NULL REFERENCES scripts(id) ON DELETE CASCADE, host_kind TEXT NOT NULL CHECK (host_kind IN ('any', 'strict', 'wildcard')), host TEXT NOT NULL DEFAULT '', host_param_name TEXT, path_kind TEXT NOT NULL CHECK (path_kind IN ('exact', 'prefix', 'param')), path TEXT NOT NULL, method TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Catch the easy case of two literally identical routes at the DB level. -- Cross-pattern overlap (param vs exact for the same request shape) is -- enforced in code by the conflict detector. CREATE UNIQUE INDEX routes_unique_binding_idx ON routes (host_kind, host, path_kind, path, COALESCE(method, '')); CREATE INDEX routes_lookup_idx ON routes (host_kind, host); CREATE INDEX routes_script_id_idx ON routes (script_id);