top of page
Search

I Talked to AI for 2 Weeks. It Built India's Fabric Marketplace. I Just Asked the Right Questions.

  • 4 days ago
  • 9 min read

Written by Shivam Dube - AI, Technology Analyst. 



01 · Why did FabricBazaar Marketplace?  



I built FabricBazaar — India's fabric Marketplace for sarees, kurtas, bed sheets, and handloom textiles. No CS degree. No team. No startup funding. Just a clear idea, Claude as my AI pair programmer, and a willingness to iterate fast.


India's textile industry is one of the largest in the world — and almost none of it is accessible online in a trustworthy, organised way. Weavers from Varanasi, block-print makers from Jaipur, silk sellers from Kanchipuram — all selling on WhatsApp or Instagram, buried on undiscoverable general marketplaces.


▪  WHAT I WANTED TO BUILD in India's Fabric Marketplace?


  • Focused exclusively on Indian fabrics — no noise, no distractions

  • Verified sellers publicly with a trust badge system

  • All Indian payment methods — UPI, cards, wallets, net banking, Cash on Delivery

  • Real-time order tracking with OTP-confirmed delivery

  • Worked for every state in India — not just four

  • Real seller analytics so they could actually grow their business


02 · The Stack

I didn't choose the stack analytically. I described the product and Claude recommended it. Flask over Django — lighter, faster to prototype, every route is a single function you can read in one pass.


Tool

Technology

Why

Backend

Flask 3.1 (Python)

Lightweight, readable, every route is a function. The AI writes cleaner Flask than Django — less magic to debug.

Database

SQLAlchemy + PostgreSQL

SQLite locally, PostgreSQL in production. Should have been PostgreSQL from day one — concurrent writes can corrupt SQLite.

Payments

Razorpay SDK

UPI, Cards, Wallets, Net Banking — all Indian payment rails in one SDK. The only real choice for India.

Hosting

Connect GitHub, add env vars, deploy. Free PostgreSQL. Auto-deploys on every git push.

AI Engine

Claude (Anthropic)

Wrote every line of code, designed architecture, ran security audit, wrote 161 tests, found the ₹1 bug.

Security

Flask-WTF + Bcrypt + Limiter

CSRF on every form. Bcrypt password hashing. Rate limiting on auth and cart routes.


No Flask-SQLAlchemy magic methods. No shortcuts. Every abstraction built explicitly so I could understand and debug it completely. This paid off enormously when tracking down the stock race condition.



03 · How It Got Built?



The best prompt is a problem statement, not a technical instruction. 'I want sellers to upload product photos' produces better code than 'write a Flask route that accepts multipart/form-data.'

— learned after hundreds of Claude conversations


Phase

What Got Built

Phase 1

Core Architecture  ·  One prompt, entire skeleton

Described the marketplace in a single paragraph. Got back complete folder structure, all data models, all 15 blueprints. Four user roles with separate dashboards and access decorators in one session.

Phase 2

Shop + Cart + Search  ·  Feature by feature

Product listings with multi-field search. Filter panel: category, price range, seller. Sort: newest, price, featured, popular. Paginated 12/page. Guest cart with session storage that merges into DB on login.

Phase 3

Razorpay Checkout  ·  The most important phase

Full checkout with all 36 Indian states, 6-digit PIN validation. Razorpay order creation. HMAC-SHA256 server-side signature verification. CoD fraud prevention: blocked above ₹5,000 and if 2+ pending CoD orders. THIS IS WHERE THE ₹1 BUG WAS HIDING.

Phase 4

Tracking + Delivery + OTP  ·  Logistics layer

Auto-assign delivery partner by state — all 36 states and UTs mapped (was originally only 4). OTP-based delivery confirmation using secrets.randbelow(). Real-time tracking timeline with 9 status states.

Phase 5

Seller Dashboard + Analytics  ·  The seller experience

