One platform. Every local business.
Thikana is an all-in-one SaaS platform combining geo-based business discovery, no-code website building, inventory & order management, payments (Razorpay), and an AI-powered recommendation engine β all in one place.
- Project Overview
- Monorepo Structure
- thikana-api β FastAPI Recommendation Engine
- thikana-web β Next.js Frontend
- Full System Architecture
- Tech Stack
- Environment Variables
- Pricing Plans
Thikana solves a real problem: local businesses have no single digital home on the internet. Thikana gives any shop owner β a neighbourhood gym, family restaurant, or corner pharmacy β a complete digital presence with:
- π Geo-based Discovery β hyperlocal search via geohash indexing
- π No-Code Website Builder β drag-and-drop GrapesJS powered builder
- π³ Payments β Razorpay integration for products, bookings & subscriptions
- π Analytics β spending anomaly detection, predictions, and insights
- π€ Social Graph β follow businesses, curated post feed, "Who to Follow"
- π’ Franchise Management β multi-outlet dashboards and delegated access
- π¦ Inventory & Orders β full product catalog with order email notifications
technions-devally-2026/
βββ thikana-api/ # FastAPI recommendation & analytics backend (Python)
βββ thikana-web/ # Next.js 16 full-stack frontend (JavaScript/React 19)
The API is a pure Python FastAPI microservice responsible for:
- Computing personalised post feeds
- Building "Who to Follow" business discovery lists
- Running financial analytics (anomaly detection, spending insights, predictions, recommendations)
It follows a strict layered architecture β routes only route, all logic is in engine/ and models/.
flowchart TB
Client([Client / Next.js])
subgraph FastAPI["FastAPI App (main.py)"]
direction TB
MW[CORS Middleware]
RF["/feed Router"]
RD["/discovery Router"]
RA["/analytics Router"]
end
subgraph Engine["engine/"]
AS[assembler.py\nCoordinates data + scoring]
FE[fetcher.py\nDB reads only]
SC[scorer.py\nPure scoring logic]
end
subgraph Models["models/"]
AD[anomaly_detector.py]
SI[spending_insights.py]
ER[expense_recommender.py]
SP[spending_predictor.py]
end
subgraph DB["db/"]
FB[firebase.py\nLive Firestore]
MK[mock.py\nMock JSON data]
end
subgraph Config["config.py"]
CFG[USE_MOCK Β· MAX_RADIUS_KM\nSCORING WEIGHTS Β· GEOHASH_PRECISION]
end
Client --> MW --> RF & RD & RA
RF --> AS
RD --> AS
AS --> FE --> FB & MK
AS --> SC
RA --> AD & SI & ER & SP
Config -.-> AS & FE & SC
thikana-api/
βββ main.py # FastAPI app entry point, registers routers
βββ config.py # Single source of truth for ALL settings
βββ requirements.txt # Python dependencies
βββ conftest.py # Pytest configuration
β
βββ routes/ # HTTP layer ONLY β no business logic
β βββ feed.py # GET /feed/{user_id}
β βββ discovery.py # GET /discovery/who-to-follow/{user_id}
β βββ analytics.py # GET /analytics/* (4 endpoints)
β
βββ engine/ # Recommendation engine (Feed + Discovery)
β βββ assembler.py # Orchestrates fetcher + scorer
β βββ fetcher.py # All DB reads go here
β βββ geohash_utils.py # Geohash cell computation helpers
β βββ scorer.py # Pure stateless scoring (no I/O)
β
βββ core/ # Legacy engine (v1, kept for reference)
β βββ assembler.py
β βββ geohash_utils.py
β βββ scorer.py
β
βββ models/ # Financial analytics models
β βββ anomaly_detector.py # Statistical anomaly detection
β βββ spending_insights.py # Category + behavioral analysis
β βββ expense_recommender.py # Budget + saving recommendations
β βββ spending_predictor.py # Next-month WMA forecast
β
βββ db/ # Data access layer
β βββ base.py # Abstract DB interface
β βββ firebase.py # Live Firestore implementation
β βββ mock.py # Mock JSON implementation
β
βββ data/
β βββ mock_db.json # Local mock data for dev/tests
β
βββ tests/ # Pytest test suite
| Method | Path | Tag | Description |
|---|---|---|---|
GET |
/ |
Health | Health check β returns {status: "ok", version: "2.0.0"} |
GET |
/feed/{user_id} |
Feed | Personalised ranked post feed |
GET |
/discovery/who-to-follow/{user_id} |
Discovery | Nearby businesses to follow |
GET |
/analytics/anomalies/{user_id} |
Analytics | Detect unusual transactions |
GET |
/analytics/insights/{user_id} |
Analytics | Spending habits & actionable insights |
GET |
/analytics/recommendations/{user_id} |
Analytics | Budget & saving strategies |
GET |
/analytics/predictions/{user_id} |
Analytics | Next-month spending forecast |
Query Parameters for /feed/{user_id}:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
lat |
float | β | β | User's latitude (-90 to 90) |
lon |
float | β | β | User's longitude (-180 to 180) |
limit |
int | β | 20 | Max posts returned (1β50) |
Each post is scored using a weighted sum of three signals:
| Signal | Weight | Logic |
|---|---|---|
| Following | 55% | 1.0 if user follows the business, else 0.0 |
| Location | 35% | Linear decay from 1.0 at 0km to 0.0 at 10km (Haversine) |
| Recency | 10% | Linear decay from 1.0 (now) to 0.0 at 168 hours (7 days) |
score = (following Γ 0.55) + (location Γ 0.35) + (recency Γ 0.10)
flowchart LR
Post([Post candidate])
F{"Is business\nfollowed?"}
L[Distance\nHaversine km]
R[Hours old\nsince createdAt]
FS["following_signal\n1.0 or 0.0"]
LS["location_signal\nmax(0, 1 - dist/10)"]
RS["recency_signal\nmax(0, 1 - hrs/168)"]
SUM["score =\n0.55ΓF + 0.35ΓL + 0.10ΓR"]
OUT([Score β 0.0β1.0])
Post --> F --> FS
Post --> L --> LS
Post --> R --> RS
FS & LS & RS --> SUM --> OUT
Businesses are scored for the discovery list using two signals:
| Signal | Weight | Logic |
|---|---|---|
| Location | 70% | Linear decay 1.0 at 0km β 0.0 at 10km |
| Activity | 30% | postCount / 20 (normalised, capped at 1.0) |
flowchart LR
Biz([Business candidate])
D[Distance km\npre-computed]
P[postCount]
LS["location_signal\nmax(0, 1 - dist/10)"]
AS["activity_signal\nmin(postCount,20)/20"]
SUM["score =\n0.70ΓL + 0.30ΓA"]
OUT([Score β 0.0β1.0])
Biz --> D --> LS
Biz --> P --> AS
LS & AS --> SUM --> OUT
Four independent, stateless models in models/:
flowchart TD
TXN[(Transaction data\nFirestore / mock_db.json)]
subgraph Analytics["models/"]
AD["anomaly_detector.py\nβ’ category_spike\nβ’ rolling_spike\nβ’ rapid_succession\nSeverity: medium / high"]
SI["spending_insights.py\nβ’ spending_patterns\nβ’ category_analysis\nβ’ saving_opportunities\nβ’ behavioral_insights\nβ’ recommendations"]
ER["expense_recommender.py\nβ’ budget_suggestions\nβ’ timing_optimization\nβ’ saving_opportunities\nβ’ category_tips"]
SP["spending_predictor.py\nβ’ WMA forecast\nβ’ trend: increasing/stable/decreasing\nβ’ confidence: high/medium/low\nβ’ lower/upper bounds"]
end
TXN --> AD & SI & ER & SP
sequenceDiagram
participant Client
participant Route as routes/feed.py
participant Asm as engine/assembler.py
participant Fetch as engine/fetcher.py
participant Score as engine/scorer.py
participant DB as Firebase/Mock
Client->>Route: GET /feed/{user_id}?lat=&lon=&limit=
Route->>Asm: build_feed(user_id, lat, lon, limit)
Asm->>Fetch: get_following_ids(user_id)
Fetch->>DB: users/{user_id}/following
DB-->>Fetch: [biz_id, ...]
Asm->>Fetch: get_nearby_businesses(lat, lon)
Fetch->>DB: location_index (9 geohash cells)
DB-->>Fetch: {biz_id: distance_km}
Note over Asm: Union: followed βͺ nearby β self
Asm->>Fetch: get_posts_for_businesses(candidates)
Fetch->>DB: posts WHERE uid IN [...]
DB-->>Fetch: raw posts []
Asm->>Fetch: get_businesses_batch(candidates)
Fetch->>DB: businesses/{biz_id} batch
DB-->>Fetch: business metadata {}
loop For each post
Asm->>Score: score_post(post, following_set, lat, lon, biz_locations)
Score-->>Asm: float score β [0.0, 1.0]
end
Note over Asm: Sort DESC, deduplicate, slice top N
Asm-->>Route: posts[]
Route-->>Client: {user_id, count, posts[]}
sequenceDiagram
participant Client
participant Route as routes/discovery.py
participant Asm as engine/assembler.py
participant Fetch as engine/fetcher.py
participant Score as engine/scorer.py
participant DB as Firebase/Mock
Client->>Route: GET /discovery/who-to-follow/{user_id}?lat=&lon=
Route->>Asm: build_who_to_follow(user_id, lat, lon, limit)
Asm->>Fetch: get_following_ids(user_id)
Fetch->>DB: users/{user_id}/following
DB-->>Fetch: already-followed set
Asm->>Fetch: get_nearby_businesses(lat, lon)
Fetch->>DB: location_index (geohash cells)
DB-->>Fetch: {biz_id: distance_km}
Note over Asm: Filter out already-followed + self
Asm->>Fetch: get_businesses_batch(candidates)
Fetch->>DB: businesses metadata
DB-->>Fetch: business docs
loop For each candidate business
Asm->>Score: score_business_to_follow(biz, distance_km)
Score-->>Asm: float score
end
Note over Asm: Sort DESC, slice top N
Asm-->>Route: suggestions[]
Route-->>Client: {user_id, count, suggestions[]}
# 1. Navigate to the API directory
cd thikana-api
# 2. Create and activate a virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS/Linux
# 3. Install dependencies
pip install -r requirements.txt
# 4. Configure environment
# Copy .env.example to .env and fill in Firebase credentials (if USE_MOCK=False)
# For local dev, USE_MOCK=True in config.py uses data/mock_db.json
# 5. Run the server
uvicorn main:app --reload --port 8000
# 6. Interactive API docs
# http://localhost:8000/docsConfiguration knobs in config.py:
| Variable | Default | Description |
|---|---|---|
USE_MOCK |
True |
True = local mock JSON, False = live Firestore |
MAX_RADIUS_KM |
10.0 |
Businesses beyond this radius are ignored |
GEOHASH_PRECISION |
5 |
Precision-5 β 5Γ5 km cell |
RECENCY_WINDOW_HOURS |
168.0 |
7 days β posts older than this score 0 on recency |
POST_WEIGHT_FOLLOWING |
0.55 |
Weight of following signal for post feed |
POST_WEIGHT_LOCATION |
0.35 |
Weight of location signal for post feed |
POST_WEIGHT_RECENCY |
0.10 |
Weight of recency signal for post feed |
FOLLOW_WEIGHT_LOCATION |
0.70 |
Weight of location signal for "Who to Follow" |
FOLLOW_WEIGHT_ACTIVITY |
0.30 |
Weight of activity signal for "Who to Follow" |
The frontend is a Next.js 16 (App Router) full-stack application with React 19. It uses:
- Firebase for auth, Firestore, and Storage
- Algolia for search indexing
- Razorpay for payments
- Zustand for client-side state management
- Framer Motion for animations
- TailwindCSS v4 for styling
- A client-side recommendation engine in
hooks/useRecommendations.jsthat mirrors the Python scoring logic entirely in the browser (no server round-trip needed for feed)
flowchart TB
Browser(["Browser / User"])
subgraph Next["Next.js 16 App - thikana-web"]
direction TB
PUB["Public Pages\nHome / About / Pricing / Contact"]
AUTH["Auth Pages\nlogin Β· register"]
subgraph Dashboard["dashboard Route Group"]
DASH["/dashboard"]
FEED["/feed"]
PROFILE["/profile"]
SEARCH["/search"]
NOTIF["/notifications"]
MAP["/map"]
GST["/gst-reports"]
WEB["/websites"]
CREATE["/posts Β· /add-product\n/add-bulk-products"]
CART["/cart"]
end
subgraph API["app/api Route Handlers"]
APIFEED["/api/feed"]
APIDISC["/api/discovery"]
APIAI["/api/ai"]
RAZORPAY["/api/razorpay"]
MAPS["/api/maps-key"]
EMAIL["/api/send-order-email"]
CONTENT["/api/generate-content"]
end
end
subgraph Services["External Services"]
FB[("Firebase\nAuth + Firestore + Storage")]
ALG["Algolia\nSearch"]
RZ["Razorpay\nPayments"]
GMAPS["Google Maps\nAPI"]
GEM["Google Gemini\nAI"]
THAPI["thikana-api\nPython FastAPI"]
end
Browser --> PUB & AUTH & Dashboard
API --> FB & ALG & RZ & GMAPS & GEM & THAPI
Dashboard --> API
thikana-web/
β
βββ app/ # Next.js App Router
β βββ layout.js # Root layout (fonts, theme, auth, toaster)
β βββ page.js # Landing / Marketing homepage
β βββ globals.css # Global CSS variables & base styles
β β
β βββ (auth)/ # Unauthenticated route group
β β βββ login/page.jsx
β β βββ register/
β β βββ page.jsx # Step-based business registration
β β βββ user/page.jsx # User registration
β β
β βββ (dashboard)/ # Authenticated route group
β β βββ layout.jsx # Dashboard shell layout
β β β
β β βββ (with-recommendations)/ # Layout with Sidebar + WhoToFollow
β β β βββ layout.jsx # 3-col feed / 2-col default / 1-col profile
β β β βββ feed/ # Personalised post feed
β β β βββ map/ # Nearby businesses map view
β β β βββ notifications/ # Real-time notification centre
β β β βββ gst-reports/ # GST report generation
β β β βββ post/ # Individual post view
β β β βββ [username]/ # Public business profile by username
β β β βββ profile/ # My profile + sub-routes
β β β βββ page.jsx # Profile overview (176 KB β heavily featured)
β β β βββ analytics/ # Spending analytics dashboard
β β β βββ inventory/ # Product inventory management
β β β βββ services/ # Service listings
β β β βββ settings/ # Account & business settings
β β β
β β βββ (create)/ # Content creation
β β β βββ posts/ # Create new post
β β β βββ add-product/ # Add single product
β β β βββ add-bulk-products/ # CSV bulk product import
β β β
β β βββ cart/ # Shopping cart & checkout
β β βββ dashboard/ # Business dashboard home
β β βββ search/ # Algolia-powered search
β β βββ websites/ # Website builder
β β βββ [websiteId]/ # Builder canvas for specific site
β β
β βββ about/page.js # About page (animated)
β βββ pricing/page.js # Pricing plans
β βββ contact/page.js # Contact form
β β
β βββ api/ # Next.js Route Handlers
β βββ feed/ # Proxy to thikana-api /feed
β βββ discovery/ # Proxy to thikana-api /discovery
β βββ ai/ # Google Gemini AI endpoints
β βββ generate-content/ # AI content generation
β βββ razorpay/ # Payment order creation
β βββ create-product-order/ # Product checkout
β βββ send-order-email/ # Nodemailer order emails
β βββ send-order-status-email/# Order status update emails
β βββ update-order-status/ # Order lifecycle management
β βββ maps-key/ # Secure Google Maps key proxy
β
βββ components/ # React components
β βββ Navbar.js # Public marketing navbar (mobile-responsive)
β βββ MainNavbar.jsx # Dashboard top navbar
β βββ Sidebar.jsx # Left sidebar (profile + nav links)
β βββ WhoToFollow.jsx # Right sidebar (business suggestions)
β βββ PostCard.jsx # Post card with likes/comments
β βββ BasicInfoForm.jsx # Business registration step 1
β βββ BusinessInfoForm.jsx # Business registration step 2
β βββ UserBasicInfoForm.jsx # User registration
β βββ MapComponent.jsx # Leaflet map component
β βββ ProfilePage.jsx # Business public profile
β βββ PhotosGrid.jsx # Photo gallery grid
β βββ CartContext.jsx # Shopping cart state & logic
β βββ PaymentForm.jsx # Razorpay payment UI
β βββ ConnectRazorpay.jsx # Razorpay account connection
β βββ ImageUpload.jsx # S3 image upload component
β βββ ThemeSwitcher.jsx # Dark/light mode toggle
β β
β βββ auth/ # Auth-related components
β βββ builder/ # Website builder components (GrapesJS)
β βββ canvas/ # Builder canvas wrapper
β βββ form-builder/ # Drag-and-drop form builder
β βββ inventory/ # Inventory management components
β βββ product/ # Product display components
β βββ profile/ # Profile sub-components
β β βββ NearbyBusinessMap.jsx # Leaflet map for nearby businesses
β βββ registry/ # Business registry components
β βββ search/ # Algolia search UI components
β βββ ui/ # Radix UI primitive wrappers
β
βββ hooks/ # Custom React hooks
β βββ useAuth.js # Firebase auth context
β βββ useRecommendations.js # useFeed + useWhoToFollow (client-side engine)
β βββ useGetPosts.js # Firestore posts fetching
β βββ useGetUser.js # Current user data
β βββ useGetUserPosts.js # User's own posts
β βββ useLikePosts.js # Like/unlike actions
β βββ useAutosave.js # Builder auto-save
β βββ useBusinessIdForMember.js # Business ID resolving for team members
β
βββ lib/ # Utility libraries
β βββ firebase.js # Firebase client SDK init
β βββ firebase-admin.js # Firebase Admin SDK (server-side)
β βββ notifications.js # Full notification system
β βββ inventory-operations.js # Inventory CRUD with Firebase
β βββ website-operations.js # Website builder save/publish
β βββ followeringAction.js # Follow/unfollow business logic
β βββ firestoreWrites.js # Batch write helpers
β βββ geohash.js # Geohash encoding
β βββ date-utils.js # Date formatting utilities
β βββ business-utils.js # Business data helpers
β βββ business-user.js # Business-user relationship
β βββ userStatus.js # Online/offline presence
β βββ ai/ # AI-related libs
β βββ data/ # Static data / seed data
β βββ payment/ # Razorpay helpers
β βββ publish/ # Website publish logic
β βββ stores/ # Zustand stores
β βββ builderStore.js # Website builder state (23 KB)
β βββ formBuilderStore.js # Form builder state
β βββ chatStore.js # Chat state
β βββ historyStore.js # Builder undo/redo history
β βββ uiStore.js # Global UI state
β
βββ context/ # React context providers
β βββ ThemeContext.js # Dark/Light theme provider
β
βββ constants/ # App-wide constants
βββ utils/ # Pure utility functions
βββ public/ # Static assets
βββ next.config.mjs # Next.js configuration
βββ package.json # Dependencies & scripts
βββ biome.json # Biome linter/formatter config
flowchart LR
Root(["HOME /"])
About["/about"]
Pricing["/pricing"]
Contact["/contact"]
Login["/login"]
Register["/register"]
RegUser["/register/user"]
Dashboard["/dashboard"]
Feed["/feed"]
Profile["/profile"]
Analytics["/profile/analytics"]
Inventory["/profile/inventory"]
Services["/profile/services"]
Settings["/profile/settings"]
PubProfile["/:username (public profile)"]
Notif["/notifications"]
Map["/map"]
GST["/gst-reports"]
Search["/search"]
Cart["/cart"]
Posts["/posts"]
AddProd["/add-product"]
BulkProd["/add-bulk-products"]
Websites["/websites"]
Builder["/websites/websiteId"]
Root --- About
Root --- Pricing
Root --- Contact
Root --- Login
Root --- Register
Register --- RegUser
Root --- Dashboard
Dashboard --- Feed
Dashboard --- Profile
Profile --- Analytics
Profile --- Inventory
Profile --- Services
Profile --- Settings
Dashboard --- PubProfile
Dashboard --- Notif
Dashboard --- Map
Dashboard --- GST
Dashboard --- Search
Dashboard --- Cart
Dashboard --- Posts
Dashboard --- AddProd
Dashboard --- BulkProd
Dashboard --- Websites
Websites --- Builder
| Feature | Description | Tech |
|---|---|---|
| Business Registration | Multi-step form with MSME/GST/PAN verification | Firebase, React Hook Form, Zod |
| Feed | Ranked posts from followed + nearby businesses | useRecommendations.js, Firestore, Geohash |
| Who to Follow | Nearby businesses user doesn't follow yet | Haversine scoring, Firestore |
| Map Discovery | Interactive map of businesses within 10 km | Leaflet, React-Leaflet, Google Maps |
| Website Builder | No-code drag-and-drop site builder | GrapesJS, Zustand, Immer |
| Form Builder | Drag-and-drop form creation | dnd-kit, Zustand |
| Inventory Management | Product catalog with CRUD + bulk CSV upload | Papa Parse, Firestore |
| Order Management | Full lifecycle β pending β confirmed β delivered | Nodemailer (email), Razorpay |
| Payments | Razorpay checkout with signature verification | Razorpay SDK |
| Notifications | Real-time in-app + WhatsApp + Email notifications | Firestore onSnapshot, Nodemailer |
| Analytics Dashboard | Spending anomalies, insights, predictions | Recharts, thikana-api |
| GST Reports | Auto-generated GST compliance reports | jsPDF, jspdf-autotable |
| Algolia Search | Instant indexed search across businesses | Algolia InstantSearch |
| AI Content Generation | Auto-generate post captions / descriptions | Google Gemini AI |
| QR Codes | Business QR code generation | react-qr-code |
| Dark Mode | Full dark/light theme switch | next-themes, CSS variables |
| Mobile Responsive | Hamburger nav, responsive layouts | TailwindCSS v4 |
flowchart TD
Root["RootLayout (layout.js)\nThemeProvider Β· AuthProvider Β· Toaster"]
PRE["Public Routes\nNavbar + Footer"]
HOME["page.js\nLanding Page"]
ABT["about/page.js"]
PRC["pricing/page.js"]
DLAY["\(dashboard\)/layout.jsx\nMainNavbar"]
RLAY["\(with-recommendations\)/layout.jsx\n3-col | 2-col | 1-col"]
FEED_PAGE["/feed/page.jsx\nPostCard list"]
PROF["/profile/page.jsx\nFull business dashboard\nInventory Β· Analytics Β· Services Β· Settings"]
NOTIF["/notifications/page.jsx"]
MAP["/map/page.jsx"]
SRCH["/search/page.jsx"]
SB["Sidebar.jsx\nUser info + nav links"]
WTF["WhoToFollow.jsx\nuseWhoToFollow hook"]
NBM["NearbyBusinessMap.jsx\nLeaflet + Google Maps"]
BUILDER["/websites/\[id\]/page.jsx\nWebsite Builder Canvas"]
BST["builderStore.js\nZustand"]
Root --> PRE & DLAY
PRE --> HOME & ABT & PRC
DLAY --> RLAY
RLAY --> SB & FEED_PAGE & WTF
RLAY --> PROF & NOTIF & MAP & SRCH
SB --- NBM
DLAY --> BUILDER
BUILDER --- BST
flowchart LR
subgraph Zustand["Zustand Stores (lib/stores/)"]
BS[builderStore\nCanvas elements\nSelected el Β· Undo history\nPublish state]
FS[formBuilderStore\nForm fields\nDrag state]
HS[historyStore\nUndo / Redo stack]
USS[uiStore\nSidebar open state\nModal state]
CS[chatStore\nChat messages\nSocket]
end
subgraph Context["React Context"]
AUTH[AuthProvider\nuseAuth hook\nFirebase user state]
THEME[ThemeProvider\ndark/light mode]
CART[CartContext\nCart items\nTotal Β· Checkout]
end
subgraph LocalHooks["Custom Hooks"]
UF[useFeed\nPosts + scores]
UW[useWhoToFollow\nBusiness suggestions]
UP[useGetPosts\nFirestore pagination]
UL[useLikePosts\nOptimistic likes]
UAS[useAutosave\nBuilder debounced save]
end
sequenceDiagram
participant User
participant UI as Login/Register Page
participant Auth as useAuth Hook
participant FB as Firebase Auth
participant FS as Firestore
User->>UI: Enter credentials
UI->>Auth: signIn(email, password)
Auth->>FB: signInWithEmailAndPassword()
FB-->>Auth: UserCredential
Auth->>FS: getDoc(users/{uid})
FS-->>Auth: User profile data
Auth-->>UI: Authenticated user
UI->>UI: Redirect to /dashboard
flowchart TD
A(["User opens /feed"]) --> B["useAuth: get userId"]
B --> C["navigator.geolocation\nget lat / lon"]
C --> D["Firestore: users/uid/following\nGet following IDs"]
D --> E["Encode geohash, compute 9 neighbor cells"]
E --> F["Firestore: location_index/cell\nGet nearby business IDs"]
F --> G{"nearbyIds empty?"}
G -- Yes --> H["Fallback: scan all businesses\nHaversine filter <= 10 km"]
G -- No --> I
H --> I["Union: following + nearby - self"]
I --> J["Batch fetch business metadata\nfrom Firestore in groups of 10"]
J --> K["Batch fetch posts WHERE uid IN candidates\norderedBy createdAt DESC"]
K --> L["Score each post:\n0.55 x following + 0.35 x location + 0.10 x recency"]
L --> M["Deduplicate, sort DESC, slice top N"]
M --> N(["Render PostCard list"])
sequenceDiagram
participant User
participant Cart as CartContext
participant API as /api/razorpay
participant RZ as Razorpay
participant FB as Firestore
participant Email as /api/send-order-email
User->>Cart: Add product β Checkout
Cart->>API: POST /api/razorpay {amount, currency}
API->>RZ: Create Order (server-side)
RZ-->>API: {order_id, amount}
API-->>Cart: Razorpay order details
Cart->>RZ: Open Razorpay Checkout (client)
User->>RZ: Complete payment
RZ-->>Cart: payment_id, signature
Cart->>API: POST /api/razorpay (verify signature)
API-->>Cart: Payment verified β
Cart->>FB: Write order document
Cart->>Email: Send order confirmation email (Nodemailer)
Email-->>User: Order confirmation π§
flowchart LR
TRIG(["Trigger: Order / Follow / System"])
ADD["addNotification / sendNotificationToUser"]
FS[("Firestore\nusers/uid/notifications")]
SNAP["onSnapshot listener\nin notification page"]
UI(["Notification Bell + List"])
WA["sendWhatsAppNotification\nvia /api/notification-whatsapp"]
EM["sendEmailNotification\nvia /api/notification-email"]
TRIG --> ADD
ADD --> FS
ADD --> WA
ADD --> EM
FS --> SNAP --> UI
# 1. Navigate to the web directory
cd thikana-web
# 2. Install dependencies
npm install
# 3. Configure environment variables
# Create .env.local (see Environment Variables section below)
# 4. Run the development server
npm run dev
# β http://localhost:3000
# 5. (Optional) Seed sample posts to Firestore
node seed-posts.mjs
# 6. Lint and format
npm run lint # Biome check
npm run format # Biome format --writeflowchart TB
subgraph Client["Browser (User)"]
NC[Next.js Client Components\nReact 19]
end
subgraph NextServer["Next.js Server (thikana-web)"]
SC[Server Components\nSSR / RSC]
RH[Route Handlers\napp/api/*]
end
subgraph PyAPI["thikana-api (FastAPI)"]
FP[Feed + Discovery\nRecommendation Engine]
AP[Analytics Engine\nSpending Models]
end
subgraph Firebase["Firebase (Google Cloud)"]
AUTH[Firebase Auth\nJWT / Email+Password]
FS_DB[(Firestore\nPrimary DB)]
ST[Firebase Storage\nImages / Assets]
end
subgraph Algolia["Algolia"]
IDX[Business + Post\nSearch Index]
end
subgraph Razorpay["Razorpay"]
PAY[Payments API\nOrders + Webhooks]
end
subgraph Google["Google APIs"]
MAPS[Maps JS API\nGeolocation]
GEM[Gemini AI\nContent Generation]
end
subgraph Email["Email (Nodemailer)"]
SMTP[SMTP Server\nOrder Emails]
end
NC <-->|REST / WS| NextServer
NC -->|Client SDK| Firebase
SC -->|Admin SDK| Firebase
RH -->|HTTP| PyAPI
RH -->|SDK| Razorpay
RH -->|API Key| Google
RH -->|SMTP| Email
NC -->|InstantSearch| Algolia
| Layer | Technology |
|---|---|
| Runtime | Python 3.11+ |
| Web Framework | FastAPI 0.100+ |
| ASGI Server | Uvicorn |
| Validation | Pydantic v2 |
| Database | Firebase Firestore (via firebase-admin) |
| Spatial | pygeohash (geohash encoding) |
| Analytics | pandas, numpy, scipy, scikit-learn |
| Testing | pytest |
| Config | python-dotenv |
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI Library | React 19 |
| Styling | TailwindCSS v4 + Custom CSS |
| Animations | Framer Motion |
| Icons | Lucide React |
| UI Primitives | Radix UI (via shadcn) |
| State | Zustand + Immer |
| Forms | React Hook Form + Zod |
| Database | Firebase Firestore |
| Auth | Firebase Auth |
| Storage | Firebase Storage |
| Search | Algolia InstantSearch |
| Payments | Razorpay |
| Maps | Leaflet / React-Leaflet + Google Maps |
| AI | Google Gemini (@google/generative-ai) |
| Charts | Recharts |
| jsPDF + jspdf-autotable | |
| Nodemailer | |
| DnD | dnd-kit |
| Linter | Biome |
| Fonts | Bricolage Grotesque (headings) + Manrope (body) |
# Only needed if USE_MOCK=False in config.py
GOOGLE_APPLICATION_CREDENTIALS=../serviceAccountKey.json# Firebase Client SDK
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
# Firebase Admin SDK (server-side)
FIREBASE_SERVICE_ACCOUNT_KEY= # JSON string or path
# Algolia
NEXT_PUBLIC_ALGOLIA_APP_ID=
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=
ALGOLIA_ADMIN_KEY=
# Razorpay
RAZORPAY_KEY_ID=
RAZORPAY_KEY_SECRET=
NEXT_PUBLIC_RAZORPAY_KEY_ID=
# Google Maps
GOOGLE_MAPS_API_KEY=
# Google Gemini AI
GEMINI_API_KEY=
# Email (Nodemailer)
EMAIL_HOST=
EMAIL_PORT=
EMAIL_USER=
EMAIL_PASS=
# thikana-api URL
NEXT_PUBLIC_API_URL=http://localhost:8000| Plan | Price | Key Features |
|---|---|---|
| Starter | Free forever | Geo-discovery profile, No-code website builder, Razorpay payments, Up to 50 products, Basic order management, Notifications |
| Pro | $29/month | Everything in Starter + Custom domain & SSL, Unlimited products, Recurring subscriptions, Invoice management, Advanced analytics, Algolia priority search |
| Franchise | $99/month | Everything in Pro + Unlimited outlets, Delegated owner logins, Centralized franchise dashboard, Cross-outlet analytics, Webhook + API access, Dedicated onboarding |
| Enterprise | Custom | Contact Sales β white-labelling, B2B supplier integrations, custom SLA |
| File | Description |
|---|---|
thikana-api/API_DOCUMENTATION.md |
Full REST API reference with request/response examples |
thikana-api/FRONTEND_INTEGRATION.md |
Guide for frontend engineers integrating the recommendation API |
thikana-api/ANALYTICS_API_FRONTED_INTEG.md |
Analytics API frontend integration guide |
thikana-web/UI_DESIGN_SYSTEM.md |
Thikana's design tokens, typography, colour palette |
thikana-web/FRONTEND_INTEGRATION.md |
Frontend-specific API integration notes |
Β© 2026 Thikana Technologies Pvt. Ltd. β Built with β€οΈ for local businesses.