Arag / ARCHITECTURE.md
AuthorBot
feat: proper visitor analytics system - New Visitor model (visitor_uid + fingerprint fallback, first_seen/last_seen/page_views, geo, device) - VisitorRepository with upsert + analytics queries - visitor_tracker.py: record_visitor() upserts on every session/init - session/init accepts visitor_uid in request body (HF-Spaces iframe-safe, no cookies) - 4 new analytics endpoints: /visitors /geo /devices /sessions/stats - geo.py: region extraction + X-Real-IP support - DB migration: visitor_uid column on chat_sessions - ARCHITECTURE.md updated
3ae7860
|
Raw
History Blame Contribute Delete
28.6 kB

Author RAG β€” Architecture Reference


πŸ€– AI AGENT MANDATORY PROTOCOL

THIS BLOCK IS FOR AI AGENTS (including Antigravity / Gemini). FOLLOW ON EVERY PROMPT.

On EVERY new request you must:

  1. READ this file first before reading any source file or writing any code.
  2. CHECK Β§9 Invariants β€” verify your planned change does not violate any rule.
  3. CHECK Β§8 Where to Add Features β€” confirm you are editing the correct file for the task.
  4. After completing any change that adds a file, route, model column, config value, or service β€” UPDATE this document to reflect the new state.
  5. Push the updated ARCHITECTURE.md in the same commit as the code change. They must never go out of sync.

What counts as a required update:

Change made Section to update
New file created Β§4 Full File Tree
New route added Β§4 (correct sub-section)
New DB column added Β§4 Models table + Β§8
New config value added Β§7 Configuration
New invariant established Β§9 Invariants
New feature area added Β§8 Where to Add Features
Architecture restructured Β§3 Layer diagram + Β§4

NEVER do this:

  • Edit source files without checking Β§9 first.
  • Add a new file without adding it to Β§4.
  • Define a new guard/detector outside guards.py.
  • Add prompt text outside prompter.py.
  • Skip updating this document after a structural change.

Purpose: This document is the single source of truth for any AI agent or human developer joining this codebase. Read this file first before opening any source file. It answers: What does each file do? How does a request flow? Where do I add X?


1. What This System Does

Author RAG is a multi-tenant SaaS platform. Each customer (an author) gets an AI-powered chatbot that lives on their website and answers questions about their books. The chatbot is a persuasive sales tool β€” it understands reader intent, retrieves precise passages from the book, and surfaces purchase links at the right moment.

Key numbers:

  • Runtime: Python 3.11, FastAPI async
  • Database: SQLite (dev) / PostgreSQL (prod) via SQLAlchemy async
  • Vector store: ChromaDB (local persistent)
  • LLM: OpenAI GPT-4o-mini (configurable)
  • Embeddings: text-embedding-3-small

2. Top-Level Directory Layout

Author RAG/
β”œβ”€β”€ app/                    ← All application code (see Β§4)
β”œβ”€β”€ static/                 ← Compiled frontend (admin SPA, widget JS)
β”œβ”€β”€ requirements.txt        ← Python dependencies
β”œβ”€β”€ Dockerfile              ← HuggingFace Spaces deployment
β”œβ”€β”€ ARCHITECTURE.md         ← THIS FILE
└── .env                    ← Secrets (never committed)

3. Layer Architecture

The codebase follows a strict 5-layer architecture. Data only flows downward. A layer may never import from a layer above it.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Layer 1 β€” API / Routers                            β”‚
β”‚  app/api/, app/admin/routers/, app/superadmin/      β”‚
β”‚  β€’ Accepts HTTP requests                            β”‚
β”‚  β€’ Validates input (Pydantic schemas)               β”‚
β”‚  β€’ Delegates to services β€” no business logic here   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Layer 2 β€” Services / Pipeline                      β”‚
β”‚  app/services/                                      β”‚
β”‚  β€’ All business logic lives here                    β”‚
β”‚  β€’ The RAG pipeline is the core of this layer       β”‚
β”‚  β€’ May call repositories and other services         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Layer 3 β€” Repositories                             β”‚
β”‚  app/repositories/                                  β”‚
β”‚  β€’ All database queries live here                   β”‚
β”‚  β€’ Returns model objects β€” never raw SQL            β”‚
β”‚  β€’ No business logic                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Layer 4 β€” Models                                   β”‚
β”‚  app/models/                                        β”‚
β”‚  β€’ SQLAlchemy ORM table definitions only            β”‚
β”‚  β€’ No methods with logic                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Layer 5 β€” Core / Infrastructure                    β”‚
β”‚  app/core/, app/config.py, app/dependencies.py      β”‚
β”‚  β€’ DB engine, Redis, ChromaDB clients               β”‚
β”‚  β€’ JWT / token crypto                               β”‚
β”‚  β€’ No domain logic                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

