Spaces:
Running
Running
| "use client"; | |
| import { useState } from "react"; | |
| import { motion, AnimatePresence } from "framer-motion"; | |
| import { | |
| BookOpen, ChevronRight, Terminal, Cpu, Zap, Shield, | |
| BarChart2, Globe, Server, Database, Code2, GitBranch, | |
| Layers, AlertTriangle, CheckCircle2, ArrowRight, | |
| Building2, Sparkles, Lock, Activity, FileText, | |
| MonitorSmartphone, Wifi, RefreshCw, Target, | |
| } from "lucide-react"; | |
| import { useThemeStore } from "@/lib/stores/themeStore"; | |
| // βββ Section types ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| interface Section { | |
| id: string; | |
| icon: React.ElementType; | |
| label: string; | |
| color: string; | |
| } | |
| const SECTIONS: Section[] = [ | |
| { id: "overview", icon: BookOpen, label: "Overview", color: "text-emerald-500" }, | |
| { id: "quickstart", icon: Terminal, label: "Quick Start", color: "text-blue-500" }, | |
| { id: "how-it-works", icon: Cpu, label: "How It Works", color: "text-purple-500" }, | |
| { id: "tech-stack", icon: Layers, label: "Tech Stack", color: "text-amber-500" }, | |
| { id: "features", icon: Zap, label: "Features", color: "text-cyan-500" }, | |
| { id: "architecture", icon: Server, label: "Architecture", color: "text-orange-500" }, | |
| { id: "ai-engine", icon: Sparkles, label: "AI Engine", color: "text-pink-500" }, | |
| { id: "security", icon: Shield, label: "Security", color: "text-red-500" }, | |
| { id: "database", icon: Database, label: "Database & Models", color: "text-teal-500" }, | |
| { id: "api", icon: Code2, label: "API Reference", color: "text-violet-500" }, | |
| { id: "deployment", icon: Globe, label: "Deployment", color: "text-lime-500" }, | |
| { id: "use-cases", icon: Target, label: "Use Cases", color: "text-sky-500" }, | |
| { id: "vs-real-world", icon: Building2, label: "vs Real Banking Apps", color: "text-rose-500" }, | |
| { id: "limitations", icon: AlertTriangle, label: "Limitations", color: "text-yellow-500" }, | |
| ]; | |
| // βββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function H1({ children }: { children: React.ReactNode }) { | |
| return <h1 className="text-3xl font-bold tracking-tight mb-2" style={{ color: "var(--fg)" }}>{children}</h1>; | |
| } | |
| function H2({ children, id }: { children: React.ReactNode; id?: string }) { | |
| return <h2 id={id} className="text-xl font-bold mt-8 mb-3 flex items-center gap-2" style={{ color: "var(--fg)" }}>{children}</h2>; | |
| } | |
| function H3({ children }: { children: React.ReactNode }) { | |
| return <h3 className="text-base font-semibold mt-5 mb-2" style={{ color: "var(--fg)" }}>{children}</h3>; | |
| } | |
| function P({ children }: { children: React.ReactNode }) { | |
| return <p className="text-sm leading-relaxed mb-3" style={{ color: "var(--fg-muted)" }}>{children}</p>; | |
| } | |
| function Code({ children }: { children: React.ReactNode }) { | |
| return ( | |
| <code | |
| className="px-1.5 py-0.5 rounded text-xs font-mono" | |
| style={{ background: "var(--card-bg)", border: "1px solid var(--border)", color: "var(--fg)" }} | |
| > | |
| {children} | |
| </code> | |
| ); | |
| } | |
| function CodeBlock({ children, lang = "bash" }: { children: string; lang?: string }) { | |
| const { theme } = useThemeStore(); | |
| const isLight = theme === "light"; | |
| return ( | |
| <div | |
| className="rounded-xl border text-xs font-mono overflow-x-auto mb-4" | |
| style={{ | |
| background: isLight ? "#1e1e2e" : "#0d0d0d", | |
| borderColor: "var(--border)", | |
| }} | |
| > | |
| <div | |
| className="flex items-center gap-1.5 px-4 py-2 border-b" | |
| style={{ borderColor: isLight ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.07)" }} | |
| > | |
| {["#ff5f57","#febc2e","#28c840"].map((c) => ( | |
| <div key={c} className="h-2.5 w-2.5 rounded-full" style={{ background: c }} /> | |
| ))} | |
| <span className="ml-2 text-[10px] text-zinc-500">{lang}</span> | |
| </div> | |
| <pre className="px-4 py-3 leading-relaxed text-zinc-200 whitespace-pre-wrap">{children}</pre> | |
| </div> | |
| ); | |
| } | |
| function Table({ headers, rows }: { headers: string[]; rows: string[][] }) { | |
| return ( | |
| <div className="overflow-x-auto mb-4"> | |
| <table className="w-full text-xs border-collapse"> | |
| <thead> | |
| <tr style={{ borderBottom: "1px solid var(--border)" }}> | |
| {headers.map((h) => ( | |
| <th key={h} className="text-left px-3 py-2 font-semibold" style={{ color: "var(--fg-muted)" }}>{h}</th> | |
| ))} | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {rows.map((row, i) => ( | |
| <tr key={i} style={{ borderBottom: "1px solid var(--border)" }}> | |
| {row.map((cell, j) => ( | |
| <td key={j} className="px-3 py-2 text-xs" style={{ color: "var(--fg-muted)" }}>{cell}</td> | |
| ))} | |
| </tr> | |
| ))} | |
| </tbody> | |
| </table> | |
| </div> | |
| ); | |
| } | |
| function Badge({ children, color }: { children: React.ReactNode; color: string }) { | |
| return ( | |
| <span className={`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-bold uppercase ${color}`}> | |
| {children} | |
| </span> | |
| ); | |
| } | |
| function InfoBox({ icon: Icon, title, children, color }: { icon: React.ElementType; title: string; children: React.ReactNode; color: string }) { | |
| return ( | |
| <div className="rounded-xl border p-4 mb-4" style={{ background: "var(--card-bg)", borderColor: "var(--border)" }}> | |
| <div className={`flex items-center gap-2 mb-2 ${color}`}> | |
| <Icon className="h-4 w-4" /> | |
| <span className="text-sm font-semibold">{title}</span> | |
| </div> | |
| <div className="text-sm" style={{ color: "var(--fg-muted)" }}>{children}</div> | |
| </div> | |
| ); | |
| } | |
| // βββ Content sections βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function SectionOverview() { | |
| return ( | |
| <div> | |
| <H1>BankBot AI β Documentation</H1> | |
| <P> | |
| BankBot AI is a <strong>production-grade, AI-native financial operating system</strong> built as a | |
| portfolio and educational project. It simulates the core features of a modern digital bank with a | |
| real AI layer on top β real-time chat, fraud detection, forecasting, and document analysis β all | |
| running in a single Docker container on Hugging Face Spaces. | |
| </P> | |
| <P> | |
| The project demonstrates how to architect a full-stack AI application with a FastAPI backend, | |
| a Next.js 14 frontend, multi-provider LLM fallback chains, JWT authentication, WebSocket | |
| streaming, and a glassmorphism UI β deployable anywhere from a local machine to cloud platforms. | |
| </P> | |
| <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 my-6"> | |
| {[ | |
| { icon: MonitorSmartphone, label: "Next.js 14 Frontend", sub: "TypeScript Β· Tailwind Β· Framer Motion", color: "text-blue-500", bg: "bg-blue-500/10 border-blue-500/20" }, | |
| { icon: Server, label: "FastAPI Backend", sub: "Python 3.11 Β· SQLAlchemy Β· JWT", color: "text-emerald-500", bg: "bg-emerald-500/10 border-emerald-500/20" }, | |
| { icon: Sparkles, label: "4-Tier AI Chain", sub: "OpenAI β Groq β Ollama β Rules", color: "text-purple-500", bg: "bg-purple-500/10 border-purple-500/20" }, | |
| ].map((item) => ( | |
| <div key={item.label} className={`rounded-xl border p-4 ${item.bg}`}> | |
| <item.icon className={`h-5 w-5 mb-2 ${item.color}`} /> | |
| <p className="text-sm font-semibold" style={{ color: "var(--fg)" }}>{item.label}</p> | |
| <p className="text-xs mt-0.5" style={{ color: "var(--fg-muted)" }}>{item.sub}</p> | |
| </div> | |
| ))} | |
| </div> | |
| <H2>Demo Account</H2> | |
| <CodeBlock lang="credentials">{`Email: alex@bankbot.dev | |
| Password: BankBot2026! | |
| Pre-loaded data: | |
| β’ $59,637 across 3 accounts (checking Β· savings Β· investment) | |
| β’ 160 transactions across 6 months | |
| β’ 1 fraud alert (Tech Store NYC Β· $847 Β· 78% risk score) | |
| β’ 4 financial goals (Emergency Fund Β· Vacation Β· MacBook Β· Down Payment) | |
| β’ 4 investments (S&P 500 Β· AAPL Β· BTC Β· US Treasuries) | |
| β’ 6 subscriptions (Netflix Β· Spotify Β· Adobe CC Β· Planet Fitness Β· iCloud Β· LinkedIn) | |
| β’ 6 notifications (3 unread)`}</CodeBlock> | |
| </div> | |
| ); | |
| } | |
| function SectionQuickStart() { | |
| return ( | |
| <div> | |
| <H1>Quick Start</H1> | |
| <P>Three ways to run BankBot AI β pick whichever fits your situation.</P> | |
| <H2>Option 1 β Hugging Face (No setup)</H2> | |
| <P>The easiest option. Just open the link and log in with the demo credentials.</P> | |
| <InfoBox icon={CheckCircle2} title="Live Demo" color="text-emerald-500"> | |
| <a href="https://mohsin-devs-bankbot.hf.space/" target="_blank" rel="noreferrer" | |
| className="text-emerald-500 underline">https://mohsin-devs-bankbot.hf.space/</a> | |
| <br />AI backend: Groq (llama-3.3-70b) Β· DB: SQLite Β· Cache: in-memory | |
| </InfoBox> | |
| <H2>Option 2 β Local Development</H2> | |
| <P>Requires Python 3.11+ and Node.js 18+. Run these once:</P> | |
| <CodeBlock lang="bash">{`# 1. Clone the repo | |
| git clone https://github.com/mohsinkp02/Bankbot-AI.git | |
| cd Bankbot-AI | |
| # 2. Backend setup | |
| cd backend | |
| python -m venv venv | |
| venv\\Scripts\\activate # Windows | |
| # source venv/bin/activate # macOS / Linux | |
| pip install -r requirements.txt | |
| # 3. Configure environment (copy example and edit) | |
| copy .env.example .env | |
| # Open .env and add at minimum: | |
| # GROQ_API_KEY=gsk_... β free at console.groq.com | |
| # JWT_SECRET_KEY=any-long-random-string | |
| # 4. Seed demo data | |
| python app/scripts/seed_demo.py | |
| # 5. Start backend (keep this terminal open) | |
| uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload`}</CodeBlock> | |
| <CodeBlock lang="bash">{`# 6. In a NEW terminal β frontend setup | |
| cd frontend | |
| npm install --legacy-peer-deps | |
| npm run dev`}</CodeBlock> | |
| <CodeBlock lang="text">{`Then open: | |
| Frontend β http://localhost:3000 | |
| API Docs β http://localhost:8000/docs | |
| Metrics β http://localhost:8000/api/metrics | |
| Health β http://localhost:8000/health`}</CodeBlock> | |
| <H2>Option 3 β Docker Compose</H2> | |
| <P>Runs everything (Nginx + FastAPI + Next.js + SQLite) in containers.</P> | |
| <CodeBlock lang="bash">{`# 1. Copy and configure environment | |
| copy .env.example .env | |
| # Add GROQ_API_KEY and JWT_SECRET_KEY | |
| # 2. Build and start | |
| docker compose up -d | |
| # 3. Seed demo data | |
| docker compose exec backend python app/scripts/seed_demo.py | |
| # 4. Open http://localhost:3000 | |
| # Stop | |
| docker compose down`}</CodeBlock> | |
| <H2>Environment Variables Reference</H2> | |
| <Table | |
| headers={["Variable", "Required", "Default", "Description"]} | |
| rows={[ | |
| ["GROQ_API_KEY", "Recommended", "β", "Free LLM from console.groq.com"], | |
| ["OPENAI_API_KEY", "Optional", "β", "OpenAI GPT-4o-mini (priority 1)"], | |
| ["JWT_SECRET_KEY", "Yes (prod)", "dev-secret","Signs JWT tokens"], | |
| ["DATABASE_URL", "Optional", "SQLite", "PostgreSQL URL (Neon / Supabase)"], | |
| ["REDIS_URL", "Optional", "in-memory","Redis URL for caching"], | |
| ["BACKEND_CORS_ORIGINS", "Optional", '["http://localhost:3000"]', "Allowed frontend origins"], | |
| ["ACCESS_TOKEN_EXPIRE_MINUTES", "Optional","60", "JWT access token lifetime"], | |
| ]} | |
| /> | |
| </div> | |
| ); | |
| } | |
| function SectionHowItWorks() { | |
| return ( | |
| <div> | |
| <H1>How It Works</H1> | |
| <P> | |
| BankBot AI is a <strong>full-stack monorepo</strong> with a clear separation of concerns. | |
| The frontend never talks directly to the database β everything goes through the FastAPI backend | |
| which handles auth, business logic, AI orchestration, and caching. | |
| </P> | |
| <H2>Request Lifecycle</H2> | |
| <CodeBlock lang="text">{String.raw`User action (e.g. load dashboard) | |
| β | |
| βΌ | |
| Next.js page component | |
| β calls dashboardApi.overview() | |
| β fetch("/api/dashboard/overview", { Authorization: Bearer <token> }) | |
| β | |
| βΌ β Nginx routes /api/* to FastAPI | |
| FastAPI route handler | |
| β validates JWT token | |
| β checks Redis cache (key: "dashboard:overview:USER_ID") | |
| β | |
| βββββββ΄βββββββ | |
| β Cache HIT β β returns JSON in ~10ms | |
| β Cache MISS β β queries SQLite/PostgreSQL | |
| βββββββ¬βββββββ accounts + transactions + goals + fraud_logs | |
| β | |
| βΌ | |
| runs AI briefing (Groq β offline fallback) | |
| sets cache (TTL 2 min) | |
| returns JSON response | |
| β | |
| βΌ | |
| React component receives data | |
| β renders dashboard with charts, cards, fraud shield`}</CodeBlock> | |
| <H2>AI Chat Flow</H2> | |
| <P> | |
| The AI Assistant builds a <strong>full financial context prompt</strong> from the user's live data | |
| before every message β so it always knows your real balance, goals, and spending patterns. | |
| </P> | |
| <CodeBlock lang="text">{`User types "How much did I spend on food this month?" | |
| β | |
| βΌ | |
| POST /api/ai/chat (with message + session_id + language) | |
| β | |
| βΌ | |
| Backend fetches user's financial context: | |
| β’ accounts + balances | |
| β’ last 50 transactions | |
| β’ active goals + progress | |
| β’ investments | |
| β’ subscriptions | |
| β’ fraud alerts | |
| β | |
| βΌ | |
| Builds system prompt: | |
| "You are BankBot. User Alex has $59,637 total. | |
| This month: Food $487.30 across 12 transactions. | |
| Top merchant: Chipotle ($143). ..." | |
| β | |
| βΌ | |
| AI Provider chain: | |
| 1. OpenAI gpt-4o-mini (if OPENAI_API_KEY set) | |
| 2. Groq llama-3.3-70b (if GROQ_API_KEY set) β HF demo uses this | |
| 3. Ollama llama3 (if running locally) | |
| 4. Rule-based fallback (always available) | |
| β | |
| βΌ | |
| Response streamed back β saved to chat memory β displayed`}</CodeBlock> | |
| <H2>Fraud Detection Flow</H2> | |
| <CodeBlock lang="text">{`Every transaction is scored when it enters the system: | |
| Amount spike? >3.5x user avg β +40 pts | |
| >2.0x user avg β +20 pts | |
| Night timing? 11PM β 4AM β +25 pts | |
| Rapid-fire? <3 min gap β +20 pts | |
| Duplicate? same merchant + amount in 10 min β +30 pts | |
| β | |
| Score β₯ 50 β status: "flagged" β notification created | |
| Score 30-49 β status: "suspicious" | |
| Score < 30 β status: "verified"`}</CodeBlock> | |
| <H2>Caching Strategy</H2> | |
| <Table | |
| headers={["Endpoint", "Cache Key", "TTL", "Why"]} | |
| rows={[ | |
| ["/api/dashboard/overview", "dashboard:overview:{uid}", "2 min", "Heavy DB query, high traffic"], | |
| ["/api/ai/coaching/score", "ai:coaching:score:{uid}", "10 min", "LLM call, slow to compute"], | |
| ["/api/ai/coaching/briefing", "ai:coaching:briefing:{uid}", "1 hour", "Expensive AI generation"], | |
| ["/api/ai/behavior/insights", "ai:behavior:insights:{uid}", "10 min", "Pattern analysis is heavy"], | |
| ["/api/ai/twin/predict", "ai:twin:predict:{uid}", "5 min", "Moderate cost"], | |
| ["/api/ai/subscriptions", "ai:subs:optimize:{uid}", "10 min", "Stable subscription data"], | |
| ]} | |
| /> | |
| <P> | |
| Cache backend: <strong>Redis β in-memory dict fallback</strong>. If Redis is not configured | |
| the app silently falls back to an in-process Python dict. No config change needed. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| function SectionTechStack() { | |
| return ( | |
| <div> | |
| <H1>Tech Stack</H1> | |
| <H2>Frontend</H2> | |
| <Table | |
| headers={["Library", "Version", "Purpose"]} | |
| rows={[ | |
| ["Next.js", "14.2", "React framework β App Router, SSR, standalone output"], | |
| ["TypeScript", "5.x", "Type safety across the entire frontend"], | |
| ["Tailwind CSS", "3.4", "Utility-first styling + custom CSS variables for theming"], | |
| ["Framer Motion", "12.x", "Page transitions, card animations, stagger effects"], | |
| ["Recharts", "3.x", "Area charts, pie charts, sparklines"], | |
| ["Zustand", "5.x", "Lightweight global state β auth, theme, language, dashboard"], | |
| ["Radix UI", "latest", "Accessible dialog, slider, tooltip primitives"], | |
| ["Lucide React", "latest", "Icon system"], | |
| ]} | |
| /> | |
| <H2>Backend</H2> | |
| <Table | |
| headers={["Library", "Version", "Purpose"]} | |
| rows={[ | |
| ["FastAPI", "0.111", "Async HTTP + WebSocket API framework"], | |
| ["Uvicorn", "0.29", "ASGI server with hot-reload"], | |
| ["SQLAlchemy", "2.0", "ORM + connection pooling"], | |
| ["Alembic", "1.13", "Database migrations"], | |
| ["python-jose", "3.3", "JWT encode/decode (HS256)"], | |
| ["passlib[bcrypt]", "1.7", "Password hashing (rounds=12)"], | |
| ["openai", "1.30", "OpenAI API client"], | |
| ["groq", "0.9", "Groq API client (llama-3.3-70b)"], | |
| ["redis", "5.0", "Redis client with in-memory fallback"], | |
| ["pydantic", "2.7", "Request/response validation and settings"], | |
| ["pypdf / PyMuPDF", "latest","PDF text extraction"], | |
| ["python-docx", "1.1", "DOCX text extraction"], | |
| ]} | |
| /> | |
| <H2>Infrastructure</H2> | |
| <Table | |
| headers={["Tool", "Role"]} | |
| rows={[ | |
| ["Docker", "Single-container build: Node build stage + Python runtime stage"], | |
| ["Nginx", "Reverse proxy: port 7860 β Next.js (3000) or FastAPI (8000)"], | |
| ["Supervisord", "Process manager: runs Nginx + FastAPI + Next.js in one container"], | |
| ["SQLite", "Default database β zero config, file-based, auto-fallback"], | |
| ["PostgreSQL", "Production database option (Neon / Supabase / Render)"], | |
| ["Hugging Face Spaces", "Free GPU-less Docker hosting β public URL in minutes"], | |
| ["GitHub Actions", "CI: lint + build checks on push"], | |
| ]} | |
| /> | |
| <H2>Why These Choices</H2> | |
| <InfoBox icon={Zap} title="Next.js App Router + FastAPI" color="text-blue-500"> | |
| Separating frontend and backend gives clean API contracts and allows each to be deployed | |
| independently (Vercel + Render) or together in Docker. The <Code>standalone</Code> output | |
| mode shrinks the Docker image by ~70% vs a full node_modules copy. | |
| </InfoBox> | |
| <InfoBox icon={Database} title="SQLite as default" color="text-emerald-500"> | |
| SQLite needs zero infrastructure β perfect for demos, local dev, and HF Spaces. | |
| The same ORM code works with PostgreSQL in production with one env var change. | |
| No migration needed between environments. | |
| </InfoBox> | |
| <InfoBox icon={Sparkles} title="Groq over OpenAI as default" color="text-purple-500"> | |
| Groq's free tier runs llama-3.3-70b at 500+ tokens/second β fast enough for real-time | |
| streaming and free enough for a portfolio project. OpenAI is supported as priority 1 | |
| if a key is provided. | |
| </InfoBox> | |
| </div> | |
| ); | |
| } | |
| function SectionFeatures() { | |
| return ( | |
| <div> | |
| <H1>Features</H1> | |
| <H2><BarChart2 className="h-5 w-5 text-blue-500" /> Dashboard</H2> | |
| <P> | |
| A single API call (<Code>GET /api/dashboard/overview</Code>) returns everything the dashboard | |
| needs: total balance, 4 stat cards, 6-month cash flow chart, category spending pie, | |
| 5 recent transactions, health score, and AI daily briefing. Cold: ~65ms. Cached: ~10ms. | |
| </P> | |
| <H2><Sparkles className="h-5 w-5 text-emerald-500" /> AI Financial Twin</H2> | |
| <P> | |
| The AI assistant has full context of your finances injected into every prompt. It knows | |
| your actual balance, top spending categories, active goals, investments, and fraud alerts. | |
| It responds in English, Hindi, or Marathi depending on your language setting. | |
| </P> | |
| <P> | |
| File attachment in chat: attach a PDF bank statement, CSV, DOCX invoice, or image directly | |
| in the chat input. The backend extracts text, runs an AI analysis, and you can ask questions | |
| about the document in the same conversation thread. | |
| </P> | |
| <H2><Shield className="h-5 w-5 text-red-500" /> Fraud Detection</H2> | |
| <P> | |
| Rule-based scoring engine that evaluates every transaction on 4 dimensions: amount vs | |
| personal average, time-of-day, transaction velocity, and duplicate detection. Flagged | |
| transactions create notifications and appear in the Security page with AI explanations. | |
| </P> | |
| <H2><Activity className="h-5 w-5 text-purple-500" /> Financial Health Score</H2> | |
| <P> | |
| A 100-point composite score across 6 weighted dimensions: savings consistency (20pts), | |
| debt ratio (20pts), spending discipline (20pts), emergency fund coverage (20pts), | |
| investment diversification (10pts), subscription hygiene (10pts). | |
| </P> | |
| <H2><Zap className="h-5 w-5 text-amber-500" /> What-If Simulator</H2> | |
| <P> | |
| 6 real-time sliders (income, rent, food, transport, entertainment, savings target) that | |
| generate an instant 36-month balance projection. Changes are calculated client-side for | |
| immediate feedback, with an AI commentary generated on demand. | |
| </P> | |
| <H2><Globe className="h-5 w-5 text-cyan-500" /> Multi-Language UI</H2> | |
| <P> | |
| Full UI translation in English, Hindi, and Marathi. The AI assistant also responds in | |
| the selected language. The <Code>html lang</Code> attribute updates automatically on | |
| language change for proper browser accessibility support. | |
| </P> | |
| <H2><MonitorSmartphone className="h-5 w-5 text-slate-500" /> Dark / Light Mode</H2> | |
| <P> | |
| Full theme system built on CSS custom properties. Every surface β sidebar, navbar, cards, | |
| charts, tooltips, notifications β adapts cleanly between dark and light mode with a single | |
| DOM class toggle. Persisted to localStorage. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| function SectionArchitecture() { | |
| return ( | |
| <div> | |
| <H1>Architecture</H1> | |
| <H2>Single-Container HF Deployment</H2> | |
| <CodeBlock lang="text">{`Internet β HF Spaces (port 7860) | |
| β | |
| βΌ | |
| Nginx (port 7860) | |
| ββββββββ΄βββββββ | |
| βΌ βΌ | |
| Next.js (3000) FastAPI (8000) | |
| (frontend) (backend API) | |
| β | |
| ββββββββββ΄βββββββββ | |
| βΌ βΌ | |
| SQLite in-memory cache | |
| (auto-seeded) (Redis fallback)`}</CodeBlock> | |
| <H2>Local / Docker Compose</H2> | |
| <CodeBlock lang="text">{`Browser β localhost:3000 (Next.js) | |
| Browser β localhost:8000 (FastAPI) β direct in dev mode | |
| Docker mode (docker compose up): | |
| nginx: localhost:80 β routes /api/* to fastapi, rest to nextjs | |
| fastapi: localhost:8000 | |
| nextjs: localhost:3000 | |
| postgres: localhost:5432 (optional, override with DATABASE_URL) | |
| redis: localhost:6379 (optional, override with REDIS_URL)`}</CodeBlock> | |
| <H2>Directory Structure</H2> | |
| <CodeBlock lang="text">{`BankBot New/ | |
| βββ Dockerfile # Single-container build (HF Spaces) | |
| βββ docker-compose.yml # Multi-service local/prod | |
| βββ hf/ | |
| β βββ nginx.conf # Nginx reverse proxy config | |
| β βββ supervisord.conf # Process manager config | |
| β βββ start.sh # Container startup script | |
| βββ backend/ | |
| β βββ app/ | |
| β β βββ main.py # FastAPI app + middleware stack | |
| β β βββ ai/ # AI modules (chat, fraud, coaching, ...) | |
| β β βββ auth/ # JWT auth router | |
| β β βββ dashboard/ # Dashboard aggregation router | |
| β β βββ database/ # SQLAlchemy models + migrations | |
| β β βββ middleware/ # Logging, caching, rate limiting | |
| β β βββ scripts/ # seed_demo.py | |
| β βββ requirements.txt | |
| βββ frontend/ | |
| βββ src/ | |
| β βββ app/ # Next.js App Router pages | |
| β β βββ page.tsx # Dashboard | |
| β β βββ chat/ # AI Assistant | |
| β β βββ analytics/ # Spending intelligence | |
| β β βββ simulator/ # What-If engine | |
| β β βββ security/ # Fraud alerts | |
| β β βββ settings/ # User preferences | |
| β β βββ docs/ # This page | |
| β βββ components/ | |
| β β βββ layout/ # Sidebar, Navbar, AppShell, DashboardLayout | |
| β β βββ ui/ # Shadcn primitives | |
| β βββ lib/ | |
| β βββ api.ts # Typed fetch client for all endpoints | |
| β βββ stores/ # Zustand: auth, theme, language, dashboard | |
| βββ package.json`}</CodeBlock> | |
| </div> | |
| ); | |
| } | |
| function SectionAIEngine() { | |
| return ( | |
| <div> | |
| <H1>AI Engine</H1> | |
| <P> | |
| BankBot's AI layer is a <strong>4-tier fallback chain</strong> with automatic provider | |
| detection. It never crashes β if all cloud providers fail, it falls back to a deterministic | |
| rule-based engine that still produces useful answers using real database data. | |
| </P> | |
| <H2>Provider Priority</H2> | |
| <CodeBlock lang="text">{`1. OpenAI (gpt-4o-mini) if OPENAI_API_KEY is set | |
| β on error / unavailable | |
| 2. Groq (llama-3.3-70b) if GROQ_API_KEY is set | |
| β on error / unavailable | |
| 3. Ollama (llama3:latest) if Ollama running on localhost:11434 | |
| β on error / unavailable | |
| 4. Rule-based fallback always available β uses real DB data`}</CodeBlock> | |
| <H2>Context Injection</H2> | |
| <P>Before every chat message, the backend builds a system prompt from live user data:</P> | |
| <CodeBlock lang="python">{"system_prompt = f\"\"\"\nYou are BankBot, an elite AI Financial Analyst.\nALWAYS communicate in {language}.\n\nLIVE USER DATA:\n Name: {user.name}\n Personality: {user.financial_personality}\n Health Score: {score}/100\n Total Balance: ${total_balance:,.2f}\n Checking: ${checking:,.2f}\n Savings: ${savings:,.2f}\n Investment: ${investment:,.2f}\n\nMONTHLY ACTIVITY:\n Income: ${monthly_income:,.2f}\n Expenses: ${monthly_expenses:,.2f}\n Savings Rate: {savings_rate:.1f}%\n\nTOP SPENDING: {top_categories}\nACTIVE GOALS: {goals_summary}\nINVESTMENTS: {investments_summary}\nFRAUD ALERTS: {fraud_count} pending\n\nRULES:\n 1. Never give generic advice β use real numbers above\n 2. Keep answers concise and actionable\n 3. Respond in {language}\n\"\"\""}</CodeBlock> | |
| <H2>Document Analysis</H2> | |
| <P> | |
| Files attached in the AI chat are uploaded to <Code>POST /api/documents/upload</Code>, | |
| which extracts text (PDF via pypdf + PyMuPDF + Tesseract OCR fallback, DOCX via python-docx, | |
| CSV row-by-row) and runs a structured analysis prompt. The extracted text is capped at 50,000 | |
| characters for storage and 6,000 characters per AI prompt to stay within token limits. | |
| </P> | |
| <H2>Streaming</H2> | |
| <P> | |
| The WebSocket endpoint (<Code>WS /api/ai/chat/ws</Code>) streams tokens from the AI provider | |
| as they arrive. The HTTP fallback (<Code>POST /api/ai/chat</Code>) returns the full response | |
| at once. The frontend simulates word-by-word streaming on HTTP responses using a 28ms interval. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| function SectionSecurity() { | |
| return ( | |
| <div> | |
| <H1>Security</H1> | |
| <H2>Authentication Flow</H2> | |
| <CodeBlock lang="text">{`POST /api/auth/login | |
| β validates email + bcrypt hash (rounds=12) | |
| β returns access_token (JWT, 60min) + refresh_token (JWT, 7 days) | |
| All protected requests: | |
| Authorization: Bearer <access_token> | |
| β FastAPI verifies signature + expiry on every request | |
| Token expired? | |
| β POST /api/auth/refresh with refresh_token | |
| β returns new access_token (refresh_token unchanged) | |
| Frontend (api.ts): | |
| β auto-retry on 401: tries refresh, then clears tokens + redirects to /login`}</CodeBlock> | |
| <H2>Middleware Stack</H2> | |
| <P>Every request passes through this stack before reaching a route handler:</P> | |
| <CodeBlock lang="text">{`1. Nginx β rate limit (30 req/min API, 10 req/min auth) | |
| 2. FastAPI β CORS validation (allowed origins from BACKEND_CORS_ORIGINS) | |
| 3. FastAPI β rate limiter (120 req/min per IP, in-process) | |
| 4. FastAPI β security headers: | |
| X-Content-Type-Options: nosniff | |
| X-Frame-Options: DENY | |
| X-XSS-Protection: 1; mode=block | |
| Referrer-Policy: strict-origin-when-cross-origin | |
| 5. FastAPI β request logger (structured JSON with request-id) | |
| 6. FastAPI β process-time header (X-Process-Time: 12.4ms) | |
| 7. Route β JWT validation (if protected) | |
| 8. Handler β business logic`}</CodeBlock> | |
| <InfoBox icon={AlertTriangle} title="Demo Note" color="text-amber-500"> | |
| The HF demo uses an ephemeral JWT_SECRET_KEY generated at container start. This means | |
| sessions don't survive a container restart. Set a persistent JWT_SECRET_KEY in HF Secrets | |
| to fix this for real usage. | |
| </InfoBox> | |
| </div> | |
| ); | |
| } | |
| function SectionDatabase() { | |
| return ( | |
| <div> | |
| <H1>Database & Models</H1> | |
| <P> | |
| BankBot uses SQLAlchemy 2.0 with auto-fallback: if <Code>DATABASE_URL</Code> points to | |
| PostgreSQL and the connection fails, it silently falls back to SQLite. All models work | |
| identically on both databases. | |
| </P> | |
| <H2>Core Models</H2> | |
| <Table | |
| headers={["Model", "Key Fields", "Relationships"]} | |
| rows={[ | |
| ["User", "id (UUID), email, password_hash, profile_data (JSON), financial_personality", "has many: Accounts, Goals, Investments, Subscriptions, Notifications"], | |
| ["Account", "id, user_id, type (checking/savings/investment), balance, currency, status", "belongs to: User Β· has many: Transactions"], | |
| ["Transaction", "id, account_id, amount, type (credit/debit), category, merchant, timestamp, tags (JSON)", "belongs to: Account Β· may have: FraudLog"], | |
| ["FraudLog", "id, transaction_id, risk_score (0β1), suspicious_activity_details, status", "belongs to: Transaction"], | |
| ["Goal", "id, user_id, title, target_amount, current_amount, target_date, ai_generated_plan (JSON)", "belongs to: User"], | |
| ["Investment", "id, user_id, asset_name, type, amount_invested, current_value, portfolio_allocation, ai_risk_analysis (JSON)", "belongs to: User"], | |
| ["Subscription", "id, user_id, merchant, amount, billing_cycle, active, ai_usage_detection (JSON)", "belongs to: User"], | |
| ["Notification", "id, user_id, title, message, type, read_status, created_at", "belongs to: User"], | |
| ["ChatMessage", "id, user_id, session_id, role (user/assistant), content, created_at", "belongs to: User"], | |
| ["UploadedDocument","id, user_id, filename, file_type, extracted_text, ai_summary, ai_insights (JSON)", "belongs to: User Β· has many: DocumentMessages"], | |
| ]} | |
| /> | |
| <H2>Seed Data</H2> | |
| <P> | |
| Running <Code>python app/scripts/seed_demo.py</Code> creates the <Code>alex@bankbot.dev</Code> demo | |
| account with 160 realistic transactions across 6 months, all goals, investments, subscriptions, | |
| notifications, and one fraud alert. The script is idempotent β it deletes the existing demo user | |
| first, then re-creates everything clean. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| function SectionAPI() { | |
| return ( | |
| <div> | |
| <H1>API Reference</H1> | |
| <P> | |
| Interactive Swagger UI available at <Code>http://localhost:8000/docs</Code> when running locally. | |
| All protected endpoints require <Code>Authorization: Bearer {'<token>'}</Code>. | |
| </P> | |
| <H2>Core Endpoints</H2> | |
| <Table | |
| headers={["Method", "Path", "Auth", "Description"]} | |
| rows={[ | |
| ["GET", "/health", "No", "Health check β status, db, cache, uptime"], | |
| ["GET", "/api/status", "No", "Runtime info β AI backend, DB type, version"], | |
| ["GET", "/api/metrics", "No", "Live observability β request counts, AI latency, cache hit ratio"], | |
| ["GET", "/docs", "No", "Interactive Swagger UI"], | |
| ["POST", "/api/auth/register", "No", "Create account β returns JWT pair"], | |
| ["POST", "/api/auth/login", "No", "Login (form-encoded) β returns JWT pair"], | |
| ["POST", "/api/auth/refresh", "No", "Refresh access token"], | |
| ["GET", "/api/auth/me", "Yes", "Current user profile"], | |
| ["PATCH","/api/auth/settings", "Yes", "Update name / preferences"], | |
| ["GET", "/api/dashboard/overview", "Yes", "Full dashboard data (cached 2min)"], | |
| ["GET", "/api/transactions/", "Yes", "Paginated transactions (filter by category/type)"], | |
| ["GET", "/api/notifications/", "Yes", "Notifications + unread count"], | |
| ["PATCH","/api/notifications/{id}/read", "Yes", "Mark notification read"], | |
| ["PATCH","/api/notifications/read-all", "Yes", "Mark all notifications read"], | |
| ["DELETE","/api/notifications/{id}", "Yes", "Dismiss notification"], | |
| ["GET", "/api/ai/coaching/score", "Yes", "Financial health score (cached 10min)"], | |
| ["GET", "/api/ai/coaching/briefing", "Yes", "AI daily briefing (cached 1hr)"], | |
| ["GET", "/api/ai/behavior/insights", "Yes", "Spending behavior analysis"], | |
| ["GET", "/api/ai/twin/predict", "Yes", "30-day balance forecast"], | |
| ["GET", "/api/ai/twin/future", "Yes", "Long-term projection (param: months)"], | |
| ["GET", "/api/ai/twin/scenarios", "Yes", "Conservative/expected/optimistic scenarios"], | |
| ["GET", "/api/ai/fraud/analysis", "Yes", "All fraud alerts for user"], | |
| ["POST", "/api/ai/chat", "Yes", "HTTP chat (non-streaming)"], | |
| ["WS", "/api/ai/chat/ws", "Yes", "Streaming WebSocket chat"], | |
| ["POST", "/api/payments/create", "Yes", "Create payment with fraud scoring"], | |
| ["POST", "/api/payments/transfer", "Yes", "Internal account transfer"], | |
| ["GET", "/api/payments/history", "Yes", "Payment history"], | |
| ["GET", "/api/goals", "Yes", "User financial goals + progress"], | |
| ["POST", "/api/goals/{id}/contribute", "Yes", "Add contribution to a goal"], | |
| ["POST", "/api/loans/eligibility", "Yes", "ML-based loan eligibility prediction"], | |
| ["GET", "/api/memory/history", "Yes", "Chat history (all sessions)"], | |
| ["POST", "/api/memory/save", "Yes", "Save a chat message"], | |
| ["DELETE","/api/memory/clear", "Yes", "Clear chat history"], | |
| ["POST", "/api/documents/upload", "Yes", "Upload + analyze document"], | |
| ["POST", "/api/documents/chat/{id}", "Yes", "Ask question about a document"], | |
| ["GET", "/api/documents/history", "Yes", "Previously uploaded documents"], | |
| ]} | |
| /> | |
| </div> | |
| ); | |
| } | |
| function SectionDeployment() { | |
| return ( | |
| <div> | |
| <H1>Deployment</H1> | |
| <H2>Hugging Face Spaces (Current)</H2> | |
| <P> | |
| The project deploys as a single Docker container to HF Spaces. The <Code>Dockerfile</Code> | |
| has two build stages: Node.js 20 compiles the Next.js standalone bundle, then a Python 3.11 | |
| slim image assembles the final runtime with Nginx, supervisord, Node, and all Python | |
| dependencies. | |
| </P> | |
| <CodeBlock lang="bash">{`# Push to the hf remote triggers an automatic rebuild: | |
| git push hf hf-deploy2:main | |
| # HF detects the new SHA, builds the Docker image (~5 min), | |
| # then starts the container. Live URL: | |
| # https://mohsin-devs-bankbot.hf.space/`}</CodeBlock> | |
| <H2>Vercel + Render (Split Deploy)</H2> | |
| <CodeBlock lang="bash">{`# Frontend β Vercel | |
| cd frontend | |
| npx vercel --prod | |
| # Set env var: NEXT_PUBLIC_API_URL=https://your-backend.onrender.com | |
| # Backend β Render | |
| # 1. Push to GitHub | |
| # 2. Render.com β New Web Service β connect repo | |
| # 3. Render reads backend/render.yaml automatically | |
| # 4. Set secrets: GROQ_API_KEY, JWT_SECRET_KEY | |
| # 5. Render provisions PostgreSQL + Redis from render.yaml`}</CodeBlock> | |
| <H2>Persistent Database Options</H2> | |
| <Table | |
| headers={["Option", "Cost", "Setup", "Notes"]} | |
| rows={[ | |
| ["SQLite (default)", "Free", "None", "Resets on HF Space restart"], | |
| ["Neon PostgreSQL", "Free tier", "DATABASE_URL secret", "Persistent, 3GB free"], | |
| ["Supabase", "Free tier", "DATABASE_URL secret", "Persistent, managed backups"], | |
| ["Render PostgreSQL","Free tier", "Auto via render.yaml", "Best for Render deploys"], | |
| ]} | |
| /> | |
| </div> | |
| ); | |
| } | |
| function SectionUseCases() { | |
| return ( | |
| <div> | |
| <H1>Use Cases</H1> | |
| <P> | |
| BankBot AI was built with specific audiences in mind. Here's who it's for and what | |
| they can do with it. | |
| </P> | |
| <H2>1. Portfolio Project / Viva Demonstration</H2> | |
| <P> | |
| The primary use case. The project demonstrates end-to-end full-stack development: database | |
| design, REST + WebSocket APIs, JWT auth, LLM integration with fallback chains, Docker | |
| containerization, CI/CD, and a production-quality UI. | |
| </P> | |
| <P> | |
| For a college viva or technical interview, you can walk through: the ER diagram, the fraud | |
| detection algorithm, the AI context injection, the caching strategy, the Docker multi-stage | |
| build, or the theme system β each one a self-contained deep-dive topic. | |
| </P> | |
| <H2>2. Learning Full-Stack AI Development</H2> | |
| <P> | |
| The codebase is structured and commented as a learning resource. Each module is independent: | |
| you can study just the auth system, just the WebSocket streaming, or just the Zustand stores | |
| without needing to understand the whole system. | |
| </P> | |
| <H2>3. Starter Template for Fintech Projects</H2> | |
| <P> | |
| The backend routers, database models, JWT auth flow, and AI orchestration layer can be | |
| adapted for real financial tools. The 4-tier AI fallback chain is especially reusable β | |
| swap the financial domain prompts for any other domain. | |
| </P> | |
| <H2>4. AI Chatbot Architecture Reference</H2> | |
| <P> | |
| The pattern of injecting live database context into every LLM prompt (rather than relying | |
| on RAG or fine-tuning) is a practical technique for domain-specific chatbots. BankBot | |
| shows how to do this cleanly with SQLAlchemy + FastAPI + streaming responses. | |
| </P> | |
| <H2>5. Demo for Non-Technical Stakeholders</H2> | |
| <P> | |
| The polished UI, realistic data, and immediate AI responses make it effective as a product | |
| demo or mockup for fintech pitches β showing what a modern banking interface with AI could | |
| look like, without building a real bank. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| function SectionVsRealWorld() { | |
| return ( | |
| <div> | |
| <H1>BankBot vs Real Banking Apps</H1> | |
| <P> | |
| This is the most important section for understanding what BankBot is and what it isn't. | |
| It's a realistic simulation, not a production banking system. | |
| </P> | |
| <H2>What BankBot Does That Real Banks Do</H2> | |
| <Table | |
| headers={["Feature", "BankBot", "Real Bank"]} | |
| rows={[ | |
| ["JWT authentication", "β Full implementation", "β OAuth2 / proprietary"], | |
| ["Transaction history", "β Paginated, filterable", "β Same concept"], | |
| ["Financial health score", "β Rule-based 100-pt system", "β Credit score systems"], | |
| ["Fraud detection alerts", "β Real-time scoring + alerts", "β ML models + human review"], | |
| ["Goal tracking", "β Progress + AI plan", "β Savings goals / pots"], | |
| ["Multi-language support", "β EN / HI / MR", "β Varies by region"], | |
| ["API-first architecture", "β REST + WebSocket", "β Open Banking APIs"], | |
| ["Dark / light theme", "β Full CSS variable system", "β Most modern apps"], | |
| ]} | |
| /> | |
| <H2>Where BankBot Differs from Real Banking</H2> | |
| <Table | |
| headers={["Area", "BankBot", "Real Banking System"]} | |
| rows={[ | |
| ["Money movement", "Simulated β no actual fund transfer", "Real money, regulatory compliance (PCI-DSS, PSD2)"], | |
| ["Identity verification", "Email + password only", "KYC: ID docs, face match, address proof"], | |
| ["Data persistence", "SQLite resets on HF restart", "ACID-compliant PostgreSQL clusters, backups, DR"], | |
| ["AI advice", "Informational only, not regulated", "Licensed financial advisors, fiduciary duty"], | |
| ["Security audit", "Basic JWT + bcrypt, no pen testing", "SOC 2, ISO 27001, regular security audits"], | |
| ["Scale", "Single-container, 1 worker, ~100 users", "Kubernetes, load balancers, millions of users"], | |
| ["Transaction data", "Seeded synthetic data", "Real transaction feeds (Plaid, bank APIs)"], | |
| ["Fraud ML", "Rule-based scoring (4 heuristics)", "Deep learning on billions of transactions"], | |
| ["Payments", "Fake payment records, no actual routing", "SWIFT, ACH, SEPA, UPI, real settlement"], | |
| ["Regulatory compliance", "None", "RBI, FCA, OCC, FDIC depending on jurisdiction"], | |
| ["Investment data", "Static seeded values", "Real-time market feeds (Bloomberg, Reuters)"], | |
| ]} | |
| /> | |
| <InfoBox icon={AlertTriangle} title="Important Disclaimer" color="text-amber-500"> | |
| BankBot AI is an educational demo. It does not handle real money, store real financial data, | |
| or provide regulated financial advice. AI responses are generated by a language model and | |
| may contain errors. Do not use it to make actual financial decisions. | |
| </InfoBox> | |
| <H2>What Makes BankBot Technically Interesting</H2> | |
| <P>Despite being a demo, several parts of BankBot reflect real production patterns:</P> | |
| <CodeBlock lang="text">{`β 4-tier AI fallback chain β same pattern used in production LLM apps | |
| β Cache-aside with TTL per endpoint β standard Redis pattern | |
| β JWT access + refresh token flow β same as real OAuth2 implementations | |
| β WebSocket with heartbeat + auto-reconnect β production WS pattern | |
| β Multi-stage Docker build β Next.js standalone output saves ~200MB | |
| β Structured JSON logging with request-id β standard observability pattern | |
| β Middleware stack order β CORS β rate limit β auth β handler | |
| β Alembic migrations β same tool used in production Python backends | |
| β pydantic-settings for env validation β standard FastAPI pattern`}</CodeBlock> | |
| </div> | |
| ); | |
| } | |
| function SectionLimitations() { | |
| return ( | |
| <div> | |
| <H1>Known Limitations</H1> | |
| <P> | |
| These are deliberate simplifications made to keep the project manageable as a portfolio | |
| piece. Each one has a note on how it would be addressed in production. | |
| </P> | |
| <Table | |
| headers={["Limitation", "Current State", "Production Fix"]} | |
| rows={[ | |
| ["Data resets", "SQLite on HF Space resets on restart", "Set DATABASE_URL to Neon/Supabase PostgreSQL"], | |
| ["Single worker", "Uvicorn runs with 1 worker on HF free tier", "Multiple workers + Gunicorn, or Kubernetes pods"], | |
| ["No real-time market", "Investment values are static seeded data", "WebSocket feed from Alpha Vantage / Polygon.io"], | |
| ["No email/SMS", "Notifications are in-app only", "Twilio SMS, SendGrid email for critical alerts"], | |
| ["No 2FA", "Email + password only", "TOTP (Google Authenticator), SMS OTP"], | |
| ["AI rate limits", "Groq free tier: 30 req/min, may queue under load", "Paid tier, or multiple provider keys"], | |
| ["No audit log", "User actions not logged for compliance", "Append-only audit trail in separate table"], | |
| ["No account linking", "Only the seeded demo account exists per user", "Plaid / Open Banking API integration"], | |
| ["Session not persistent","Chat session IDs reset if localStorage cleared", "Store session_id server-side in DB"], | |
| ["Image OCR quality", "Tesseract OCR can fail on low-res images", "Google Vision API or AWS Textract"], | |
| ]} | |
| /> | |
| <H2>Reporting Issues</H2> | |
| <P> | |
| The GitHub repository is at{" "} | |
| <a href="https://github.com/mohsinkp02/Bankbot-AI" target="_blank" rel="noreferrer" | |
| className="text-emerald-500 underline"> | |
| github.com/mohsinkp02/Bankbot-AI | |
| </a> | |
| . Open an issue for bugs or feature suggestions. | |
| </P> | |
| </div> | |
| ); | |
| } | |
| // βββ Section registry βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const SECTION_COMPONENTS: Record<string, React.ComponentType> = { | |
| "overview": SectionOverview, | |
| "quickstart": SectionQuickStart, | |
| "how-it-works": SectionHowItWorks, | |
| "tech-stack": SectionTechStack, | |
| "features": SectionFeatures, | |
| "architecture": SectionArchitecture, | |
| "ai-engine": SectionAIEngine, | |
| "security": SectionSecurity, | |
| "database": SectionDatabase, | |
| "api": SectionAPI, | |
| "deployment": SectionDeployment, | |
| "use-cases": SectionUseCases, | |
| "vs-real-world": SectionVsRealWorld, | |
| "limitations": SectionLimitations, | |
| }; | |
| // βββ Main docs page βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export default function DocsPage() { | |
| const { theme } = useThemeStore(); | |
| const isLight = theme === "light"; | |
| const [activeSection, setActiveSection] = useState("overview"); | |
| const ActiveComponent = SECTION_COMPONENTS[activeSection] ?? SectionOverview; | |
| return ( | |
| <div className="flex h-[calc(100vh-4rem)] -m-8 overflow-hidden"> | |
| {/* ββ Left nav ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */} | |
| <div | |
| className="hidden lg:flex flex-col w-56 flex-shrink-0 border-r overflow-y-auto py-4" | |
| style={{ background: "var(--sidebar-bg)", borderColor: "var(--border)" }} | |
| > | |
| <div className="px-4 mb-3"> | |
| <div className="flex items-center gap-2"> | |
| <BookOpen className="h-4 w-4 text-emerald-500" /> | |
| <span className="text-sm font-bold" style={{ color: "var(--fg)" }}>Documentation</span> | |
| </div> | |
| <p className="text-[10px] mt-0.5" style={{ color: "var(--fg-subtle)" }}>BankBot AI v2.0</p> | |
| </div> | |
| <nav className="px-2 space-y-0.5"> | |
| {SECTIONS.map((sec) => { | |
| const isActive = activeSection === sec.id; | |
| return ( | |
| <button | |
| key={sec.id} | |
| onClick={() => setActiveSection(sec.id)} | |
| className={`w-full flex items-center gap-2.5 rounded-xl px-3 py-2 text-xs font-medium text-left transition-all ${ | |
| isActive | |
| ? isLight ? "bg-emerald-50 border border-emerald-200/80" : "bg-white/10 border border-white/10" | |
| : isLight ? "hover:bg-black/5" : "hover:bg-white/5" | |
| }`} | |
| style={{ color: isActive ? "var(--fg)" : "var(--fg-subtle)" }} | |
| > | |
| <sec.icon className={`h-3.5 w-3.5 flex-shrink-0 ${isActive ? "text-emerald-500" : sec.color}`} /> | |
| <span>{sec.label}</span> | |
| {isActive && <ChevronRight className="h-3 w-3 ml-auto text-emerald-500" />} | |
| </button> | |
| ); | |
| })} | |
| </nav> | |
| </div> | |
| {/* ββ Content βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */} | |
| <div className="flex-1 overflow-y-auto"> | |
| <div className="max-w-3xl mx-auto px-6 lg:px-10 py-8"> | |
| {/* Mobile section picker */} | |
| <div className="lg:hidden mb-6 flex flex-wrap gap-2"> | |
| {SECTIONS.map((sec) => ( | |
| <button | |
| key={sec.id} | |
| onClick={() => setActiveSection(sec.id)} | |
| className={`flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs font-medium transition-all ${ | |
| activeSection === sec.id | |
| ? "border-emerald-500/50 bg-emerald-500/10 text-emerald-500" | |
| : "" | |
| }`} | |
| style={activeSection !== sec.id ? { borderColor: "var(--border)", color: "var(--fg-subtle)" } : undefined} | |
| > | |
| <sec.icon className="h-3 w-3" /> | |
| {sec.label} | |
| </button> | |
| ))} | |
| </div> | |
| {/* Section breadcrumb */} | |
| <div className="flex items-center gap-2 mb-6 text-xs" style={{ color: "var(--fg-subtle)" }}> | |
| <BookOpen className="h-3.5 w-3.5" /> | |
| <span>BankBot AI</span> | |
| <ChevronRight className="h-3 w-3" /> | |
| <span className="text-emerald-500 font-medium"> | |
| {SECTIONS.find(s => s.id === activeSection)?.label} | |
| </span> | |
| </div> | |
| {/* Animated section content */} | |
| <AnimatePresence mode="wait"> | |
| <motion.div | |
| key={activeSection} | |
| initial={{ opacity: 0, y: 12 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| exit={{ opacity: 0, y: -8 }} | |
| transition={{ duration: 0.2, ease: "easeOut" }} | |
| > | |
| <ActiveComponent /> | |
| </motion.div> | |
| </AnimatePresence> | |
| {/* Next section nav */} | |
| <div className="mt-10 pt-6 border-t flex items-center justify-between" style={{ borderColor: "var(--border)" }}> | |
| {(() => { | |
| const idx = SECTIONS.findIndex(s => s.id === activeSection); | |
| const prev = SECTIONS[idx - 1]; | |
| const next = SECTIONS[idx + 1]; | |
| return ( | |
| <> | |
| {prev ? ( | |
| <button | |
| onClick={() => setActiveSection(prev.id)} | |
| className="flex items-center gap-2 text-xs transition-colors hover:text-emerald-500" | |
| style={{ color: "var(--fg-muted)" }} | |
| > | |
| <ArrowRight className="h-3.5 w-3.5 rotate-180" /> | |
| <div className="text-left"> | |
| <div style={{ color: "var(--fg-subtle)" }}>Previous</div> | |
| <div className="font-medium">{prev.label}</div> | |
| </div> | |
| </button> | |
| ) : <div />} | |
| {next ? ( | |
| <button | |
| onClick={() => setActiveSection(next.id)} | |
| className="flex items-center gap-2 text-xs transition-colors hover:text-emerald-500 text-right" | |
| style={{ color: "var(--fg-muted)" }} | |
| > | |
| <div> | |
| <div style={{ color: "var(--fg-subtle)" }}>Next</div> | |
| <div className="font-medium">{next.label}</div> | |
| </div> | |
| <ArrowRight className="h-3.5 w-3.5" /> | |
| </button> | |
| ) : <div />} | |
| </> | |
| ); | |
| })()} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |