Three walls, three retrievers

The design is short to describe and hard to shortcut. One ChromaDB collection per role, named finance_docs, engineering_docs, admin_docs. Every query carries a role. The retrieval function picks the matching collection and runs similarity search inside it. No document outside that collection is ever a candidate for the top-k result.

The full pipeline

Login mints a session and a role. Every query carries the role down to a role-scoped retrieval against ChromaDB. Results and role fuse into a role-aware prompt for OpenRouter.

Role travels with the request all the way to the vector store. The role-scoped collection is the wall.
vector_store.py
python
def search_documents(self, role: str, query: str, top_k: int = 3) -> list[dict]:
    if role not in ROLES:
        return []
    results = self.collections[role].query(
        query_texts=[query],
        n_results=top_k,
    )
    # ...format and return

The signature is the design. Role is a required parameter, the role selects the collection, and nothing else can be queried. You cannot accidentally skip the wall because there is no no-role code path.

Quiz: Quiz

Loading practice…

Each module in this course picks one box in that pipeline and goes deep. Auth, retrieval, role-aware prompt, rate limiter, admin flow. By the end you will have touched every layer and you will know what each one is actually for.