Company profile with GST/PAN, logo upload (MIME-verified). Product management with all toggles. Analytics: revenue by day, orders by status, top 10 products. Seller data isolation — sellers see only their own orders.

Phase 6

Security Audit + Deep Testing  ·  Where everything changed

Uploaded full codebase. Asked: what is broken, insecure, and would embarrass in production? Found 14 issues. Then 161 test cases across 8 categories. Found race conditions, insecure OTPs, monkey-patched columns, missing templates, and the ₹1 bug.




04 · Bugs, hmm ...


These weren't edge cases. Some would have caused immediate financial damage or permanently destroyed buyer trust if they had reached real customers.


▪  BUG #1 — THE ₹1 PAYMENT BUG

🐛  CRITICAL  Every Razorpay payment charged exactly ₹1 regardless of cart total

Razorpay takes amount in paise — 100 paise equals ₹1. The checkout code had amount: 100 hardcoded. A buyer purchasing a ₹4,000 Kanjivaram silk saree would be charged ₹1. Would have surfaced on the very first real transaction.


  ●  ●  ●   routes/checkout.py — the one-line fix

- amount_paise = 100                              # ₹1 always — completely broken

+ amount_paise = int(float(order.total) * 100)    # correct paise conversion


✅  Fixed  One line + HMAC-SHA256 server-side verification added

Also added hmac.compare_digest() constant-time signature check so payment callbacks cannot be faked. Any mismatch now logs the client IP as a potential fraud attempt. Found only because of a security audit.


▪  BUG #2 — LAST-ITEM RACE CONDITION

🐛  HIGH  Two buyers could simultaneously purchase the last item in stock

Without a database row lock, two concurrent checkouts could both read stock = 1, both decrement it, both succeed — leaving stock at -1. Classic concurrency problem invisible in single-user development.


  ●  ●  ●   routes/checkout.py — adding the DB row lock

- p = Product.query.get(product.id)

+ p = Product.query.with_for_update().filter_by(id=product.id).first()

  # with_for_update() → DB row lock until transaction commits


▪  BUG #3 — HARDCODED CREDENTIALS IN SOURCE CODE

🐛  CRITICAL  Live Razorpay keys hardcoded directly in config.py

Original config.py had live Razorpay credentials, a personal UPI ID, and the Flask secret key all as plain string literals. Anyone who cloned the repository could charge transactions to the Razorpay account immediately.


  ●  ●  ●   config.py — before and after

# ❌ Original — DO NOT DO THIS

- RAZORPAY_KEY_ID     = "rzp_test_SPBHWeZf5cvbyY"

- RAZORPAY_KEY_SECRET = "Qt6KtjlDp8i6IhZ6BhAT9D41"

- SECRET_KEY          = "fabricbazaar-secret-key-2024"


# ✅ Fixed — all secrets from environment variables

+ RAZORPAY_KEY_ID     = os.environ.get('RAZORPAY_KEY_ID', '')

+ RAZORPAY_KEY_SECRET = os.environ.get('RAZORPAY_KEY_SECRET', '')

+ SECRET_KEY          = os.environ.get('SECRET_KEY') or secrets.token_hex(32)


✅  Fixed  .env file + .gitignore + production warnings

Added .env.example template, .gitignore excluding .env and *.db, and a ProductionConfig.init_app() that logs a loud warning if Razorpay keys or SQLite are detected at production startup.


▪  BUG #4 — DELIVERY ONLY COVERED 4 STATES

🐛  BUSINESS LOGIC  Only Maharashtra, Karnataka, Chhattisgarh, and Goa had delivery routing

Every other buyer in India had their order routed to a single fallback rider. That is 32 states and UTs with no proper delivery coverage for a marketplace claiming to serve India nationally.


✅  Fixed  Expanded STATE_PARTNER_EMAIL to all 28 states + 8 Union Territories

One Python dictionary mapping every Indian state and UT to a dedicated delivery partner email. Expanding from 4 to 36 required adding 32 dictionary entries and updating the seed file.


