We Migrated a Family-Owned Jewellery Chain From Tally-Only to a Custom Web ERP — Here's the 90-Day Plan
A 6-store jewellery chain in Coimbatore moved from Tally Prime + 4 Excel sheets to a custom web ERP with hallmark traceability and live gold-rate tied billing. The 90-day extraction, dual-write, and reconciliation playbook.
Vivek Kumar
November 15, 202516 min read
0%
A 6-store family-owned jewellery chain in Coimbatore had been running on Tally Prime since 2009. Beautiful, conservative, audit-friendly — and increasingly the bottleneck. Inventory was a separate Excel per store. Hallmark BIS numbers were tracked in a third spreadsheet. Live gold rates were typed into an invoice template by a counter executive every morning at 10:15. The owner's son took over operations in March 2025 and gave us a brief: "build me a web ERP that does what Tally does, plus the four sheets, and ties to live gold rates. Do not break a single audit." We shipped in 90 days. This is the playbook.
6
Stores Across Coimbatore + Erode
16 yrs
Of Tally Data to Migrate
90 days
Discovery to Cutover
₹22.6L
Fixed-Price Build (Phase 1)
## The Answer in 60 Words
We extracted 16 years of Tally vouchers via the Tally ODBC + XML API, normalised them into a Postgres schema, ran a 4-week dual-write (every Tally entry also wrote to the web ERP), reconciled daily, and cutover on a Sunday at 11:14 pm. The web ERP runs on Next.js + Postgres + a Tally bridge written in Python. Cost: ₹22.6 lakh build, ₹38,000/month run.
## Why This Matters Now (For Indian Jewellery SMBs)
Three forces hit jewellery SMBs in 2025. First, [BIS hallmark mandatory traceability](https://www.bis.gov.in/) on 6-digit HUID makes Tally-only inventory an audit risk — every piece needs a separately searchable trail. Second, gold rates have become volatile enough that a 10:15 am rate is wrong by 11:30 am — cash-flow leaks were quietly opening. Third, customers under 35 expect a digital invoice with QR for the BIS number; they are checking it on the BIS Care app before they leave the store. The choice for SMBs is no longer "Tally vs ERP" — it is "Tally plus a custom layer" or "lose the next-gen customer."
We do not believe SMBs should rip out Tally. Tally is genuinely good at what it does (statutory accounting). The play is to build a web ERP that handles the parts Tally is bad at (multi-store inventory, hallmark traceability, live rates, customer portals) and bridge the two so the financial books still flow through Tally for the CA's audit.
## The Client (Specific Details)
- Sector: Jewellery retailer — gold, diamond, silver, kundan
- Location: Coimbatore (4 stores) + Erode (2), Tamil Nadu
- Stock value: ₹38 crore floating, ~14,000 SKUs
- Staff: 78 — 32 sales counter, 12 valuation/QA, 14 admin/back-office, 8 management, 4 IT/maintenance, 8 security
- Tally usage: Tally Prime 4.1, on-premise Windows server with 6 client installs, FY2024-25 had 240,000 vouchers
- The trigger: The CFO retired in February 2025. The new ops head asked her CA: "is the closing stock as of March 31 actually reconciled across all stores?" The CA answered: "It is reconciled in Tally. The Excel sheets do not always match." The owner gave us 90 days.
## The Architecture (Tally-as-Source-of-Truth Pattern)
📊
Tally Bridge (Python)
A Python service running on the in-store Windows box. Polls Tally's HTTP XML API every 90 seconds for new vouchers, pushes them to the web ERP via signed REST. Bidirectional — sales raised in the web UI write a voucher back to Tally.
🪙
Live Gold-Rate Service
Polls 3 sources (Mehrasons, Riddisiddhi Bullions, IBJA) every 90 seconds. Median rate becomes the "today's rate" for billing. Per-store override allowed with audit log.
🔍
HUID Hallmark Tracker
Each piece has a 6-digit BIS HUID. The web ERP maintains a per-piece ledger: BIS issuance date → store stock-in → display → sale → BIS verification on customer phone. QR on the invoice deep-links to BIS Care.
🛡️
Reconciliation Daemon
Runs nightly. Compares web ERP totals to Tally totals per ledger, per store. Drift greater than ₹100 raises a Slack alert to the ops head. We had drift on day 7. Found a manual Tally entry without a corresponding web sale. Fixed in 14 minutes.
## The Stack (And What We Picked Instead)
| Layer | Choice | Alternative | Why |
|---|---|---|---|
| Frontend | Next.js 14 + Tailwind | React + Vite | Server components made the 14,000-SKU search fast on counter terminals (mostly older Windows 10 boxes with 4 GB RAM). |
| Database | PostgreSQL 16 | MySQL | Audit trail was a hard requirement; Postgres' pgaudit extension and JSONB for hallmark history were the deciding factors. |
| Tally bridge | Python 3.11 + tdlserver XML | TallyConnect (paid) | The owner's CA was already familiar with Tally's XML API. The free path saved ₹3.4 lakh in licence and let us own the bridge. |
| Hosting | DigitalOcean Mumbai droplets | AWS Mumbai | Owner wanted single-cloud, single-vendor billing. DO's INR billing matched his preference for round-number monthly invoices. |
| Auth | Clerk | Auth.js | 78 staff with 5 role types. Clerk's organisation feature did 2 weeks of RBAC work for us. |
| Real-time | Pusher Channels | Supabase Realtime | Counter terminals are constantly subscribed to gold rate updates. Pusher's per-channel pricing fit better than usage-billed Supabase. |
## The 90-Day Plan (Copy This)
1
Days 1–9: Discovery + voucher-flow audit
Sat with the senior accountant for 4 days. Mapped every voucher type (Sales, Receipt, Purchase, Credit Note, Debit Note, Stock Journal, Manufacturing Journal). Counted 38 distinct voucher templates the firm used. Talked to 9 of the 32 counter staff. Took photos of the 4 Excel sheets and a paper register no one had mentioned (the security register that tracks pieces moving between display and vault).
2
Days 10–14: Schema design + Postgres setup
Designed 41 tables. The hardest one was `pieces` — a single physical jewellery item with a HUID, weight, purity, design code, current location (store/display/vault/sold), and a history of every state change. Insisted on event-sourcing for stock movements; the owner's CA insisted on idempotent voucher imports. Both constraints made it into the schema.
3
Days 15–28: Tally extraction (one-time)
Ran our Python ODBC + XML extractor across all 6 store servers, weeknight after 11 pm. Extracted 240,000 vouchers from FY2024-25 + 2.1 million from prior years for historical lookup. Total raw data: 3.4 GB of Tally XML. Normalised into Postgres in 4 batches. Initial reconciliation: drift of ₹0 on revenue totals per store per month. We celebrated for 30 minutes.
4
Days 29–42: Build the web ERP MVP
Three core surfaces — counter sales, stock movement, day-end close. The sales surface ships with a barcode scanner integration (most stores already had a USB barcode reader gathering dust from a 2019 attempt at a previous ERP). Day-end close generates a Tally voucher batch for the bridge to push.
5
Days 43–56: Build the Tally bridge + dual-write
The bridge writes to Tally for every web-side sale. The reverse — Tally entries pushed to the web — is a polling service. Both directions had to be idempotent. Tally voucher-numbering quirks burned 4 days. Fix: namespace web-originated voucher numbers (e.g. `SI/W/001` vs `SI/T/001`) so they cannot collide.
6
Days 57–70: Pilot at 1 store (Race Course Road)
Soft launch at the smallest store. 14 days of dual-write. Both Tally and web ERP recorded every transaction. Reconciliation script ran nightly. Drift on day 1: ₹3,400 (manual entry the bridge missed because it was added to a closed period). Drift on day 14: ₹0 for 5 consecutive days.
7
Days 71–84: Roll out to 5 more stores + train staff
3 days per store. Two trainers (the project lead + Manvi from QA) physically present. We ran the same dual-write window per store. The biggest store, RS Puram, had a senior counter staff member who was vocally skeptical. By day 4 he was demoing the gold-rate auto-fill to walk-in customers.
8
Days 85–87: Final reconciliation + cutover rehearsal
A 2-hour rehearsal on staging. Identified the 7 ledger pairs that needed special-case handling for the cutover (mostly closing-stock journals that the CA always ran manually).
9
Day 88: Cutover at 11:14 pm Sunday
Web ERP becomes the source of truth for new transactions. Tally bridge keeps pushing for the audit trail. Dual-write stayed on for another 60 days as a hedge. No incidents. Closing balances at month-end matched to the rupee.
## The Schema That Mattered (Pieces + Movements)
The hardest design decision was how to model a piece of jewellery. A single piece moves states constantly — vault, display, customer-trial, hold-for-customer, sold, returned, melted. The CA needed a daily ledger that summed correctly. The ops head needed live "where is this piece" lookup. We landed on event sourcing for movements, with a materialised view for current-state lookup.
sql
-- piece_movements is append-only
CREATE TABLE piece_movements (
id BIGSERIAL PRIMARY KEY,
piece_id BIGINT REFERENCES pieces(id),
from_location TEXT NOT NULL, -- 'vault.coimbatore.race-course'
to_location TEXT NOT NULL,
movement_type TEXT NOT NULL, -- 'transfer','sale','return','melt'
moved_by_user_id BIGINT NOT NULL,
voucher_id BIGINT, -- if part of a Tally voucher
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
metadata JSONB
);
-- materialised view: current location per piece
CREATE MATERIALIZED VIEW piece_current_location AS
SELECT DISTINCT ON (piece_id)
piece_id, to_location AS current_location, occurred_at AS as_of
FROM piece_movements
ORDER BY piece_id, occurred_at DESC;
CREATE UNIQUE INDEX ON piece_current_location (piece_id);
-- Refresh after every movement (or batched, every 90s)
REFRESH MATERIALIZED VIEW CONCURRENTLY piece_current_location;
The CA's audit team has since used piece_movements to reconstruct the location history of any piece on any date — something that was impossible with the Excel approach. They now ask for it instead of working around it.
## The Cost Breakdown (Real Numbers)
Run cost (steady state): DigitalOcean Mumbai droplets ₹14,000, Postgres-managed (DO) ₹8,200, Pusher Channels ₹3,400, Clerk Pro (78 users) ₹6,800, gold-rate API allowances ₹2,800, daily backups to S3 + offsite Wasabi ₹1,400, Sentry + Better Stack monitoring ₹1,400. Total: ₹38,000/month.
## The Outcome (Numbers That Mattered to the Owner)
₹0
Drift on Closing Stock at Month-End
14 → 1.5
Day-End Close Time (Hours per Store)
100%
HUID-to-Sale Traceability
~₹4.8L/yr
Recovered Gold-Rate Margin
The recovered margin came from auto-applied live rates. Pre-build, the counter executive's morning rate was used for the entire day, so afternoon rate spikes silently became margin loss to the firm. Post-build, the rate updates every 90 seconds, with a 12-minute customer-quote lock to keep the in-shop conversation honest.
## The Pre-Cutover Checklist (We Refuse to Run Without This)
Tally bridge runs in dual-write mode for ≥ 14 consecutive days with zero reconciliation drift > ₹100
HUID-to-piece mapping verified for every active SKU (counted manually at one store as a spot check)
Gold-rate failover tested — kill the primary source, confirm fallback to median of remaining 2 sources
All voucher templates round-trip through bridge — ie the CA can see a "web sale" voucher in Tally and it looks identical to a manual one
Day-end close report matches Tally's day book to the rupee, run twice on staging
Per-store admin can pause web ERP and revert to Tally-only for that store via one click (we have used it twice in 6 months — once for a network outage, once for a hardware fault)
Roll-back plan: Postgres point-in-time restore tested, Tally state preserved (we keep Tally as the audit-immutable source for 24 months post-cutover)
Customer-facing invoice prints HUID + BIS QR — verified scannable on 5 different Android phones
Counter staff trained on the piece-movement screen; spot-check passes before rollout
Backup script for Tally companies tested; restore time ≤ 15 minutes
## What We Deliberately Did Not Build
1. A customer-facing app. The owner wanted one. We pushed back hard. Customer-facing jewellery apps need photography pipelines, return-flow workflows, and a CRM that no SMB jeweller is operationally ready for. We shipped a customer-side WhatsApp invoice instead — every sale generates a PDF + WhatsApp message in 4 seconds. v2 candidate: a logged-in "my pieces" portal for customers.
2. AI-driven customer personalisation. A vendor pitched "AI predicts which customer will buy what" for ₹6 lakh extra. We declined for the client. With ~32 counter staff who know their regular customers by name, the human network beats any AI for the first 2 years of the build. Revisit when the chain crosses 12 stores.
3. Multi-currency support. The owner has cousins in Dubai and a vague export plan. We built USD/AED placeholders into the schema but did not ship the UI. Rule: do not ship a feature for a use case 12 months away. Re-evaluate in 2027.
## Common Mistakes (Each One Hurts)
Symptom: "Tally voucher numbers collide." Cause: web-originated and Tally-originated vouchers share the same numbering series. Fix: namespace them at the prefix (SI/W/ vs SI/T/) so the CA can tell which side a voucher originated from at a glance.
Symptom: "Closing stock differs by ₹X every month." Cause: a manual stock-journal entry the CA runs after-hours that the bridge has not seen. Fix: have the bridge poll for "recently modified vouchers" not just "new vouchers", and batch-process anything with a modified date in the last 24 hours. Or, better, ban manual after-hours entries during the dual-write window.
Symptom: "Gold rate spikes mid-customer-quote and the customer is angry." Cause: customer was quoted at 10:15 am rate, paid at 12:30 pm at 12:30 pm rate. Fix: lock the quote for 12 minutes from issuance. After 12 minutes, re-quote with the live rate. This is industry-standard for reputable jewellers; we matched it in software.
Symptom: "BIS HUID search returns 'not found' for valid pieces." Cause: HUIDs entered with leading zero variants. Fix: normalise to 6-digit string with leading zeros, both on entry and on search.
Symptom: "Counter staff bypass the new system at peak hours." Cause: the counter UI is slower than the muscle memory of typing in Tally. Fix: ship a one-keystroke "quick sale" mode that drops to a barcode-scan-and-quantity-only view. We added this in week 16 post-launch — adoption climbed from 64% to 93% in 11 days.
## A Detail That Saved Us On Day 67
A senior counter staff at the Erode-2 store called the project lead at 10:42 am: "the gold rate is showing ₹56,840 — Mehrasons site is showing ₹56,720." The bridge's median-of-3 logic had picked the wrong rate because Riddisiddhi Bullions had returned a stale value (cached from 8 minutes earlier). We added a "max staleness 90 seconds" filter on the rate sources, with auto-failover to the next source if the primary is stale. Three weeks later, IBJA's API went down for 22 minutes — the failover handled it without a human noticing.
## Where Custom ERP Fits In Our Wider Work
We have shipped variants of this Tally-bridge pattern for:
- A 14-branch diagnostics chain — see our March 2026 architecture writeup.
- An Ahmedabad textile exporter — see the 2.4M-row MySQL-to-Postgres migration.
- A 240-agent real-estate firm — see our Salesforce vs custom CRM analysis.
Tally-as-source-of-truth is a pattern that respects the CA's audit habits. Every Indian SMB build we ship in finance-adjacent verticals starts here. Founder-essay version of why we make this trade-off lives at viveksinra.com.
## A Common Question About Long-Term Maintenance
Tally is a moving target. Tally Prime 5.0 is on the roadmap, GST 2.0 ships April 1 2026 (we covered the 6 software changes in our March 2026 checklist), and the XML schema occasionally adds non-backwards-compatible fields. We staff 4 hours/month of bridge maintenance into the run contract. In 18 months of running similar bridges across 4 clients, we have spent ~8 hours total on Tally Prime upgrade compatibility. Cost is real but bounded.
## FAQ
### Why not just buy a jewellery-specific ERP?
We considered three (Synergics, Aaron, Logic). Their lowest-tier subscription was ₹4.8 lakh/year for 6 stores, with 2-week onboarding and a roadmap controlled by the vendor. Custom build costs more upfront (₹22.6 lakh) but the owner controls the roadmap, owns the data, and pays no per-user fee. Payback vs Synergics at our cost level: 4.7 years. The owner's framing: "I would rather own the software than rent it."
### Can the bridge work with Tally on cloud?
Yes — Tally Cloud's HTTP XML API works the same. We've tested it. The polling latency is slightly higher (avg 3.4s vs 0.6s for on-prem) but the developer experience is otherwise identical.
### What about the audit trail for the tax authorities?
Tally remains the immutable source for accounting. Every web-originated transaction lands in Tally with a "source: web-erp" tag in the narration. The CA can audit Tally as before. We have run two CA-led audits since cutover; both passed without queries.
### How did you handle migration of the 4 Excel sheets?
For each sheet (display inventory, vault, hallmark issuance log, manual gold-rate book), we wrote a one-time importer that read the latest snapshot, normalised it into the relevant Postgres table, and asked the senior accountant to approve a sign-off PDF. Total: 6 days of effort across 4 sheets.
### What was the team composition?
Three engineers (one senior on the bridge and reconciliation, one mid on the Next.js ERP, one junior on the gold-rate service and HUID tracker), one designer at 0.4 FTE, one QA at 0.5 FTE, and the project lead at 0.3 FTE. Plus 8 weeks of a Tally bridge specialist who had built similar bridges at 3 prior firms.
### Did the CA push back on the migration?
Heavily, in week 1. By week 6 (after the dual-write demo), he was the project's strongest internal advocate. What turned him: showing him that Tally remained the audit source and the web ERP only added information, never removed it.
### Can we add a customer-facing portal in v2?
Yes, and the schema is ready for it. The piece-movement event sourcing means a "track my piece" customer experience is straightforward. We are quoting v2 separately because the customer-facing layer needs different security review and a customer-support workflow that does not exist today.
### What happens if Tally goes down?
The web ERP keeps running. The bridge queues outbound vouchers to a Postgres outbox table; when Tally comes back, they replay in order. We tested this for 4 hours of simulated downtime. Zero data loss.
Have a legacy Tally setup you want extended into a custom ERP?
We migrate Tally-only operations to custom web ERPs for Indian SMBs in retail, manufacturing, and trading verticals. Typical project: ₹18–35 lakh, 12–18 weeks, fixed scope. The CA stays in the room from day one. The first call is free; we will tell you whether your business is ready or whether you should stay on Tally for another year.