← Portfolio 0.1% DEV — Architecture
CLIENT APPLICATION SERVICES 👤 User Browser React 18 + Vite TanStack Query v5 · React Router v6 · Tailwind CSS static browse (0 API calls) · checkout.js modal · video player · AI chat zero-API browse FastAPI (Python) OpenAI SDK · Razorpay client · Uvicorn · CORS POST /api/payments/razorpay-order · POST /api/ai/ask LocalStorage hasCourse(id) · session → Firestore in production Firebase Storage Video streaming via URL HTML5 video · CDN delivery Razorpay API Server-side order create secret never leaves FastAPI OpenAI API text-embedding-3-small gpt-4.1-mini · async calls browse · buy · watch · ask POST response read/write stream URL create order embed + chat
STARTUP INDEXING — runs once at boot QUERY PATH — per user request seed_transcripts.json Course + lecture content chunked source of truth chunk_courses() 180-word windows 35-word overlap · step=145 embed_many() OpenAI API batch text-embedding-3-small VectorStore.index() InMemoryVectorStore persists in process · O(1) insert shared with query path ↓ question embed(question) 1536-dim vector same model as indexing cosine_similarity() InMemoryVectorStore O(N×D) scan · top 8 returned _rank_matches() semantic + Jaccard lexical max(sem, lex) per chunk · top 5 gate ≥ 0.15 → GPT-4.1-mini score < 0.15 → canned reply (no LLM) context blocks → gpt-4.1-mini → AskResponse
Key Design Decisions
Core Architecture
Static catalogue — zero API on browse
All 8 courses, tracks, and pricing live in a local JS file (tracks.js). Browsing triggers zero network calls — instant page loads, deployable to any CDN. API is only called at purchase or AI chat. This makes the browse experience feel native.
tracks.jsTanStack QueryCDN-deployable
Payments Security
Razorpay secret never leaves FastAPI
Order creation happens server-side only — FastAPI receives the amount, creates the Razorpay order, returns only the order_id and public key_id to the browser. The secret key never touches the client. Prices are stored in paise (integer) to avoid float precision issues.
FastAPIRazorpaypaise integers
RAG Design
In-memory vector store, FAISS-swappable
InMemoryVectorStore is pure Python with O(N×D) cosine scan — no NumPy, no external deps. For the seed transcript size it's fast enough. The entire store is one file (vector_store.py) with a clean interface — swap to FAISS or Pinecone in one file change.
pure Pythoncosine similarityFAISS-ready
RAG Quality
Hybrid re-ranking: semantic + Jaccard lexical
After cosine search returns top 8, _rank_matches() re-scores each with both semantic similarity (weight 1.0) and Jaccard lexical overlap (stop-word filtered). Per-chunk score is max(semantic, lexical) — ensures exact keyword matches surface even when embeddings drift.
Jaccardstop-word filtertop 5 after rerank
AI Safety
Gate at 0.15 — no LLM call below threshold
If no chunk scores ≥ 0.15, the system returns a canned "I don't have enough context" message without touching GPT-4.1-mini. This prevents hallucination on out-of-domain questions, saves API cost, and keeps the assistant honest about what it knows.
threshold gateno hallucinationcost control
Scalability Path
localStorage → Firestore production path
hasCourse(id) checks localStorage in the MVP — instant, no network call. The production path is Firestore arrayUnion per uid on successful payment. This swap is isolated to a single hook. Firebase Auth Google Sign-In replaces the current localStorage session at the same boundary.
localStorage MVPFirestoreFirebase Auth