Agilo Fashion Starter Audit
Codebase Stats
| Metric | Value |
|---|---|
| Storefront files (TS/TSX/JS/JSX) | 219 |
| Storefront lines of code | ~15,900 |
| Framework | Next.js 15.5.10 (App Router, Turbopack) |
| React | 19.x |
| Styling | Tailwind CSS 3.4 + tailwind-merge + tailwindcss-animate + tailwindcss-radix |
| UI library | React Aria Components (Adobe) + react-stately |
| Forms | react-hook-form 7.x + zod 4.x |
| Carousel | Embla Carousel 8.x |
| Search | MeiliSearch 0.55.0 (client-side SDK) |
| Payments | Stripe + PayPal |
| Font | Mona Sans (variable weight) |
| Other | @vercel/speed-insights, @tanstack/react-query 5.x, lodash, qs |
Project Structure
Monorepo with two packages (no workspace config):
/storefront— Next.js 15 App Router storefront/medusa— Medusa v2 backend with:- Custom
fashionmodule (Material and Color data models + admin widgets) - Custom
meilisearchmodule (product indexing + search) - Custom
resendmodule (transactional emails via React Email) @agilo/medusa-analytics-plugin(PostHog analytics)- S3 file storage, Redis caching/event-bus/locking, Stripe provider
- Custom
Page Routes
| Route | Description |
|---|---|
/ | Homepage — hero, product types grid, collections, about section |
/about | Static brand story page |
/inspiration | Lookbook-style page with specific products/collections |
/store | Product listing with filters (collection, category, type) and sorting |
/products/[handle] | PDP with gallery, variant picker, add-to-cart |
/collections/[handle] | Collection page with category/type filters and sorting |
/search?query=X | Search results page (MeiliSearch-powered) |
/cart | Full cart page |
/checkout?step=X | Multi-step checkout |
/order/confirmed/[id] | Order confirmation |
/auth/login | Login page |
/auth/register | Registration page |
/auth/forgot-password | Forgot password form |
/auth/forgot-password/reset | Password reset (from email link) |
/auth/reset-password | Password reset page |
/account | Account dashboard — personal info, addresses, change password |
/account/my-orders | Order history with pagination |
/account/my-orders/[orderId] | Individual order detail |
/privacy-policy | Static page |
/cookie-policy | Static page |
/terms-of-use | Static page |
All routes nested under /[countryCode]/ for multi-region support.
Commerce Components
Product
| Component | Path | Lines |
|---|---|---|
| Product preview (card) | src/modules/products/components/product-preview/index.tsx | 58 |
| Product actions (variant picker + ATC) | src/modules/products/components/product-actions/index.tsx | 316 |
| Product price | src/modules/products/components/product-price/index.tsx | 47 |
| Product thumbnail | src/modules/products/components/thumbnail/index.tsx | 69 |
| Image gallery | src/modules/products/components/image-gallery/index.tsx | 39 |
| ProductPageGallery (carousel) | src/components/ProductPageGallery.tsx | 126 |
| Related products | src/modules/products/components/related-products/index.tsx | 68 |
| Paginated products grid | src/modules/store/templates/paginated-products.tsx | 108 |
Cart
| Component | Path | Lines |
|---|---|---|
| Cart drawer (slide-out) | src/components/CartDrawer.tsx | 118 |
| Cart item | src/modules/cart/components/item/index.tsx | 89 |
| Cart totals | src/modules/cart/components/cart-totals/index.tsx | 111 |
| Discount code | src/modules/cart/components/discount-code/index.tsx | — |
Checkout
| Component | Path | Lines |
|---|---|---|
| Checkout form (orchestrator) | src/modules/checkout/components/checkout-form/index.tsx | 50 |
| Email step | src/modules/checkout/components/email/index.tsx | 151 |
| Addresses step | src/modules/checkout/components/addresses/index.tsx | 270 |
| Shipping step | src/modules/checkout/components/shipping/index.tsx | 134 |
| Payment step | src/modules/checkout/components/payment/index.tsx | 270 |
| Review step | src/modules/checkout/components/review/index.tsx | 73 |
| Billing address | src/modules/checkout/components/billing_address/index.tsx | 387 |
| Shipping address | src/modules/checkout/components/shipping-address/index.tsx | 411 |
Filter / Search
| Component | Path | Lines |
|---|---|---|
| Refinement list (filter bar) | src/modules/store/components/refinement-list/index.tsx | 128 |
| Category filter (checkbox dropdown) | src/modules/store/components/refinement-list/category-filter/index.tsx | 48 |
| Collection filter (checkbox dropdown) | src/modules/store/components/refinement-list/collection-filter/index.tsx | 48 |
| Type filter (checkbox dropdown) | src/modules/store/components/refinement-list/type-filter/index.tsx | 48 |
| Sort products dropdown | src/modules/store/components/refinement-list/sort-products/index.tsx | 53 |
| Mobile filters (drawer) | src/modules/store/components/refinement-list/mobile-filters/index.tsx | 165 |
| Mobile sort (drawer) | src/modules/store/components/refinement-list/mobile-sort/index.tsx | 81 |
| SearchField (autocomplete) | src/components/SearchField.tsx | 177 |
| Pagination | src/modules/store/components/pagination/index.tsx | 118 |
Account
| Component | Path |
|---|---|
| PersonalInfoForm | src/modules/account/components/PersonalInfoForm.tsx |
| UpsertAddressForm | src/modules/account/components/UpsertAddressForm.tsx |
| AddressSingle / AddressMultiple | src/modules/account/components/ |
| DefaultShippingAddressSelect | src/modules/account/components/DefaultShippingAddressSelect.tsx |
| SidebarNav | src/modules/account/components/SidebarNav.tsx |
| LoginForm | src/modules/auth/components/LoginForm.tsx |
| SignUpForm | src/modules/auth/components/SignUpForm.tsx |
Navigation / Layout
| Component | Path | Lines |
|---|---|---|
| Header | src/components/Header.tsx | 76 |
| HeaderDrawer (mobile nav) | src/components/HeaderDrawer.tsx | 88 |
| Footer | src/components/Footer.tsx | 101 |
| RegionSwitcher | src/components/RegionSwitcher.tsx | 81 |
| NewsletterForm | src/components/NewsletterForm.tsx | 68 |
| CollectionsSlider | src/modules/store/components/collections-slider/index.tsx | — |
UI Primitives
Button, Checkbox, Modal, Radio, Select, Skeleton, Slider, Tag, TagList, Dialog, Drawer, Input, NumberField, Link, LocalizedLink, 27 custom SVG icons. All built on React Aria Components.
Feature Inventory
Faceted Filtering
Three filter types on /store and collection pages:
- Collection — multi-select checkbox dropdown
- Category — multi-select checkbox dropdown
- Type — multi-select checkbox dropdown (e.g., “Sofa”, “Armchair”)
Sort: Latest Arrivals, Lowest price, Highest price.
Mobile filter drawer for responsive layouts. URL search param-driven.
Missing: No price range filter, no color/size/material filters on the store page.
Search
MeiliSearch integration — full stack, with autocomplete.
- Backend: Custom MeiliSearch module in Medusa with product indexing subscribers (auto-index on product changes)
- Searchable attributes: title, subtitle, description, collection, categories, type, tags, variants, SKU
- Autocomplete: Yes.
SearchFielduses React AriaComboBoxwithuseAsyncList. Shows dropdown with product thumbnails, titles, variant names, and prices as you type. - Results page:
/search?query=Xshows full product grid - Architecture: Backend indexes to MeiliSearch; storefront queries directly via MeiliSearch JS client
This is the most significant differentiator of this starter.
Checkout
Multi-step (5 steps):
- Email — email input
- Addresses — shipping + billing
- Shipping — method selection
- Payment — Stripe card + PayPal
- Review — terms + place order
URL-param driven (?step=). No express checkout (no Apple Pay, Google Pay).
Image Gallery
Embla Carousel on PDP:
- Horizontal swipe with prev/next arrows
- Dot/number pagination
- Mobile: full-width at top
- Desktop: left half of PDP layout
- No lightbox, no zoom
Customer Accounts
Full:
- Login/register with email/password
- Forgot/reset password (email-based via Resend)
- Personal info editing (name, phone)
- Multiple addresses with CRUD + default shipping/billing selection
- Order history with pagination, status tags (Packing/Delivering/Delivered/Canceled)
- Order detail page
- Password change via email reset
- No wishlist
SEO
- OG tags: Yes on product pages
- Static generation: Products, collections via
generateStaticParams - robots.txt: Dynamic with
DISALLOW_ROBOTSenv var - Sitemap:
next-sitemap.jsconfigured - JSON-LD: None
- Meta descriptions: Basic, many generic
Theming / Branding
Custom Tailwind design system:
- Custom color palette (grayscale, black/white, accent)
- Custom font sizes, border radius, spacing scales
- Mona Sans variable font
Reskin difficulty: Moderate. Tailwind config is clean and centralized. However, brand name “Sofa Society” is hardcoded across content pages, and About/Inspiration pages are entirely sofa-themed with static images.
Notable Features
MeiliSearch Integration (the standout)
Full-stack search with:
- Backend product indexing via Medusa subscribers
- Auto-sync on product CRUD events
- Searchable: title, description, categories, tags, variants, SKU
- Client-side autocomplete with thumbnails and prices
- Dedicated results page
Highly relevant for a bookstore — would index title, author (in description/metadata), genre (categories), ISBN (SKU), tags. Autocomplete provides much better search UX than basic form-submit search.
Fashion Module (backend)
Custom Medusa module for Materials and Colors with admin widgets. Not relevant for books — would be replaced with book-specific metadata (format, binding, page count).
Resend Email Integration
Custom notification module with React Email templates for:
- Welcome email
- Password reset
- Order confirmation
Other
- PostHog analytics plugin
- E2E test setup (Playwright)
- Multi-region routing
- React Aria for accessibility
- Newsletter signup form
Assessment for Dungeon Books
Strong contender. The MeiliSearch integration is the killer feature:
- Search with autocomplete dramatically improves book discovery UX
- MeiliSearch indexes product metadata — perfect for searching by title, author, ISBN
- Backend indexing subscribers handle the sync automatically
- The Ingram search fallback could extend this: query MeiliSearch first, then fall back to Ingram API for “Available to Order” results
Gaps to fill:
- No CMS integration (content pages are hardcoded)
- No JSON-LD structured data
- No lightbox/zoom on image gallery
- Fashion-specific content (About, Inspiration) needs full rewrite
- Material/Color module irrelevant, needs replacement
- No blog
Compared to Solace: Fashion has better search (MeiliSearch with autocomplete vs basic Medusa search). Solace has better CMS integration (Strapi), lightbox gallery, dark mode, blog, and more content pages. The choice depends on whether search quality or CMS/content completeness matters more.