Good's Clothing · Đà Nẵng · paying client, live in production

A clothing shop runs its whole day on this

6,874 customers and four years of order history now live in software I built for a Đà Nẵng clothing shop — and a customer profile that used to take 18 seconds to open now opens in under one.

crm.shopgoods.vn
🔒Client system · behind a loginReal customer data — screens available on request
6,874
customers under management
18s → 1s
to open a customer profile
3,252
corrupted records repaired automatically
78
tests that must pass before any deploy

6,874 customers, 4,076 orders and 49 monthly spreadsheets covering four years — that was the shop's entire memory of its own business, and none of it could answer the one question the owner actually asked: who should we message today?

The problem nobody had written down

Good's Clothing is a fashion retailer in Đà Nẵng. Like most small shops here, it ran on a Google Sheet: one tab per month, back to June 2022, filled in by whoever was on shift. The shop already had a point-of-sale system that handled money perfectly well. What it did not have was a memory of people.

So the real problems were never the ones I was first told about:

  • "We want a CRM" actually meant we cannot tell who has stopped buying from us.
  • "The numbers don't match" actually meant staff type the same order in two places and nobody knows which one is true.
  • "It's slow" actually meant opening one customer takes 18 seconds, so nobody ever opens one.

I spent the first week not writing code. I read four years of their sheet, counted 1,785 unique phone numbers hiding behind 7,973 order rows, and wrote down what the data could and could not support. Half the features on the original wish list were impossible, because the data to power them had never been collected. Saying that out loud on day five was the most valuable thing I did on the whole project.

The brief said "CRM". The job was "give the shop a memory of its customers, and never contradict the till."

What I built

A staff-facing web app that sits beside the point-of-sale system rather than replacing it. The till still owns the money. My system owns the relationship.

  • Khách 360 — one screen per customer: every order, every channel they've messaged on, what they bought, what they returned, when they last spoke to anyone.
  • A customer-care reminder engine — the daily list of who to message and why, now in its third version, with a feedback and up-sale window per order instead of a blanket rule.
  • Đối soát (revenue reconciliation) — the screen that finds orders where the sheet, the till and the actual money received disagree, and shows the gap in đồng rather than in adjectives.
  • Loyalty tiers, product merge, an image validator, mobile layouts, and self-serve Google sign-in so the owner can add staff without calling me.
  • A two-way sync with the shop's own Google Sheet, because taking the sheet away would have killed the project on week one. Staff keep working exactly as they always did.

The two hardest parts were invisible from the outside. First, 113 products had to sync live with zero data loss, which meant 8 of 8 SKU, colour and price mapping checks passing before I would let it near production. Second, the sheet is edited by humans, so the software has to survive humans.

Where the AI actually went

I am not a developer. I use AI the way a manager uses a team — and the useful parts were rarely "write me this function".

  • Reading four years of a stranger's spreadsheet. I had a model classify every one of 49 monthly tabs, flag the columns that changed meaning over time, and produce a list of contradictions for me to rule on. That is a week of human work compressed into an afternoon, and it is checkable — every claim it made, I could grep for.
  • Turning "the numbers look wrong" into a testable rule. Staff complaints arrive as feelings. I used AI to draft candidate rules, then wrote code that tested each rule against all 49 tabs. Rules that failed on real data were deleted, not argued about.
  • Repairing data at a scale I could never do by hand. 3,252 corrupted customer records were auto-corrected and 2,606 ghost rows purged, each with a dated backup written first.
  • Where AI was deliberately kept out: anything that decides money. The reconciliation logic is plain, boring, readable code. If a model had written a number, I could not have defended it to the owner — and I would have had to.

The habit underneath all of it: AI drafts, code verifies, and a human signs. Every AI-produced rule ends up as a test that runs forever afterwards.

The unglamorous part I am most proud of

Staff merge cells in spreadsheets. Not occasionally — constantly, in eighteen different columns, in three different patterns, roughly 19,500 merged cells across the file. Two separate production incidents came out of that habit, and the fix was never "tell the staff to stop".

So the software learned to tolerate it: a parser tested against 18 columns × 3 merge types, 56 of 56 checks passing, plus a splitter that takes one merged payment cell covering several orders and divides it proportionally, then flags what it did so a human can look. The shop changed nothing. The software absorbed the mess. I wrote the whole incident up in this post.

What it cost the shop and what it returned

BeforeAfter
Open one customer's history18 secondsUnder 1 second
Know who to message todayNobody knewA daily list, with the reason
Orders that silently disagreeInvisibleListed, in đồng, on one screen
Corrupted or ghost records5,858 sitting in the dataRepaired or purged, with backups
Confidence in a deployHope78 automated tests, red means it does not ship

The engagement was a 10,000,000 VND build, then ongoing support. The system has been live in daily use since July 2026, on the shop's own domain, behind staff login.

What I would do differently

Three honest things.

  1. I built features before I had earned trust in the data. The first reminder engine went out while the underlying records were still dirty, so the shop's first impression of it was a list with wrong names on it. Data first, features second — always, even when features are what got you hired.
  2. I let "preview" and "production" share one database for too long. It made testing convenient and it made one bad afternoon much worse. They are separated now, and the deploy gate refuses to run if the target is ambiguous.
  3. I assumed staff would read a message asking them to change how they type. They did not, and they were right not to. Software should absorb the human habit, not audit it.

The transferable part

Most small businesses are not missing software. They are missing a memory, and they are drowning in a spreadsheet that three people edit differently. If that sounds familiar, the shape of the fix is the same wherever the business is: leave the tool people already trust in place, build the memory beside it, and prove every number before you show it to anyone.

Client
Good's Clothing, a fashion retailer in Đà Nẵng
Engagement
10,000,000 VND build, then ongoing support
Live at
crm.shopgoods.vn (staff login required)
Built with
Cloudflare Pages · Cloudflare Workers · Neon Postgres · Hyperdrive · Cloudflare Access · Google Sheets sync · Zalo and Pancake channels
Timeline
First commit to production in about 12 weeks, 420 commits
My role
Everything — problem definition, product decisions, build, data migration, QA, handover
Got something like this? Tell me what's broken.