Skip to main content

03 / WORK / CASE STUDY

Naily — AI Nail Commerce App

A Flutter commerce app — storefront, custom press-ons and payments. I took over the app frontend in November 2025; the on-device AI and AR modules belong to another team.

TYPE
MOBILE APP
SCOPE
Live on both stores · takeover since 2025.11
STACK
FLUTTER · FIREBASE · ECPAY
LINKS
APP STORE GOOGLE PLAY

01 / Problem

Press-on nails are highly customized; customers can rarely judge their own nail sizes, so online orders often bounce back over fit. This app replaces in-store measuring with the phone camera and on-device AI, folding design → sizing → AR try-on → checkout → payment and logistics into one flow.

02 / Constraints

  • Inherited a multi-author codebase built by the original team (198 commits before the handover), with no transition period.
  • On-device nail recognition and AR try-on are another team’s work, outside my scope; this case study covers only the app frontend around those modules.
  • Payments and personal data are involved: tokens live in secure storage only, logs must not capture full request bodies, iOS requires ATT consent. P0–P2 launch-readiness audit fixes were completed before release; the app is now live on both stores.

03 / Architecture

A modular Flutter app: feature-first layering (config / models / services / screens) with declarative GoRouter navigation — 82 screens, 72 services, 44 models across 533 Dart files (~129k lines), talking to 123 backend API endpoints.

The on-device AI and AR modules (nail detection/segmentation and hand-landmark models on ONNX Runtime, plus the iOS CoreML bridge) are built and maintained by another team and are not covered here. On the side I own, commerce integrates ECPay payments/logistics/e-invoicing and four social logins; Firebase covers push, Crashlytics and analytics; CI runs three pipelines — staged CI, nightly full E2E, and tag-triggered signed releases.

04 / Responsibilities

Took over in November 2025; the foundation and commerce flows were built by the original team. Since then the app frontend’s development, maintenance and releases are mine (121 commits, 85% of the period): FCM and tracking integration, the custom press-on feature, a points system, breaking up the oversized files, security hardening and CI/CD. The on-device AI and AR modules belong to another team; the backend API is a separate service outside this repo.

05 / Challenges and solutions

CHALLENGE

Core screens were multi-thousand-line monsters — order detail at 5,256 lines, checkout at 3,416 — where every change rippled everywhere.

SOLUTION

Set an 800-line-per-file cap and split by UI region and logic: order detail went 5,256 → 230 lines (logic extracted); the cart/checkout/subscription trio went 6,800 → 1,200 lines plus standalone widgets.

CHALLENGE

Expired tokens logged users out mid-session, and pre-launch security hardening was thin.

SOLUTION

Added 401 intercept-and-refresh across seven services (seamless renewal), and hardened for launch with native-layer obfuscation, Dart obfuscation, certificate pinning and root/jailbreak detection.

06 / System facts

82

screens

~129k

lines of Dart

121

commits since takeover

64

test files (unit + e2e)

07 / Lessons

The first step in a takeover is not refactoring — it is writing the conventions down. Once rules are explicit, every change makes the system more consistent instead of more divergent.

Trust git, not prose: this project's CHANGELOG was reconstructed after the fact and its dates don't match the commits. Records worth keeping should be generated with tags, not backfilled.

NEXT

Naily Storefront & Canvas Product Customizer