Skip to main content

02 / WORK / CASE STUDY

AI Nail Platform

From AI nail recognition and AR try-on to designer marketplace, CRM and POS.

TYPE
FULL STACK
SCOPE
AI × AR × Commerce × POS
STACK
AI · AR · DJANGO · REACT · B2B
LINKS
Internal project (private)

01 / PROBLEM

One platform, two faces: consumers get AI nail recognition and AR try-on; merchants and internal teams get an operations console covering products, orders, inventory, B2B quoting and settlement, promotions and finance. This case study covers what can be shared today — the ops console frontend, spanning ~50 business modules.

02 / CONSTRAINTS

  • A commercial, closed-source project; business details stay private.
  • The scope is huge and still growing: one SPA has to hold the line on bundle size, consistency and maintainability.
  • Frontend and backend share no types: the API contract survives on conventions and centralized error normalization.

03 / ARCHITECTURE

The platform is multiple services: a main business API (Django REST Framework) plus a standalone approval microservice. The ops console is a React 18 + Ant Design SPA — ~600k lines, a service layer split into 128 domain files with 1,951 API call sites, and components organized into 50+ module folders.

Cross-cutting concerns converge in a single Axios interceptor layer: automatic JWT attachment, a 401 refresh queue, global 403 broadcasting, deduped error toasts, and json-bigint for numeric precision. In-browser object detection runs on TensorFlow.js, auth supports WebAuthn/Passkey, 30+ feature flags gate functionality, and CI enforces a bundle-size budget.

04 / RESPONSIBILITIES

The ops console frontend: sole contributor since taking over in September 2025 (330 commits, 72.8% of the repo) — the original team built the initial skeleton in Aug–Sep 2025. Since the takeover: unified the responsive and error-handling architecture, rebuilt dark mode and the design tokens, and ran four cross-module audits with fixes landed. Also responsible for backend (Django) API design and development on the platform.

05 / CHALLENGES → SOLUTIONS

CHALLENGE

The moment a JWT expires, dozens of in-flight requests all try to refresh at once.

SOLUTION

Every 401 joins a refresh queue: one refresh fires, then all queued requests replay. The same interceptor normalizes per-field validation errors from the backend, so forms display them directly instead of parsing on their own.

CHALLENGE

Bundling 50+ modules eagerly would sink the first paint.

SOLUTION

Route-level lazy loading plus feature flags gate the surface area; a CI bundle-size budget makes every size increase a visible decision, never an accident.

CHALLENGE

An enterprise audit across workflows, forms, permissions, accessibility and performance produced 163 raw findings — the highest-leverage class being a “fake success” anti-pattern recurring in four-plus modules: forms toasting success without persisting to the backend, buttons reporting success on silently disabled features.

SOLUTION

The 163 were deduplicated to 49; the 21 Critical/High items were each cross-verified (21/21 confirmed real) before any fix, then landed across 18 batched commits — repairing the fake-success actions and returning eight commission files to the unified errorHandler. The remaining 28 Medium/Low findings stay tracked as open, with no progress inflated.

CHALLENGE

A stock-size table and its alert kept growing downward until they burst the container — but only in browsers with space-occupying scrollbars. Headless testing uses overlay scrollbars, so automated screenshots showed nothing wrong and the page was once misjudged as stable.

SOLUTION

The root cause: the table’s own scroll plus a fixed first column, stacked on a global overflow-x:auto, formed two nested horizontal scroll containers — and the fixed column kept re-triggering Ant Design’s ResizeObserver in a “scrollbar appears → container narrows → remeasure” loop. Removing the table-level scroll/fixed and letting the global wrapper own a single scroll layer fixed it, verified with Playwright at 1280/900/600/375 widths.

06 / SYSTEM FACTS

91

admin routes

~600k

lines of frontend code

1,193

test cases (Jest + E2E)

72.8%

of commits mine (330/453)

07 / LESSONS

Without shared types, the highest-leverage contract investment is normalizing error shapes in the interceptor — it beats per-form handling by an order of magnitude.

Tech debt gets paid only when it has a number: audited, prioritized items get fixed one by one — 'when we have time' never arrives on its own.

“The UI said success” and “the data was actually written” are two different claims to verify: the audit’s most repeated anti-pattern was fake success — a toast fires while nothing persists. Every write operation now gets checked on both sides before shipping: the feedback the user sees, and the state the backend holds.

NEXT

Naily — AI Nail Commerce App