A search that finds a document the user cannot access has already failed, even if the interface hides the final link. In document systems, case files, back-office systems, and knowledge bases, the risk appears earlier: in the index, retrieved chunks, displayed metadata, and a response generated from unauthorized context.
Permission-aware semantic search in PHP must treat authorization as part of retrieval, not as a decorative check in the view. The goal is not merely to return useful results: it is to ensure that every candidate chunk, citation, and response is derived exclusively from content that the authenticated principal can access at that moment.
Decisions that must be settled before indexing

Start by defining the corpus and its access model. Not all content has the same lifecycle or sensitivity: a public policy, an internal manual, a case file, and an externally shared file require different rules. You must also decide which action search enables: finding a title, reading an excerpt, opening the document, downloading an attachment, or requesting a summary. Having discovery permission does not necessarily imply read permission.
- Principal: user, service account, or delegated session performing the query.
- Scope: organization, workspace, project, case file, or repository where they can search.
- Action: discover, read, download, or administer.
- Resource: document and chunk, with their status, classification, and membership.
- Error tolerance: authorization must prioritize non-disclosure; a false negative is inconvenient, while a false positive can be a breach.
Vector similarity does not understand business rules. An embedding represents semantic proximity, not access legitimacy. Therefore, the design cannot trust that a “similar” result is safe or that a generative model will ignore improper context.
Reference architecture and source of truth
Keep permissions in a transactional source of truth: the PHP application, its database, or the document system that governs the resources. The index is a rebuildable projection, not the authority that decides access. If the index becomes corrupted, delayed, or receives incomplete data, the authorization layer must be able to prevent delivery.
A robust flow separates four stages:
- Content is extracted from an identifiable version of the document and split into chunks with coherent boundaries.
- Retrieval representations are computed and stored along with scope and version metadata.
- The query constructs a filter derived from the principal's authorization and retrieves candidates only within that scope.
- The application checks permission and validity again for each candidate before displaying it or using it as context.
In PHP, encapsulate these responsibilities. A policy service must resolve can($principal, 'read', $document); an index adapter must receive filters derived from that decision; and the result assembler must accept only verified candidates. Avoid having controllers, templates, or prompts compose permission filters on their own.
Metadata that enables filtering without guessing
Every document and chunk needs a stable organization and resource identifier, a content version, indexing status, and a reference to the parent document. Add the attributes needed to express the policy, but do not replicate sensitive data unnecessarily.
- tenant_id or organization: mandatory barrier in multitenant environments.
- document_id and chunk_id: traceability from the result back to the source.
- acl_revision: version of the policy applied during indexing.
- audience: simple scope such as internal public, team, project, or case file.
- lifecycle_state: active, archived, deleted, or pending review.
- content_revision: prevents citing a version that has already been replaced.
Do not index a massive list of users per chunk if the policy is based on changing groups: it increases cost, exposes relationships, and ages poorly. It is preferable to filter by stable scopes where possible and resolve exceptions in post-verification. If the retrieval engine does not support reliable filters, it must not receive content from multiple security scopes in the same searchable space.
Filter before retrieval and verify afterward
Pre-filtering reduces the exposure surface: the semantic query must include organization, active status, and permitted scopes before calculating the final candidates. This prevents forbidden text from influencing ranking, excerpts, or the context of an assisted response.
Post-verification remains necessary. Permissions can change between the query and reading, inheritance may depend on data that was not projected, or the index may be delayed. For each candidate, retrieve the current document or consult an authorization cache with safe invalidation. If the check fails, discard the chunk without revealing its title, score, or existence.
When assisted generation is involved, provide the model only with chunks that have already been authorized and verified. Define a specific use case, such as summarizing retrieved results; evaluate responses with permitted and prohibited cases; retain verifiable citations; limit the cost per query; and maintain a non-generative alternative, such as a results list. A model does not replace the access policy or human oversight of sensitive content.
Inheritance, links, and revocations that break simple designs
Groups, inherited folders, and shared links introduce indirect changes. A person leaving a group, a document changing folders, or a link expiring must affect both opening and retrieval. Explicitly model precedence among direct permissions, inheritance, and denials, and test conflicts.
Revocations require a stricter strategy than grants. Publish content and ACL change events through a transactional queue or change log; a worker recalculates metadata and deletes or reindexes chunks. While the index converges, post-verification protects delivery. For deletions, mark the resource as unavailable immediately in the source of truth and purge its chunks asynchronously, with alerts if the delay exceeds the operational target.
Verifiable results, testing, and observability
Show title, limited excerpt, location, and date only if those fields are also readable. Every result must lead to the original authorized resource; a citation must not reveal a path, author, or text from a hidden document. When there are no results, use a neutral message: do not confirm whether content exists outside the user's scope.
Build a test matrix with users from different organizations, group members and non-members, limited administrators, expired links, and resources revoked during a session. Test direct queries, synonyms, rare terms, and questions designed to attract forbidden content. Expected results include empty lists when everything relevant is prohibited.
Record, without storing unnecessary sensitive queries, the index version, applied filters, number of candidates before and after verification, latency, denials, and synchronization delay. An increase in post-verification discards may indicate outdated ACLs; zero results after a migration may signal overly restrictive filters; cross-organization queries are an isolation alert.
When to choose another solution and exit checklist

Semantic search is not always worth it. For small catalogs and stable vocabulary, filters, text search, and hierarchical navigation are more explainable and cheaper. They are also preferable when permissions are highly dynamic and the engine cannot filter by attributes safely. Use semantic retrieval when it provides real value for queries formulated in natural language and full access control can be sustained.
- The source of truth decides access, and the index can be rebuilt.
- All chunks have organization, document, version, and status.
- The query filters before retrieval and verifies before delivery.
- Grants, changes, revocations, and deletions have observable synchronization.
- Assisted responses use only authorized context, citations, and a non-AI alternative.
- Tests include deliberate attempts at improper access and empty results.