▪  BUG #5 — PREDICTABLE DELIVERY OTPS

🐛  SECURITY  OTPs generated with Python's non-cryptographic random module

random.randint(100000, 999999) is seeded from system state and is not cryptographically unpredictable. A sophisticated attacker could potentially calculate upcoming OTP values.


  ●  ●  ●   models/delivery.py

- import random

- return str(random.randint(100000, 999999))

+ import secrets

+ return str(secrets.randbelow(900000) + 100000)  # cryptographically secure


▪  BUG #6 — MONKEY-PATCHED DATABASE COLUMNS

🐛  MIGRATIONS  seller_reply columns defined outside class — invisible to Alembic

The seller_reply and seller_replied_at columns were added as module-level statements after class definitions. Alembic scans class bodies to detect schema changes — it could not see these. Every fresh deployment would silently be missing those columns.


✅  Fixed  Columns moved inside class definitions — also fixed loyalty double-award and missing templates

Also fixed in the same session: loyalty points double-award guard (idempotency check), duplicate email registration crash, two missing templates (wishlist.html and admin/settings.html), and missing rate limits on cart endpoints.


▪  BUG #7 — RENDER FREE TIER HAS NO SHELL

🐛  DEPLOYMENT  Deployed to Render free tier — database empty, no way to run seed.py

After deployment, the database was completely empty. To populate it you would normally run 'python seed.py' — but Render's free plan has no shell access. The app was live and totally blank with no obvious fix.


  ●  ●  ●   start.sh — auto-seed on first boot

#!/bin/bash

# Check if DB is empty → seed automatically → start gunicorn

python -c "

from app import create_app, autoseed_if_empty

app = create_app('production')

autoseed_if_empty(app)  # skips if User.query.count() > 0

"

gunicorn "app:create_app('production')" --workers 2 --bind 0.0.0.0:$PORT


✅  Fixed  start.sh seeds automatically if database is empty — no shell, no upgrade needed

On every server boot: check User.query.count(). If zero — fresh deployment — run seed.py. If non-zero — data exists — skip. Safe to restart as many times as needed. Works on the free tier with no upgrade required.


05 · Security Audit Findings


The audit was a single conversation where the full codebase was uploaded and the question asked was: what is broken, insecure, and would embarrass in production?


Finding

Severity

Status

Razorpay credentials hardcoded in config.py

HIGH

Fixed

Flask SECRET_KEY hardcoded as plain string

HIGH

Fixed

Razorpay amount hardcoded to 100 paise (₹1)

HIGH

Fixed

No rate limiting on login or register routes

HIGH

Fixed

No HMAC verification on Razorpay callback

HIGH

Fixed

Stock decrement has no DB row lock

MEDIUM

Fixed

Delivery OTP uses random (not secrets)

MEDIUM

Fixed

File upload checks extension only — no MIME type verification

MEDIUM

Fixed

No security HTTP headers on responses

MEDIUM

Fixed

SESSION_COOKIE_SECURE not set in production

MEDIUM

Fixed

Login error reveals whether email exists

LOW

Fixed

No rate limiting on cart add endpoint

LOW

Fixed

Razorpay webhook not implemented

MEDIUM

Roadmap P1

Admin panel has no 2FA

MEDIUM

Roadmap P2


06 · Numbers & SWOT


Metric

Value

Metric

Value

Lines of Python

5,959

HTML Templates

90+

Route Blueprints

15

Data Models

10

Test Cases

161

Tests Passing

160 (99%)

Security Issues Found

14

Issues Fixed

12/14

States Covered

36 (all India)

Cost to Build

₹0


SWOT Analysis


STRENGTHS

  • Niche Indian textile focus — no marketplace noise

  • Full multi-role: Buyer, Seller, Admin, Delivery

  • Razorpay: all Indian payment rails in one SDK

  • OTP-confirmed delivery with real-time tracking

  • Seller analytics: revenue, orders, top products

  • CoD fraud prevention built-in

  • SEO: OG, Twitter Card, JSON-LD structured data

  • 161 security + logic tests, 160 passing

