ADR-010: API Versioning and RLS
Geliştirme · 0.0.0-dev
Yayın
- Doküman
- 0.0.0-dev
- Uygulama
- 0.0.0
Bu sayfa
- Uygulama
- 0.0.0
- Status: Accepted
- Date: 2026-08-18
- Decision owners: API, database, security and release maintainers
- Scope: PostgREST/Supabase contract authority, grants, RLS and safe routine execution
Context
Bölüm başlığı “Context”Munderecat will expose immutable corpus text, evolving annotations, curation workflows and policy-qualified lookup through Supabase/PostgREST. Those data classes do not share one lifecycle or visibility rule. Published core may be public, a user’s draft may be private, a review queue may be role-limited and provenance evidence may contain paths, selectors or diagnostics that must never reach a public client.
PostgreSQL object existence is not an API contract. A table can appear in an exposed
schema while having an internal shape, a helper function can accidentally inherit
PUBLIC EXECUTE, and a view can bypass the caller’s RLS when it runs with owner rights.
Application-side filters and hidden frontend controls cannot repair those database
authority mistakes.
Versioning has separate ambiguity. Code, database schema, public JSON shape, data release and policy can change independently. Returning a current row without identifying the effective data and policy can silently change an old URL or reference. Conversely, encoding every code deploy into an API path would create needless breaking versions.
ADR-003 supplies release manifests. ADR-006 separates private audit closure from public projections. ADR-007 defines accepted curation and atomic compare-and-apply. ADR-008 and ADR-009 require policy-bound, set-valued lookup states. ADR-021 defines non-login, non-bypass database capability roles and explicit grants. This ADR defines the API/RLS contract that must preserve those boundaries.
Decision
Bölüm başlığı “Decision”Independent version axes
Bölüm başlığı “Independent version axes”Munderecat records these identities independently:
| Axis | Meaning | Example change |
|---|---|---|
api_contract_release |
Public operations, request/response semantics and authorization | Rename/remove a field |
code_release |
Deployed application and pipeline code | Internal optimizer fix |
schema_release |
Exact database objects, owners, grants, RLS and definitions | Add an index or policy |
data_release |
Exact accepted core/annotation/relation roots | Publish corrected corpus data |
policy_release |
Versioned resolution/propagation/visibility decisions | Change current-resolution policy |
One release manifest binds the compatible tuple used by a deployment, but no axis borrows another’s identity. A code deploy with no contract change does not mint an API version. A new data release can use an existing API contract if its semantics and capability remain compatible. A contract cannot claim compatibility with a schema/data/policy combination that its release manifest did not validate.
Every successful public response identifies at least the exact API contract release and effective data release. Operations using resolution, alignment, repetition, dictionary or other policy also identify the effective policy release. Schema and code release IDs remain available in release/debug metadata subject to disclosure policy; clients do not infer them from timestamps or server headers.
Contract records and identity
Bölüm başlığı “Contract records and identity”The logical contract model has these records:
| Record | Meaning |
|---|---|
api_contract |
Stable public major-line identity and compatibility promise |
api_contract_release |
Immutable exact operation/schema release within one major line |
api_operation |
Globally stable logical purpose independent of wire revision |
api_operation_revision |
Immutable major/contract-bound method, input, output and authority semantics |
access_policy |
Versioned role, row-visibility and action rules used by operations |
exposure_manifest |
Exact allowlisted database relations/routines and grants |
api_deprecation |
Announced support-window transition for one contract/operation |
api_deployment |
Exact compatible contract/code/schema/data/policy tuple made visible |
All are package-deterministic, version-controlled identities except an emergency deployment withdrawal, which is an ADR-007/release incident event and does not rewrite the withdrawn records. Identity facts include the complete canonical contract or policy document digest. Mutable labels, OpenAPI ordering, database OIDs and deployment times are not identity inputs.
An api_operation ID is globally unique and permanently denotes one logical capability,
such as exact entity lookup. It may have revisions in several major lines only through
explicit api_operation_revision records. A revision belongs to exactly one contract
release and binds the complete request, response, authorization and error semantics.
Changing those facts issues a new revision ID. Sharing the logical operation across
majors does not imply wire compatibility, and one ID is never reused for a different
purpose. Historical contract releases and revisions remain resolvable after deprecation
or withdrawal even when execution is no longer available.
Contract version rules
Bölüm başlığı “Contract version rules”Public contracts use semantic major.minor.patch labels bound to immutable release IDs:
majorchanges when a client-visible field, type, cardinality, interpretation, authorization requirement, default release/policy behavior or error-state meaning is removed or changed incompatibly;minoradds optional operations/fields or capabilities while preserving all existing accepted behavior; andpatchcorrects non-semantic contract metadata or documentation without changing any accepted request, response, error or authorization behavior.
An implementation defect fix with unchanged declared contract produces a code_release,
not an API patch. If the deployed observable contract changes, contract compatibility is
evaluated from the old and new accepted behavior and receives the required API release;
calling the change a bug fix cannot bypass that result.
F2-018 will define the project-wide compatibility matrix. Until then, uncertainty is breaking. A database migration, function replacement or TypeScript type change cannot declare compatibility by itself; the API contract diff and fixtures decide.
Each major has an explicit stable routing surface. Concrete path/schema/RPC naming is reserved for F2-020, but the routing mechanism must identify the major before operation dispatch. An unversioned convenience alias may exist only if it resolves to one declared supported major and returns the resolved exact contract release. It cannot silently move across majors.
Multiple majors coexist for a declared support window. Deprecation records identify the last supported contract, announcement time, replacement major, removal condition and machine-readable migration reference. Removing execution support is a release action; old contract metadata and permanent entity IDs remain inspectable.
Release pinning and consistency
Bölüm başlığı “Release pinning and consistency”Before dispatch, an operation resolves and pins one exact api_deployment,
api_contract_release and api_operation_revision, then the deployment’s compatible
code, schema, data and applicable policy releases. The complete tuple is fixed once at
transaction start and used for the entire response. A request may pin a supported
historical deployment or tuple, but independently supplied release IDs are accepted only
when they exactly match a validated deployment compatibility record. Unsupported,
withdrawn, incompatible, forbidden and unavailable tuples remain distinct outcomes;
they never fall forward to current data.
All continuation state binds the exact deployment, API contract/revision, code, schema, data and applicable policy releases plus query shape and authorization subject. Pagination details belong to F2-020, but no continuation may mix releases or reuse a token under another subject/policy. A multi-call frontend flow that needs snapshot consistency carries the returned validated deployment tuple into later calls.
Current/recommended resolution is always an explicit operation or mode. Exact-ID lookup returns the requested historical entity and its lifecycle summary when authorized. It does not silently redirect to a superseding, translated or canonical-repeat target.
Public API allowlist
Bölüm başlığı “Public API allowlist”The public API is the exact public_surface partition of an immutable
exposure_manifest, not every object present in PostgreSQL. The manifest has two
disjoint, separately rooted inventories:
public_surface: PostgREST-exposed contract views/routine revisions, client grants and disclosure-approved OpenAPI/comments; andprivate_dependency: non-exposed backing relations/columns, helper functions, owners, grants and RLS dependencies required to implement that surface.
The manifest root binds both partitions, but only public_surface generates public docs,
OpenAPI, operation discovery and client types. No private dependency name or metadata is
copied into those projections. Together the partitions bind:
- exposed schema/profile and PostgREST configuration identity;
- exact relation/view and routine signatures;
- exact non-exposed backing relations/columns needed by invoker projections;
- operation/contract IDs;
- owners, invoker/definer modes and volatility settings;
- schema, object, column, sequence and routine grants;
- RLS enable/force flags and canonical policy-expression digests;
- public comments/OpenAPI projection and disclosure classification; and
- schema/data/policy compatibility roots.
Objects absent from the manifest are not supported, documented or granted. The PostgREST-exposed schema contains contract views and routines, not storage tables. Concrete internal schema names are deferred to the ER/schema tasks, but core, annotation, curation, provenance, cache and migration storage must remain outside every exposed schema. Supabase/PostgREST schema configuration is hash-bound to the manifest and cannot add another storage schema at runtime.
Invoker views may require narrowly declared USAGE and SELECT on non-exposed backing
schemas/relations so caller RLS is evaluated. Those dependency grants are recorded in the
manifest but do not create REST endpoints because the backing schema is not exposed.
Helper routines, materialized views, caches and migration ledgers remain private.
PostgREST-exposed operations cannot rely on PostgreSQL function overloading. Every allowlisted callable signature resolves unambiguously by name and input shape; adding an overload that makes PostgREST dispatch ambiguous is a contract failure.
The OpenAPI document and generated client schema are projections of the manifest’s
public_surface plus contract source. Comments cannot expose private table/column names
or evidence metadata. Generated drift fails release rather than being patched manually.
Capability and request roles
Bölüm başlığı “Capability and request roles”ADR-021 capability roles remain authoritative. This ADR adds their API use, not new privilege inheritance:
| Principal/capability | Permitted API role |
|---|---|
anon |
Explicit public-release reads/lookup only |
authenticated |
Public reads plus policies for its own user-scoped rows and eligible curation calls |
app_runtime |
Server-side execution of explicitly granted read/lookup operations |
curation_executor |
Owner/executor capability for narrow accepted mutation routines |
auditor |
Restricted read-only audit operations outside public clients |
ci_migrator / prod_migrator |
Versioned schema change only; no application session |
break_glass_owner |
External incident path only; never normal API execution |
provider service_role |
Server/operator infrastructure only; never browser or curation authority |
All project capability roles remain NOLOGIN, NOINHERIT, NOBYPASSRLS and otherwise
restricted as ADR-021 declares. Provider-owned gateway roles are adapter principals, not
permission templates. Their grants are explicit and machine-inventoried.
The Supabase service_role can bypass RLS in provider deployments. It is never embedded
in browser bundles, docs, fixtures, logs, public artifacts or user-controlled workers. A
service-role request does not count as ADR-007 review or curation authority. Server code
does not use it for routine application reads or curation.
Project migrations explicitly revoke service_role schema/table/sequence privileges and
all public or mutating RPC execution, including future default privileges. A separate
provider-adapter allowlist may grant only exact non-domain infrastructure operations that
cannot insert, update, delete, curate or publish corpus/annotation rows. Deployment fails
if the managed provider restores broader project-object grants or prevents their removal;
normative application code policy is not accepted as an ACL control.
Grant baseline
Bölüm başlığı “Grant baseline”Every schema migration starts from denial:
- revoke schema/object privileges and routine execution from
PUBLIC; - set default privileges for every creator/owner to grant nothing implicitly;
- grant schema
USAGEonly to named principals that need allowlisted objects; - grant no table DML or sequence use to
anon,authenticatedorapp_runtime; - grant API-view/backing-relation
SELECTand routineEXECUTEonly by exact manifest identity, dependency and signature; and - prohibit
ALL TABLES,ALL FUNCTIONSand future-object wildcard grants in release migrations.
Client-facing writes occur only through reviewed routines. Sequence privileges and table ownership are never required by clients. Curation and runtime capabilities cannot own storage tables, alter policies, grant roles, create objects or become a migration owner.
A grant is necessary but never sufficient: RLS/policy and operation-level validation must also authorize the row/action. Conversely, RLS does not compensate for an accidentally granted mutating routine or security-definer helper.
RLS baseline
Bölüm başlığı “RLS baseline”Every storage relation reachable from an API operation receives an explicit classification and policy decision. Absence of a policy is deny, not public. Initial classes are:
| Class | Required behavior |
|---|---|
| Published global core | Read only through an accepted release-bound projection |
| Published global annotation | Read only when effective and disclosure-approved |
| User-owned draft/preference | Forced RLS by authenticated subject with USING and WITH CHECK |
| Team/curation work | Forced RLS plus current database-backed membership/authority |
| Private provenance/audit | No anon/authenticated policy; restricted operation only |
| Derived cache/materialization | Never directly exposed; projection inherits every source restriction |
| Migration/control ledger | Operator/migrator only; no runtime operation |
Underlying restricted tables enable and force RLS. Their owners are not runtime/curation
roles, and every executing principal is NOBYPASSRLS. Provider superuser/bypass behavior
is tested separately and never used as proof that ordinary policies work.
Published global projections may use a read policy equivalent to public visibility only
after binding an accepted data release and effective publication state. USING (true) on
a mutable storage table is forbidden. Rejected, pending, retired-private, embargoed or
partially published rows do not become visible because neighboring rows are public.
User/team policies derive subject and membership from a trusted request identity plus
current database state. Critical curation authority is rechecked in the database so stale
JWT role claims cannot override revocation or freeze. Client-supplied actor_id,
tenant_id, owner ID, review role or policy ID is data to validate, never authority.
RLS predicates are stable, bounded and free of caller-controlled dynamic SQL. Recursive policy dependencies, cross-table policy cycles and functions that read the same protected table without a reviewed security boundary are forbidden.
Views and materializations
Bölüm başlığı “Views and materializations”Client-facing views use PostgreSQL security-invoker behavior so underlying grants and RLS apply as the caller. A view owned by a privileged role cannot be used as a definer-style RLS bypass. Security-barrier behavior is enabled where predicate pushdown could reveal restricted values, and expressions/functions used by the projection are reviewed for leakage and side effects.
Materialized views and caches do not enforce source RLS automatically and are therefore private derived storage. They are refreshed from one bound release/policy, carry its visibility partition and are queried only through an invoker projection or secured RPC. Cache misses never fall back to broader unfiltered storage.
A projection cannot mix public and private roots in one JSON object and rely on omitted fields for safety. Its source query and operation contract select only disclosure-approved data before serialization.
Routine execution modes
Bölüm başlığı “Routine execution modes”SECURITY INVOKER is the default. A read RPC uses invoker rights unless it requires a
narrow reviewed capability that cannot be represented safely with invoker views/RLS.
A SECURITY DEFINER routine is allowed only when its contract records:
- one dedicated controlled
NOLOGIN,NOBYPASSRLSowner that is not a storage-table owner and cannot create, grant or change roles; SET search_path = pg_catalog, pg_tempwith every project object fully qualified;- exact input/output types, volatility, parallel-safety and transaction behavior;
- explicit
REVOKE ALL ... FROM PUBLICand exact signature-level execute grants; - no caller-controlled
SET ROLE, search path, identifier, relation, predicate or SQL; - bounded statement/time/resource behavior and fail-closed exception handling; and
- audit/provenance classification for arguments, actor, decision and result.
Dynamic SQL is forbidden in public definer routines unless a later reviewed operation has a finite identifier allowlist, uses identifier-safe formatting, binds all values and demonstrates that no equivalent static SQL exists. Text concatenation of client input into SQL is always forbidden.
Definer routines do not trust a client-provided actor or tenant. A non-public context
helper verifies the trusted authenticator session_user, the gateway-selected request
role and authenticated JWT subject from transaction-local request context before the
definer transition; it accepts no client arguments. Gateway adapter configuration and the
allowed authenticator identity are release-bound.
Custom request GUC/JWT JSON is not sole authority because a direct database session may set ordinary custom settings. Direct capability roles receive no execute grant on public curation routines, and critical authorization always joins current database-backed grants, membership, revocation and freeze state inside the same transaction.
Curation mutation
Bölüm başlığı “Curation mutation”Clients have no direct core or annotation DML. An eligible authenticated curator submits an ADR-007 proposal/review/apply operation through narrow routines. The apply routine:
- derives the authenticated subject and verifies current capability;
- locks the expected curation parent and affected entities;
- verifies frozen proposal/action bytes, approvals, idempotency key and scope;
- rechecks authority revocation, freeze epoch and bound release/policy roots;
- invokes domain validation and performs the complete append-only decision atomically;
- publishes effective state only when every check succeeds; and
- emits restricted audit evidence without returning private diagnostics.
Any mismatch writes no domain/effective row. A retry with the same idempotency key and same action returns the original result; the same key with different bytes fails. The routine cannot accept arbitrary table names, operations or bulk predicates.
Core release publication and migrations remain separate privileged workflows. A curation RPC cannot alter core text, schema, grants, RLS, API contracts or release manifests.
Request identity and anti-enumeration
Bölüm başlığı “Request identity and anti-enumeration”The trusted HTTP gateway authenticates tokens and selects the database request role. The database still verifies that the expected role and subject are present, validates token time/audience/issuer through the platform boundary, and checks mutable authorization in current tables. Anonymous requests have no fabricated subject.
Authorization applies before object resolution details are exposed. A caller cannot use exact-ID, count, pagination, error detail, timing-oriented alternate endpoints or OpenAPI metadata to enumerate private entities. F2-020 defines the concrete error envelope, but forbidden and absent resources must have a policy-controlled indistinguishable public shape while restricted audit retains the true reason.
An operation returning related entities re-applies visibility to every member after resolution. A visible source does not authorize a private supersession target, alignment, repeat, note, provenance record or dictionary decision.
Historical and policy-qualified lookup
Bölüm başlığı “Historical and policy-qualified lookup”Exact-ID lookup, current resolution and reference propagation are separate operations or explicit modes. Each binds the contract, data release and resolution/propagation policy. Set-valued, retired, unavailable, ambiguous and integrity-error results remain explicit.
RLS filtering cannot turn a multi-target result into a false exact singleton. If one required branch is hidden, the public result follows the operation’s fail-closed status and suppresses destinations as defined by the bound policy. Restricted audit may explain the hidden branch without changing the public semantics.
Historical data releases use their historical policy/projection records. A current RLS policy may further restrict access, but cannot broaden historical disclosure or silently substitute newer data.
Deployment and publication
Bölüm başlığı “Deployment and publication”An api_deployment binds exact hashes/roots for:
- API contract and exposure manifest;
- schema object definitions, owners, grants and default privileges;
- RLS flags and policy expressions;
- routine bodies, configuration and signatures;
- OpenAPI/generated contract projection;
- compatible code, schema, data and policy releases;
- role-matrix and contract-test evidence; and
- public disclosure projection plus restricted audit attestation.
Deployment first stages migrations and objects without public visibility. Activation acquires the singleton deployment lane lock and locks the authoritative active-deployment pointer. The request supplies its expected predecessor deployment ID/head. Inside the same compare-and-activate boundary it revalidates that predecessor, current release and curation heads, authority/revocation state, freeze epoch, disclosure policy, signatures, grants, role attributes, RLS/policies, routine owners/configuration, complete compatibility tuple and gateway exposure allowlist.
Only after every comparison succeeds does the transaction issue the deployment record and change the visibility pointer. Schema-cache reload/notification is bound to that exact activation and traffic does not route to the new surface until its receipt verifies. Any mismatch leaves the prior deployment authoritative and publishes no partial surface; a concurrent activation cannot pass against the same predecessor.
Rollback never edits an accepted schema/data/API release in place. Reactivating a prior deployment uses the same lane lock, expected-current compare-and-activate transaction and fresh authority, freeze, disclosure, grant/RLS and compatibility checks; historical prior approval is insufficient. Otherwise recovery issues a forward-fix release. A migration that removed old-major support cannot be called rollback-safe merely because application code was reverted.
Query behavior
Bölüm başlığı “Query behavior”The contract must support operations to:
- discover supported major lines and exact contract releases;
- read one release-bound chapter/core projection without annotations;
- add authorized annotations without making core reconstruction dependent on them;
- inspect an exact historical entity separately from current resolution;
- execute authorized curation proposals/reviews/decisions without direct DML;
- inspect public release/provenance summaries separately from restricted audit; and
- retrieve deployment/contract/data/policy identity needed to reproduce a response.
F2-020 defines operation names, request/response envelopes, pagination, generated types, empty/pending/unavailable representation and performance budgets. It cannot weaken this ADR’s version, grant, RLS, identity or definer-routine boundaries.
Validation Requirements
Bölüm başlığı “Validation Requirements”Implementations must prove at least:
- The exposure manifest’s disjoint public/private partitions equal the visible surface and backing dependency sets; OpenAPI/docs contain only the public partition and extra objects, overloads, grants or comments fail release.
PUBLIC,anon,authenticatedandapp_runtimehave zero unapproved schema, storage-table DML, sequence and routine privileges, including default privileges.- The gateway exposes only the API schema; every backing schema is absent from PostgREST configuration and every reachable relation has explicit owner, grant, RLS enable/force state and policy digest.
- Role-matrix tests run each public operation as anonymous, two unrelated users, an eligible/ineligible curator, runtime, auditor and provider adapter and compare exact row/field visibility.
- Direct SQL attempts cannot forge subject/tenant/actor through parameters, custom GUCs,
JWT JSON,
SET ROLE, search path or function overloading. - Every client-facing view uses invoker semantics and every cache/materialization remains private and release/visibility-bound.
- Definer-routine inspection verifies owner attributes, fixed safe search path, fully qualified objects, exact execute grants, no unsafe dynamic SQL and no storage ownership.
- Curation concurrency fixtures verify frozen bytes, approvals, parent/freeze/revocation, idempotency and all-or-nothing apply under the actual RLS role.
- Private provenance, diagnostics and hidden relation members cannot be inferred through response content, counts, errors, OpenAPI/comments or related-entity traversal.
- Contract snapshots separate logical operations from immutable revisions, prove additive minor behavior, reject incompatible same-major changes and keep supported old majors executable against declared deployment tuples.
- Every response/continuation fixture binds exact deployment, operation revision, code, schema, data and applicable policy; arbitrary combinations and unsupported pins never fall forward.
- Exact-ID, current-resolution, repetition and multilingual propagation fixtures retain ambiguity/set cardinality after visibility filtering and never expose partial targets.
- Service-role fixtures prove zero direct project-table DML, sequence and public/mutating RPC access under current and default privileges; only exact non-domain adapter operations may remain.
- Concurrent activation and rollback fixtures lock the active pointer, reject stale predecessors and recheck authority, freeze, disclosure, grants/RLS, compatibility and generated contracts before atomic visibility change.
- Browser/public artifacts and logs contain no service-role, migration, audit or break-glass credentials; live roles retain ADR-021 non-bypass/non-admin attributes.
- Core and annotation reconstruction hashes remain identical before and after API/RLS migrations, contract deployment, curation calls and rollback/forward-fix exercises.
Consequences
Bölüm başlığı “Consequences”Benefits
Bölüm başlığı “Benefits”- PostgreSQL object drift cannot silently expand the public API.
- Client code can distinguish contract changes from data/policy updates and reproduce a response against an exact release tuple.
- RLS, grants and operation validation provide independent least-privilege layers.
- Public reading stays simple while private drafts, curation and provenance retain separate authority.
- Historical IDs and old supported majors remain explicit instead of being redirected by current recommendations.
- Supabase/PostgREST remains usable without treating service-role bypass as application authorization.
- Every migration must maintain object, grant, owner, RLS and exposure inventories.
- Old major lines may require compatibility views/routines during their support window.
- Role-matrix and anti-enumeration tests are broader than ordinary endpoint tests.
- Definer routines require dedicated ownership, review and exact signature grants.
- Release-pinned continuations and multi-call flows carry more explicit metadata.
Alternatives Considered
Bölüm başlığı “Alternatives Considered”Expose public-schema tables and rely on RLS alone
Bölüm başlığı “Expose public-schema tables and rely on RLS alone”RLS cannot define stable JSON contracts, prevent accidental function grants or hide storage churn. An explicit operation allowlist is required.
Put authorization only in Next.js/server code
Bölüm başlığı “Put authorization only in Next.js/server code”PostgREST and direct server paths could bypass that filter, and a missed query predicate would disclose rows. Database grants and RLS remain authoritative.
Use service role for every server request
Bölüm başlığı “Use service role for every server request”This bypasses RLS and turns every application bug into unrestricted database access. It is reserved for narrow infrastructure adapters and never constitutes curation authority.
Version by code release or database migration number
Bölüm başlığı “Version by code release or database migration number”Neither identifies public semantics. Internal changes would create noise while policy or data semantic changes could remain invisible. Independent contract identity is required.
Replace old API behavior in place
Bölüm başlığı “Replace old API behavior in place”Existing clients and permanent references would silently change meaning. Incompatible behavior receives a new major and support-window record.
Trust JWT role/tenant claims for all decisions
Bölüm başlığı “Trust JWT role/tenant claims for all decisions”Claims can be stale and custom request settings are not sufficient authority for direct database sessions. Critical membership, revocation and freeze state is rechecked in the database.
Make every RPC security definer
Bölüm başlığı “Make every RPC security definer”This needlessly widens impact and can bypass caller RLS. Invoker is default; definer use is narrow, owned and explicitly justified.
Deferred Decisions
Bölüm başlığı “Deferred Decisions”- F2-011 through F2-014 define concrete tables, schemas, entity catalog and permanence.
- F2-017/F2-018 define migration/release signing and complete compatibility/approval rules.
- F2-019 defines shared provenance/curation physical contracts.
- F2-020 defines API/RPC naming, concrete version routing, pagination, error/state envelopes, generated clients and query budgets.
- F3/F4 implement storage, grants, RLS, views, routines and contract inventory.
- F8 implements web/API clients and browser E2E role/continuation behavior.
- F9 certifies reference targets and closes any domain-specific direct-DML/RLS gaps.
- Production provider adapters define secret brokering and gateway-specific claim verification without weakening this contract.
Revisit Conditions
Bölüm başlığı “Revisit Conditions”Revisit this ADR if:
- managed Supabase cannot expose an allowlisted major surface without granting storage objects or bypassing declared RLS;
- a valid client workflow requires direct DML that cannot be expressed as a narrow reviewed operation;
- PostgreSQL invoker/definer or FORCE RLS behavior changes materially in the supported database version;
- historical contract/data/policy pinning cannot be implemented without silent fallback; or
- a provider forces a bypass credential into ordinary browser/runtime requests.