4. Full File Tree with Descriptions

app/ β€” Root

File Role
main.py FastAPI app factory. Registers middleware, exception handlers, routers. Startup delegates to core/startup/.
config.py All env-var settings via Pydantic BaseSettings. One source of truth for every config value.
dependencies.py FastAPI Depends() providers: DB session, Redis, auth guards (get_current_author_scoped, get_subscription_author, get_current_superadmin).

app/core/ β€” Infrastructure

File Role
core/startup/db.py init_db() β€” creates all tables + runs incremental ALTER TABLE migrations on startup.
core/startup/seeder.py seed_superadmin() β€” bootstraps the superadmin account from env vars on first run.
core/access/token_crypto.py Creates and verifies signed subscription tokens (widget embed).
core/access/subscription.py Subscription validation logic (expiry, budget, revocation).
core/access/jwt_blacklist.py Redis-backed JWT revocation list.
core/access/totp.py TOTP 2FA for SuperAdmin login.
core/chroma_client.py Singleton ChromaDB client.
core/security.py hash_password(), verify_password().

app/api/ β€” Public Widget API

These routes are called by the embedded widget on the author's website. All require X-Subscription-Token header (validated via get_subscription_author).

File Routes Role
api/chat.py POST /api/chat/{slug} Main chat endpoint β€” calls run_pipeline().
POST /api/chat/{slug}/session/init Creates a new visitor session.
GET /api/chat/{slug}/session/history/{id} Returns chat history.
POST /api/chat/{slug}/session/farewell Graceful session close + summarization.
POST /api/chat/{slug}/session/rate Star rating.
POST /api/chat/{slug}/track-click Records buy-link click.
POST /api/chat/{slug}/feedback πŸ‘/πŸ‘Ž message feedback.
GET /api/chat/{slug}/events SSE stream for ingestion progress.
api/ingest.py POST /api/admin/{slug}/books/upload Book PDF upload + async embedding pipeline.
api/widget.py POST /api/widget/token Returns a signed subscription token for the embed script.
api/schemas_router.py /api/auth/* Login, register, token refresh.

app/admin/ β€” Author Admin API

Prefix: /api/admin/{author_slug}/ Auth: Bearer JWT (get_current_author_scoped)

File Routes Role
admin/router.py β€” 20-line aggregator. Mounts all 7 sub-routers.
admin/routers/dashboard.py /sessions, /sessions/search, /sessions/{id}/transcript, /sessions/{id}/block, /sessions/{id}/messages/{mid}/annotate Session management and message review.
admin/routers/books.py /books, /books/{id}, /books/{id}/cover Book list, delete, cover upload.
admin/routers/analytics.py /analytics, /analytics/funnel, /analytics/intents, /analytics/visitors, /analytics/geo, /analytics/devices, /analytics/sessions/stats Dashboard charts, funnel data, visitor analytics.
admin/routers/settings.py /password, /widget-config, /profile, /personality, /notifications, /embed-token, /token-usage All author account settings.
admin/routers/links.py /smart-links/{book_id} Buy/preview URL management.
admin/routers/qa.py /qa, /qa/import, /qa/export, /qa/{id} Custom Q&A training data (CRUD + CSV).
admin/routers/exports.py /export/sessions, /export/analytics, /export/conversations CSV data exports.

app/superadmin/ β€” SuperAdmin API

Prefix: /api/super/ Auth: Bearer JWT + TOTP (get_current_superadmin)

File Routes Role
superadmin/router.py β€” 15-line aggregator. Mounts 3 sub-routers.
superadmin/routers/platform.py /, /diag, /health, /audit, /announce, /backup Platform diagnostics, audit log, announcements.
superadmin/routers/authors.py /authors, /authors/{id}, /authors/{id}/suspend, /authors/{id}/grant, /authors/{id}/embed-token Full author account lifecycle.
superadmin/routers/grants.py /grants, /grants/{id}/revoke, /grants/{id}/bonus-tokens, /grants/{id}/extend, /grants/{id}/reset-tokens, /grant Subscription token budget management.
superadmin/routers/_utils.py β€” Shared _err() error handler (no routes).

app/services/pipeline/ β€” The RAG Pipeline ⭐

This is the core of the product. Every visitor message flows through run_pipeline().

app/services/pipeline/
β”œβ”€β”€ __init__.py       ← Public API: run_pipeline, PipelineResult, invalidate_book_cache
β”œβ”€β”€ core.py           ← 12-step orchestrator (the conductor, ~200 lines)
β”œβ”€β”€ generation.py     ← Steps 8–10: LLM call + faithfulness retry + safety scrub
β”œβ”€β”€ handlers.py       ← Short-circuit response functions (greeting, catalog, piracy...)
β”œβ”€β”€ helpers.py        ← Pure stateless utilities (call_llm, format_history, get_book_links...)
β”œβ”€β”€ guards.py         ← Boolean detectors (is_greeting, is_full_story_request, ...) β€” SINGLE SOURCE OF TRUTH
β”œβ”€β”€ cache.py          ← LRU answer cache (256 slots, MD5 key)
└── dedup.py          ← Chunk deduplication by Jaccard overlap

The 12-Step Pipeline (core.py)

Step 0   sanitize_user_input()         Strip dangerous/empty input
Step 1   check_boundary()              Jailbreak / piracy / off-topic guard
Step 1.5 check_custom_qa()            Short-circuit: exact Q&A match (no LLM)
Step 2   classify_intent()            3-tier: rules β†’ cache β†’ LLM-as-fallback
Step 3   Book resolution              Greeting / catalog / book-select short-circuits
         LRU cache lookup             Skip steps 4-12 on cache hit
Step 4   rewrite_query()              Generate 3 query variations for multi-pass retrieval
Step 5   retrieve_chunks()            ChromaDB vector search (top_k=15 default)
Step 6   rerank_chunks()              Cross-encoder re-ranking (top_n=5 default)
Step 6.5 deduplicate_chunks()         Remove near-duplicate overlapping windows
Step 7   build_context()              Token-aware context assembly (max 2000 tokens)
Step 8   MASTER_SYSTEM_PROMPT.format  Assemble full prompt with history + interest + context
         call_llm()                   OpenAI chat completions
Step 9   check_faithfulness()         NLI guardrail β€” retry with stricter prompt if hallucinating
Step 10  scrub_unsafe_response()      Output safety scrub + is_response_safe() check
Step 11  UpsellEngine.select_strategy() Choose upsell strategy based on intent + session state
Step 12  ResponseFormatter.format()   Assemble final JSON response with optional buy button
         cache_set()                  Store result for future identical questions

Where to look for what:

Task File
Change the LLM model or temperature config.py β†’ OPENAI_CHAT_MODEL, RAG_TEMPERATURE
Edit the system prompt services/prompter.py
Change what counts as a greeting services/pipeline/guards.py β†’ _GREETINGS
Change upsell logic services/upsell_engine.py
Change faithfulness threshold services/faithfulness.py
Change how queries are rewritten services/rewriter.py
Change intent labels / rules services/intent.py
Change chunking strategy services/chunker.py
Change re-ranking services/reranker.py
Change context token limit config.py β†’ RAG_CONTEXT_MAX_TOKENS

app/services/ β€” All Other Services

File Role
rag_pipeline.py Compatibility shim only. Imports from pipeline/ and re-exports.
intent.py 3-tier intent classifier: keyword rules β†’ session cache β†’ LLM fallback.
rewriter.py Query rewriter β€” generates 3 variations using conversation context.
guardrails.py Input sanitization, boundary checks, output safety, response scrubbing.
prompter.py All prompt templates: MASTER_SYSTEM_PROMPT, boundary responses, upsell hooks.
faithfulness.py NLI-based faithfulness scoring against retrieved context.
formatter.py ResponseFormatter β€” assembles the final JSON {text, links, has_links} dict.
upsell_engine.py UpsellEngine β€” selects upsell strategy, decides if link should show.
context_builder.py Token-aware context string builder from ranked chunks.
vector_store.py ChromaDB retrieval β€” multi-query search + score filtering.
reranker.py Cross-encoder re-ranking of retrieved chunks.
embeddings.py Generates and stores OpenAI embeddings into ChromaDB.
chunker.py Splits book text into overlapping sliding-window chunks.
parser.py Extracts clean text from PDF uploads.
auth_service.py Register, login, token refresh logic.
superadmin_service.py Business logic for author lifecycle (suspend, delete, grant).
token_budget.py Token usage tracking and budget enforcement.
email_service.py Transactional email sending.
rate_limiter.py Per-IP / per-author rate limiting.
file_validator.py PDF upload validation (size, MIME type, header).
session_store.py Redis-backed session state persistence.
summarizer.py End-of-session conversation summarizer.
notifications.py In-app notification helpers.
analytics.py Analytics event recording facade.

services/analytics_core/

| File | Role | |------||------| | tracker.py | Records AnalyticsEvent rows after each chat turn. | | aggregator.py | Pre-aggregates daily analytics for dashboard charts. | | geo.py | IP β†’ country/region/city lookup (MaxMind GeoLite2). Exposes get_real_ip() (proxy-aware). | | visitor_tracker.py | record_visitor() β€” upserts Visitor table on every session/init. Deduplicates via localStorage UUID then fingerprint fallback. |

services/session_core/

File Role
manager.py SessionManager + SessionContext β€” the session state object passed through the pipeline.
context.py Interest score and tag tracking across turns.
fingerprint.py Visitor fingerprint generation (SHA-256, no PII).

app/models/ β€” Database Tables

File Table Key columns
user.py users id, email, role (author/superadmin), bot_name, chatbot_is_active
book.py books id, author_id, title, status, chroma_collection_id, chunk_count, buy_url
chat_session.py chat_sessions, chat_messages Session: visitor_fingerprint, visitor_uid, turn_count, rating, blocked. Message: role, intent, faithfulness_score, hallucination_detected
client_access.py client_access author_id, plan, token_budget, tokens_used, expires_at, is_revoked
custom_qa.py custom_qa author_id, question, answer, match_threshold, priority, match_count
analytics.py analytics_events author_id, session_id, intent, link_clicked, prompt_tokens, response_ms
link.py links author_id, book_id, purchase_url, preview_url
document.py documents book_id, filename, status, pages
visitor.py visitors author_id, visitor_uid (UUID, unique per author), fingerprint, first_seen, last_seen, page_views, country_code, region, city, device_type, browser, os

app/repositories/ β€” Database Access Layer

| File | Role | |------||------| | base.py | BaseRepository β€” shared get_by_id, save, delete methods. | | user_repo.py | UserRepository β€” lookup by email/slug, list all authors. | | book_repo.py | BookRepository β€” list_active_for_author(), list_for_author(). | | access_repo.py | AccessRepository β€” get_active_for_author() β€” used everywhere for budget checks. | | link_repo.py | LinkRepository β€” get_for_book(), upsert_for_book(). | | audit_repo.py | AuditRepository β€” append-only log(), list_recent(). | | document_repo.py | DocumentRepository β€” book document tracking. | | visitor_repo.py | VisitorRepository β€” get_by_uid(), get_by_fingerprint(), create(), touch(), distribution queries for analytics. |


app/schemas/ β€” Pydantic Request/Response Schemas

File Role
chatbot.py ChatRequest, ChatResponse, SessionInitResponse, FarewellRequest
admin.py AnnotateRequest, FlagRequest, PasswordChangeRequest, ProfileUpdate, WidgetConfigUpdate
superadmin.py CreateAuthorRequest, GrantAccessRequest, RevokeAccessRequest, AddBonusTokensRequest
auth.py LoginRequest, RegisterRequest, TokenResponse

app/middleware/ β€” Request Middleware

File Role
logging_middleware.py Structured request/response logging with structlog.
rate_limit_middleware.py Sliding-window rate limiting (configurable per route type).
security_headers.py CSP, HSTS, X-Frame-Options headers.
metrics.py Prometheus metrics collection (optional).

app/tasks/ β€” Background Tasks

File Role
ingestion_task.py Async book processing: parse β†’ chunk β†’ embed β†’ store in ChromaDB.
analytics_task.py Periodic analytics aggregation.
email_task.py Queued email sending.
backup_task.py SQLite + ChromaDB backup.
expiry_check_task.py Subscription expiry warnings.
geo_update_task.py Retroactive geo enrichment for sessions.
link_health_task.py Checks buy links for 404s.
celery_app.py Celery app instance (optional β€” tasks can run inline).

5. A Complete Request Trace

Scenario: A reader on an author's website asks "Is the ending happy?"

Browser (widget JS)
  β”‚  POST /api/chat/{author_slug}
  β”‚  Headers: X-Subscription-Token: <signed JWT>
  β”‚  Body: { "message": "Is the ending happy?", "session_id": "..." }
  β–Ό
app/api/chat.py β†’ chat()
  β”‚  1. get_subscription_author()      Verify token, check budget, load author
  β”‚  2. SessionManager.load()          Load session from Redis (history, book selection)
  β”‚  3. run_pipeline(query, author, session_context, db)
  β–Ό
app/services/pipeline/core.py β†’ run_pipeline()
  β”‚  Step 0:  sanitize_user_input()       β†’ "Is the ending happy?"
  β”‚  Step 1:  check_boundary()            β†’ no violation
  β”‚  Step 1.5: check_custom_qa()          β†’ no match
  β”‚  Step 2:  classify_intent()           β†’ intent="question", confidence=0.92
  β”‚  Step 3:  BookRepository.list_active_for_author()  β†’ [Book("The Last Signal")]
  β”‚           is_greeting()              β†’ False
  β”‚           is_catalog_question()      β†’ False
  β”‚           LRU cache lookup           β†’ miss
  β”‚  Step 4:  rewrite_query()            β†’ ["Is the ending happy?", "How does it end?", "resolution of the story"]
  β”‚  Step 5:  retrieve_chunks()          β†’ 15 chunks from ChromaDB
  β”‚  Step 6:  rerank_chunks()            β†’ top 5 chunks scored by cross-encoder
  β”‚  Step 6.5: deduplicate_chunks()      β†’ 4 unique chunks
  β”‚  Step 7:  build_context()            β†’ 1,840 tokens of context
  β–Ό
app/services/pipeline/generation.py β†’ generate_response()
  β”‚  Step 8:  MASTER_SYSTEM_PROMPT.format(...)
  β”‚           call_llm()                 β†’ "Without giving anything away, I can say..."
  β”‚  Step 9:  check_faithfulness()       β†’ faithful=True, score=0.91
  β”‚  Step 10: is_response_safe()         β†’ True
  β”‚           return (response, 0.91, False, 312, 87)
  β–Ό
core.py (continues)
  β”‚  Step 11: UpsellEngine.select_strategy()   β†’ "SOFT_MENTION"
  β”‚           should_include_link()            β†’ True (turn 4, high interest)
  β”‚           get_book_links()                 β†’ purchase_url="https://amazon.com/..."
  β”‚  Step 12: ResponseFormatter.format()       β†’ {text, links:[{label:"Get the book", url:...}], has_links:True}
  β”‚           cache_set()                      β†’ stored for next identical query
  β–Ό
app/api/chat.py (continues)
  β”‚  SessionManager.save()             Update session: turn_count++, history appended
  β”‚  analytics.record_event()          Log intent, tokens, latency, link_shown
  β”‚  token_budget.deduct()             Deduct prompt+completion tokens from grant
  β–Ό
HTTP 200 { "message": "Without giving anything away...", "links": [...] }
  β–Ό
Browser (widget JS)
  Renders response + "Get the book" button

6. Authentication Model

Three distinct auth tiers with separate dependencies:

Tier 1: Visitor (Widget)
  β†’ Header: X-Subscription-Token (signed JWT, no login needed)
  β†’ Dependency: get_subscription_author()
  β†’ Checks: token signature, expiry, token budget, author active

Tier 2: Author (Admin)
  β†’ Header: Authorization: Bearer <JWT>
  β†’ Dependency: get_current_author_scoped()
  β†’ Checks: JWT validity, author role, slug matches token

Tier 3: SuperAdmin
  β†’ Header: Authorization: Bearer <JWT>
  β†’ Dependency: get_current_superadmin()
  β†’ Checks: JWT validity, superadmin role, TOTP verified

7. Key Configuration Values

All in app/config.py (loaded from .env):

Variable Default Effect
OPENAI_CHAT_MODEL gpt-4o-mini LLM used for response generation
OPENAI_EMBED_MODEL text-embedding-3-small Embedding model
RAG_RETRIEVAL_TOP_K 15 Chunks fetched from ChromaDB
RAG_RERANK_TOP_N 5 Chunks kept after re-ranking
RAG_RERANK_MIN_SCORE 0.3 Min cross-encoder score to keep
RAG_CONTEXT_MAX_TOKENS 2000 Max tokens in assembled context
RAG_MAX_RESPONSE_TOKENS 300 Max tokens in LLM response
RAG_TEMPERATURE 0.4 LLM temperature
RAG_BOOK_CONFIDENCE_THRESHOLD 0.7 Min score to route to a specific book
SUPERADMIN_EMAIL β€” Seeded on first startup
SUPERADMIN_PASSWORD β€” Seeded on first startup

8. Where to Add New Features

Task Where to add it Notes
New author admin route app/admin/routers/<closest>.py Or create a new file + mount in admin/router.py
New superadmin route `app/superadmin/routers/<platform authors
New intent label app/services/intent.py β†’ _RULE_MAP Add keyword rules first; LLM only as fallback
New guard/detector app/services/pipeline/guards.py Never define is_greeting elsewhere
New short-circuit response app/services/pipeline/handlers.py Must return PipelineResult
New prompt template app/services/prompter.py Keep ALL prompt text in one file
New DB column app/models/<model>.py + app/core/startup/db.py β†’ _NEW_COLUMNS No Alembic needed
New background task app/tasks/<name>_task.py Register in tasks/celery_app.py if async
New config value app/config.py Always typed, always has a default

9. Invariants β€” Rules That Must Never Be Broken

  1. Services never import from routers. Data flows down only.
  2. guards.py is the single source of truth for all boolean detectors. Never re-define is_greeting() elsewhere.
  3. All prompt text lives in prompter.py. No inline f-strings with user-facing text in other files.
  4. All pipeline results return PipelineResult. Never return a raw dict from run_pipeline().
  5. Repositories never contain business logic. If it's a decision, it belongs in a service.
  6. Never skip a pipeline step. Steps 0–12 run for every message; short-circuits return early from core.py, not by skipping steps.
  7. Cache only cacheable intents. purchase_intent, complaint, greeting are never cached (time/person-sensitive).
  8. Token usage must always be recorded. Every LLM call goes through call_llm() in helpers.py which returns token counts.
  9. All new DB columns go into core/startup/db.py β†’ _NEW_COLUMNS. This keeps migrations consistent across environments.
  10. All exceptions have typed exception classes in app/exceptions/. Never raise HTTPException directly in service layer.
  11. This document must be updated on every structural change. See Β§AI AGENT MANDATORY PROTOCOL above.

10. Change Log

AI agents: append an entry here after every significant change. Format: YYYY-MM-DD | What changed | Files affected.

Date Change Files Affected
2026-06-19 Initial project build β€” auth, chat API, admin panel, ingestion pipeline All
2026-06-22 Intelligence overhaul β€” Python-first intent classifier, hybrid rewriter, LRU cache, chunk dedup, natural upsell intent.py, rewriter.py, upsell_engine.py, rag_pipeline.py
2026-06-23 Modularity refactor Phase 1 β€” admin/router.py split into 7 sub-routers, rag_pipeline.py split into pipeline/ package admin/router.py, admin/routers/*, services/pipeline/*, services/rag_pipeline.py
2026-06-23 Modularity refactor Phase 2 β€” superadmin/router.py split into 3 sub-routers, main.py startup extracted to core/startup/, pipeline/core.py generation extracted to pipeline/generation.py superadmin/router.py, superadmin/routers/*, core/startup/*, services/pipeline/generation.py, main.py
2026-06-23 Added ARCHITECTURE.md with AI Agent Mandatory Protocol ARCHITECTURE.md
2026-06-23 Production Improvements Phases 1–5: 8 bugs fixed, 7 features added. B1 fingerprint null crash, B2 silent truncation, B3 OpenAI client per-call, B4 no LLM retry, B5 piracyβ†’jailbreak wrong intent, B6 history only 3 turns, B8 no budget warning, B9 sync ChromaDB in async loop. New: per-visitor rate limit, input cap, tenacity retry, intent rule expansion (+30% coverage), history fix, budget email warning, async health check. config.py, middleware/rate_limit_middleware.py, api/chat.py, services/pipeline/core.py, services/pipeline/helpers.py, services/intent.py, dependencies.py, services/token_budget.py, requirements.txt
2026-06-23 Visitor Analytics System: Replaced session-based visitor counting with proper deduplication. New Visitor model (one row per browser per author), VisitorRepository, visitor_tracker.py service. session/init now accepts visitor_uid (localStorage UUID) in request body β€” HF-Spaces-safe (no cookies). 4 new analytics endpoints: /visitors, /geo, /devices, /sessions/stats. geo.py updated with region extraction and X-Real-IP header support. models/visitor.py, repositories/visitor_repo.py, services/analytics_core/visitor_tracker.py, services/analytics_core/geo.py, api/chat.py, admin/routers/analytics.py, schemas/chatbot.py, models/chat_session.py, core/startup/db.py, models/__init__.py