WEAKNESSES

  • No email notifications — on-screen only

  • No Razorpay webhook — client-side verify only

  • No mobile app — web only

  • Flask-Limiter in-memory — resets on restart

  • SQLite still default if DATABASE_URL not set

OPPORTUNITIES

  • ONDC integration — national reach, zero CAC

  • B2B wholesale portal — MOQ, bulk pricing, GST invoices

  • WhatsApp Business API for notifications

  • Weaver-direct GI-tag certification at premium pricing

  • AI fabric matching — photo-based recommendations

  • Government ODOP and handloom scheme alignment

THREATS

  • Amazon India and Flipkart ethnic wear categories

  • Meesho — cracked Tier-2/3 fabric reselling

  • Instagram/WhatsApp seller disintermediation

  • Render free PostgreSQL expires after 90 days

  • Low switching cost — no strong lock-in yet


07 · Lessons — What Vibe Coding Taught Me?


1

Add .env to .gitignore before writing line one

Not before pushing to GitHub. Before writing anything. Credentials in source code is not a beginner mistake — it is catastrophic. The original config had live Razorpay keys in plain text. One public repo push and it is over.

2

PostgreSQL from day one, not SQLite

SQLite is a single file. Perfect for local development. The moment two users touch your app simultaneously it can corrupt data. Set up Render PostgreSQL on day one — it is free, takes five minutes, and you never think about it again.

3

Describe the product, not the code

'I want sellers to upload product photos' produces better code than 'write a Flask route that accepts multipart/form-data.' The AI knows the implementation. You know the product. Stay in your lane.

4

Ask for audits more than features

The most valuable sessions were not building features — they were uploading the full codebase and asking what is broken, insecure, and would embarrass in production. That is how the Rs. 1 payment bug was caught.

5

Test every user journey manually before calling it done

Automated tests catch code errors. Manual walkthroughs catch product errors — like the missing wishlist template that caused a silent 500 error only when a logged-in buyer visited their wishlist for the first time on a fresh deployment.

6

Know your hosting limits before deploying

Render free tier: no shell, 15-minute spin-down, 90-day PostgreSQL expiry. None are dealbreakers, but all need workarounds planned in advance. The shell problem was solved with the auto-seed startup script.


Vibe coding is real software development. It just inverts where the thinking happens. You think about the product, users, and business logic. The AI thinks about syntax, patterns, and implementation. That is a genuinely good division of labour if you stay in your lane.

— FabricBazaar Team · Raipur, Chhattisgarh


08 · Roadmap


Pri

Feature

Description

P1

Razorpay Webhook

Server-side payment event verification — more reliable than client-side callback alone, protects against network failures during payment

P1

Email Notifications

Order confirmations, shipping updates, OTP delivery via SendGrid — currently everything is shown on-screen only

P1

ONDC Integration

India's Open Network for Digital Commerce — national buyer reach with zero marketing spend

P2

B2B Wholesale Portal

MOQ pricing, bulk order workflows, GST invoice generation for garment manufacturers — the fabric industry's real volume

P2

WhatsApp Business API

Order notifications, seller chat, and re-marketing via WhatsApp — where India's buyers actually live

P3

Android App + UPI Deep Links

Native mobile for Tier-2/3 city buyers who shop exclusively on phones — better conversion than responsive web

P3

AI Fabric Matching

Photo or occasion-based recommendations — 'find me something for a winter wedding in Rajasthan'



Try It Live Now ...



FabricBazaar is live at marketplace-fk8b.onrender.com.


Browse, log in as any role, test the full checkout flow.


Role

Email

Password

Access

Admin

Admin@1234

Full platform control

Seller

Seller@1234

Seller dashboard

Customer

Customer@1

Buyer experience



Images show samples of fabrics, sarees, etc. available on Fabric Bazar for Sale.





 
 
 

Comments


bottom of page