CHULIYING
Travel agency CRM architecture
A side project I designed and built solo for my family's travel agency, in production on its customers, tours, and surveys, with an AI assistant on top. The public demo uses synthetic data. The design separates identity from access, application permissions from database scope, and factual computation from language generation.
01Separate identity from access
Google verifies the account; database membership decides the tenant, role, and capabilities. Organizational access stays under the CRM's control, not the identity provider's.
02Authorize before reading
Every page and API checks the required capability on the server before customer data loads. A direct API call meets the same check as page navigation, and a denied request stops before any customer-data queries run.
03Match the method to the data
Deterministic queries take priority wherever they are sufficient, so retrieval and model usage stay proportional to the question.
Structured facts & aggregates
Counts, dates, statuses, and grouped results come from parameterized SQL.
Text evidence
Full-text and vector retrieval find approved, traceable summaries and comments.
04Enforce scope in the database
Application checks decide which actions are allowed; PostgreSQL row-level security limits the tenant and role scope of records and retrieval evidence. Queries that omit tenant filters still cannot cross the boundary.
05Establish facts before phrasing
One rule holds on every answer path: numbers come only from approved queries and text claims only from cited evidence. A model may rephrase a deterministic answer or call those queries as tools; output that breaks the rule falls back to the deterministic answer.
06Make decisions reviewable
Access decisions, citations, model usage, and user feedback are recorded, so authorized reviewers can trace who accessed which data, which evidence an answer used, and whether the model added value.