Skip to main content

03 / WORK / CASE STUDY

Naily — AI Nail Commerce App

A Flutter commerce app — on-device AI nail sizing, AR try-on and custom press-ons. I took over all development and maintenance in November 2025.

TYPE
MOBILE APP
SCOPE
Pre-launch · takeover since 2025.11
STACK
FLUTTER · ONNX · FIREBASE · ECPAY
LINKS
Internal project (private)

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.
  • AI inference must run on-device within phone-level compute — at handover, AR try-on ran at 1 FPS.
  • Payments and personal data are involved: tokens live in secure storage only, logs must not capture full request bodies, iOS requires ATT consent. The app is in pre-launch readiness (P0–P2 audit fixes).

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.

On-device AI is split into six single-purpose AR/CV packages running four ONNX models (YOLO11 nail detection/segmentation, hand landmarks), with an iOS platform channel to native CoreML. 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 all development, maintenance and releases are mine (121 commits, 85% of the period): FCM and tracking integration, the custom press-on feature, a points system, the AR rewrite, the iOS CoreML native layer, security hardening and CI/CD. The backend API is a separate service outside this repo.

05 / CHALLENGES → SOLUTIONS

CHALLENGE

At handover, AR try-on ran at 1 FPS, with the design overlay flickering and drifting during detection.

SOLUTION

Retired three generations of old implementations and rewrote it as five single-purpose packages (detection, rendering, classic CV, mask recolor, manual studio), moving iOS detection to native CoreML, plus cross-frame hysteresis to kill flicker. FPS went from 1 to realtime; the core detection page shrank from 3,051 to 1,356 lines.

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