simpleshop_theme/PHASE_9_PLAN.md

29 KiB

SimpleShop Theme - Phase 9 Implementation Plan

Overview

This plan covers Phase 9: Storefront Integration - applying the theme system to the actual public-facing shop. Based on my analysis, Phases 1-8 are complete, with a fully functional theme editor at /admin/theme. Phase 9 will create the public storefront that uses the saved theme settings.

Current State Summary

Completed (Phases 1-8):

  • Settings and Media contexts with SQLite storage
  • CSS three-layer architecture (primitives, attributes, semantic)
  • Theme editor LiveView with 8 presets
  • All 7 preview pages (home, collection, pdp, cart, about, contact, error)
  • Full customization controls (mood, typography, shape, density, colors, layout, toggles)
  • Logo and header image uploads with BLOB storage
  • SVG recoloring functionality
  • CSS generation system
  • Preview data system (mock products, testimonials, categories)

Not Started (Phase 9):

  • Public storefront routes
  • Storefront LiveViews
  • Theme CSS injection for public pages
  • Plug to load theme settings
  • CSS cache warming
  • Real product integration

Architecture Decisions

1. Routing Strategy

  • Public routes: Use root-level paths (/, /products/:slug, /cart, etc.)
  • No shop slug: Since this app IS the shop (not multi-tenant), no slug needed
  • Future-proof: Structure allows adding multi-shop support later if needed

2. LiveView Structure

  • Reuse preview templates: The preview pages are already production-ready
  • Extract to shared components: Move reusable pieces from preview_pages/ to components/
  • Storefront-specific LiveViews: Create dedicated LiveViews that handle real data

3. CSS Application

  • Same three-layer system: Use identical CSS as theme editor
  • Root element: Use .shop-root class with data attributes
  • Inline CSS injection: Inject generated CSS into layout via assign
  • ETS caching: Use CSSCache for production performance
  • Cache invalidation: Invalidate on theme settings save

4. Data Handling

  • Smart degradation: Show empty states when no products exist
  • Graceful fallback: Use preview data patterns for missing content
  • Real products: When Products context exists, use real data

Implementation Steps

Step 1: Extract Shared Components

Goal: Move reusable preview components to shared location for use in both admin and storefront

Files to create:

  • lib/simpleshop_theme_web/components/shop/announcement_bar.ex
  • lib/simpleshop_theme_web/components/shop/header.ex
  • lib/simpleshop_theme_web/components/shop/footer.ex
  • lib/simpleshop_theme_web/components/shop/search_modal.ex
  • lib/simpleshop_theme_web/components/shop/product_card.ex

Files to modify:

  • lib/simpleshop_theme_web/live/theme_live/preview_pages.ex - Import and use new components
  • All preview templates - Update to use new component modules

Actions:

  1. Create lib/simpleshop_theme_web/components/shop/ directory
  2. Extract announcement_bar/1 from preview_pages.ex to shop/announcement_bar.ex
  3. Extract shop_header/1 to shop/header.ex
  4. Extract shop_footer/1 to shop/footer.ex
  5. Extract search_modal/1 to shop/search_modal.ex
  6. Create new product_card/1 component (used in multiple places)
  7. Update preview_pages.ex to import and use new components
  8. Update all 7 preview templates to use new component paths
  9. Test theme editor still works correctly

Validation:

  • Run mix test test/simpleshop_theme_web/live/theme_live_test.exs
  • Visit /admin/theme and verify all 7 preview pages still render correctly
  • No visual regressions

Step 2: Create LoadTheme Plug

Goal: Create a plug that loads theme settings and generated CSS for every public request

Files to create:

  • lib/simpleshop_theme_web/plugs/load_theme.ex
  • test/simpleshop_theme_web/plugs/load_theme_test.exs

Plug functionality:

defmodule SimpleshopThemeWeb.Plugs.LoadTheme do
  import Plug.Conn
  alias SimpleshopTheme.Settings
  alias SimpleshopTheme.Theme.{CSSGenerator, CSSCache}

  def init(opts), do: opts

  def call(conn, _opts) do
    # Try cache first
    {theme_settings, generated_css} =
      case CSSCache.get() do
        {:ok, css} ->
          {Settings.get_theme_settings(), css}
        :miss ->
          settings = Settings.get_theme_settings()
          css = CSSGenerator.generate(settings)
          CSSCache.put(css)
          {settings, css}
      end

    conn
    |> assign(:theme_settings, theme_settings)
    |> assign(:generated_css, generated_css)
  end
end

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add plug to public pipeline

Actions:

  1. Create plug file with init/1 and call/2 functions
  2. Implement cache-first CSS loading strategy
  3. Assign both :theme_settings and :generated_css to conn
  4. Add plug to :browser pipeline in router (before routes)
  5. Write tests for plug behavior
  6. Test cache hit and cache miss scenarios

Validation:

  • Run mix test test/simpleshop_theme_web/plugs/load_theme_test.exs
  • Verify assigns are available in subsequent requests
  • Verify CSS is cached and reused

Step 3: Create Storefront Layout

Goal: Create a dedicated layout for the public storefront with theme CSS injection

Files to create:

  • lib/simpleshop_theme_web/components/layouts/shop.html.heex

Layout structure:

<!DOCTYPE html>
<html lang="en" class="h-full">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="csrf-token" content={get_csrf_token()} />
    <.live_title><%= assigns[:page_title] || @theme_settings.site_name %></.live_title>
    <link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
    <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}></script>

    <!-- Inject theme CSS -->
    <style id="theme-css">
      <%= Phoenix.HTML.raw(@generated_css) %>
    </style>
  </head>
  <body class="h-full">
    <div class="shop-root h-full"
         data-mood={@theme_settings.mood}
         data-typography={@theme_settings.typography}
         data-shape={@theme_settings.shape}
         data-density={@theme_settings.density}
         data-grid={@theme_settings.grid_columns}
         data-header={@theme_settings.header_layout}
         data-sticky={to_string(@theme_settings.sticky_header)}
         data-layout={@theme_settings.layout_width}
         data-shadow={@theme_settings.card_shadow}>
      <%= @inner_content %>
    </div>
  </body>
</html>

Files to modify:

  • lib/simpleshop_theme_web/components/layouts.ex - Add shop/1 layout function

Actions:

  1. Create new shop.html.heex layout file
  2. Add .shop-root wrapper with all theme data attributes
  3. Inject @generated_css into <style> tag
  4. Use @theme_settings.site_name for page title default
  5. Add shop layout function to layouts.ex module
  6. Ensure Google Fonts are loaded (already in root.html.heex)

Validation:

  • Inspect HTML output to verify data attributes present
  • Verify CSS injection works
  • Check that layout compiles without errors

Step 4: Create Home Page LiveView

Goal: Create the public homepage LiveView using real/mock data

Files to create:

  • lib/simpleshop_theme_web/live/shop_live/home.ex
  • lib/simpleshop_theme_web/live/shop_live/home.html.heex
  • test/simpleshop_theme_web/live/shop_live/home_test.exs

LiveView structure:

defmodule SimpleshopThemeWeb.ShopLive.Home do
  use SimpleshopThemeWeb, :live_view
  alias SimpleshopTheme.Theme.PreviewData

  def mount(_params, _session, socket) do
    # Use real products when available, else preview data
    products = PreviewData.products()
    categories = PreviewData.categories()
    testimonials = PreviewData.testimonials()

    {:ok, assign(socket,
      page_title: "Home",
      products: products,
      categories: categories,
      testimonials: testimonials
    )}
  end
end

Template approach:

  • Copy structure from preview_pages/home.html.heex
  • Use new shared components (header, footer, announcement_bar)
  • Remove preview-specific wrapper divs
  • Ensure data-driven rendering from assigns

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add home route

Actions:

  1. Create home LiveView module with mount function
  2. Load preview data (real products when available)
  3. Create home template based on preview version
  4. Use shared components for header, footer, announcement bar
  5. Add route: live "/", ShopLive.Home, :index in public scope
  6. Set layout to :shop for route
  7. Write tests for home page rendering
  8. Test with and without products

Router changes:

# Public storefront
scope "/", SimpleshopThemeWeb do
  pipe_through :browser

  live_session :public_shop, layout: {SimpleshopThemeWeb.Layouts, :shop} do
    live "/", ShopLive.Home, :index
  end
end

Validation:

  • Visit / and verify homepage renders
  • Check theme styles are applied
  • Test announcement bar toggle works
  • Verify header layout variations work
  • Test sticky header toggle
  • Confirm products display (mock data)

Step 5: Create Collection Page LiveView

Goal: Create product collection/grid page

Files to create:

  • lib/simpleshop_theme_web/live/shop_live/collection.ex
  • lib/simpleshop_theme_web/live/shop_live/collection.html.heex
  • test/simpleshop_theme_web/live/shop_live/collection_test.exs

LiveView structure:

defmodule SimpleshopThemeWeb.ShopLive.Collection do
  use SimpleshopThemeWeb, :live_view
  alias SimpleshopTheme.Theme.PreviewData

  def mount(%{"slug" => slug}, _session, socket) do
    # Future: Load real collection by slug
    # For now: Use preview products filtered by category
    products = PreviewData.products()

    {:ok, assign(socket,
      page_title: "Shop All Products",
      collection_name: "All Products",
      products: products,
      filter: nil,
      sort: "featured"
    )}
  end

  def handle_event("filter", %{"category" => category}, socket) do
    # Filter products by category
    {:noreply, assign(socket, filter: category)}
  end

  def handle_event("sort", %{"by" => sort_by}, socket) do
    # Sort products
    {:noreply, assign(socket, sort: sort_by)}
  end
end

Template approach:

  • Copy from preview_pages/collection.html.heex
  • Implement filter sidebar (responds to filter events)
  • Implement sort dropdown (price, name, featured)
  • Use product_card component
  • Respect grid_columns setting (2/3/4)

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add collection route

Actions:

  1. Create collection LiveView module
  2. Implement filtering and sorting logic
  3. Create collection template based on preview
  4. Add route: live "/collections/:slug", ShopLive.Collection, :show
  5. Handle empty state (no products)
  6. Write tests for filtering and sorting
  7. Test grid columns respect theme setting

Router changes:

live "/collections/:slug", ShopLive.Collection, :show
live "/collections", ShopLive.Collection, :index  # "All Products"

Validation:

  • Visit /collections and /collections/tshirts
  • Test filter sidebar works
  • Test sort dropdown changes order
  • Verify grid columns (2, 3, 4) work correctly
  • Check card shadow setting is respected
  • Test hover image toggle works

Step 6: Create Product Detail Page (PDP) LiveView

Goal: Create individual product page with gallery, details, add to cart

Files to create:

  • lib/simpleshop_theme_web/live/shop_live/product.ex
  • lib/simpleshop_theme_web/live/shop_live/product.html.heex
  • test/simpleshop_theme_web/live/shop_live/product_test.exs

LiveView structure:

defmodule SimpleshopThemeWeb.ShopLive.Product do
  use SimpleshopThemeWeb, :live_view
  alias SimpleshopTheme.Theme.PreviewData

  def mount(%{"slug" => slug}, _session, socket) do
    # Future: Load real product by slug
    # For now: Use first preview product
    [product | _] = PreviewData.products()

    {:ok, assign(socket,
      page_title: product.name,
      product: product,
      selected_variant: nil,
      quantity: 1,
      selected_image: 0
    )}
  end

  def handle_event("select_variant", %{"variant_id" => id}, socket) do
    {:noreply, assign(socket, selected_variant: id)}
  end

  def handle_event("select_image", %{"index" => index}, socket) do
    {:noreply, assign(socket, selected_image: String.to_integer(index))}
  end

  def handle_event("add_to_cart", _params, socket) do
    # Future: Add to cart functionality
    {:noreply, put_flash(socket, :info, "Added to cart")}
  end
end

Template approach:

  • Copy from preview_pages/pdp.html.heex
  • Image gallery with thumbnails
  • Variant selector (size, color)
  • Quantity selector
  • Add to cart button
  • Respect toggle settings: pdp_trust_badges, pdp_reviews, pdp_related_products
  • Gallery position: left/right based on gallery_position setting

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add product route

Actions:

  1. Create product LiveView module
  2. Implement variant selection logic
  3. Implement image gallery navigation
  4. Create product template based on preview
  5. Add route: live "/products/:slug", ShopLive.Product, :show
  6. Handle toggle features (reviews, badges, related)
  7. Write tests for variant selection and cart add
  8. Test gallery position setting

Router changes:

live "/products/:slug", ShopLive.Product, :show

Validation:

  • Visit /products/example-tshirt
  • Test variant selection updates UI
  • Test image gallery thumbnail clicks
  • Verify trust badges show/hide based on setting
  • Verify reviews show/hide based on setting
  • Verify related products show/hide based on setting
  • Test "Add to cart" button (shows flash for now)
  • Test gallery position (left/right) setting

Step 7: Create Cart Page LiveView

Goal: Create shopping cart page with line items and checkout

Files to create:

  • lib/simpleshop_theme_web/live/shop_live/cart.ex
  • lib/simpleshop_theme_web/live/shop_live/cart.html.heex
  • test/simpleshop_theme_web/live/shop_live/cart_test.exs

LiveView structure:

defmodule SimpleshopThemeWeb.ShopLive.Cart do
  use SimpleshopThemeWeb, :live_view
  alias SimpleshopTheme.Theme.PreviewData

  def mount(_params, _session, socket) do
    # Future: Load real cart from session
    # For now: Use preview cart items
    cart_items = PreviewData.cart_items()

    {:ok, assign(socket,
      page_title: "Shopping Cart",
      cart_items: cart_items,
      subtotal: calculate_subtotal(cart_items),
      shipping: 0,
      tax: 0
    )}
  end

  def handle_event("update_quantity", %{"id" => id, "quantity" => qty}, socket) do
    # Update item quantity
    {:noreply, socket}
  end

  def handle_event("remove_item", %{"id" => id}, socket) do
    # Remove item from cart
    {:noreply, socket}
  end

  def handle_event("checkout", _params, socket) do
    # Future: Proceed to checkout
    {:noreply, put_flash(socket, :info, "Checkout coming soon")}
  end

  defp calculate_subtotal(items) do
    Enum.reduce(items, 0, fn item, acc ->
      acc + (item.price * item.quantity)
    end)
  end
end

Template approach:

  • Copy from preview_pages/cart.html.heex
  • Line items with product image, name, variant, price, quantity
  • Quantity update controls
  • Remove item button
  • Cart summary (subtotal, shipping, tax, total)
  • Checkout button
  • Empty cart state

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add cart route

Actions:

  1. Create cart LiveView module
  2. Implement quantity update logic
  3. Implement remove item logic
  4. Create cart template based on preview
  5. Add route: live "/cart", ShopLive.Cart, :show
  6. Handle empty cart state
  7. Write tests for cart operations
  8. Test price calculations

Router changes:

live "/cart", ShopLive.Cart, :show

Validation:

  • Visit /cart
  • Test quantity update buttons
  • Test remove item button
  • Verify price calculations correct
  • Test empty cart state
  • Verify checkout button shows flash
  • Check button style setting is respected

Step 8: Create Static Pages (About, Contact, Error)

Goal: Create remaining static pages

Files to create:

  • lib/simpleshop_theme_web/live/shop_live/about.ex
  • lib/simpleshop_theme_web/live/shop_live/about.html.heex
  • lib/simpleshop_theme_web/live/shop_live/contact.ex
  • lib/simpleshop_theme_web/live/shop_live/contact.html.heex
  • lib/simpleshop_theme_web/controllers/error_html/404.html.heex
  • test/simpleshop_theme_web/live/shop_live/about_test.exs
  • test/simpleshop_theme_web/live/shop_live/contact_test.exs

About Page:

defmodule SimpleshopThemeWeb.ShopLive.About do
  use SimpleshopThemeWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, page_title: "About Us")}
  end
end

Contact Page:

defmodule SimpleshopThemeWeb.ShopLive.Contact do
  use SimpleshopThemeWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket,
      page_title: "Contact Us",
      form: to_form(%{})
    )}
  end

  def handle_event("submit_contact", %{"contact" => params}, socket) do
    # Future: Send contact email
    {:noreply, put_flash(socket, :info, "Message sent successfully")}
  end
end

Files to modify:

  • lib/simpleshop_theme_web/router.ex - Add routes
  • lib/simpleshop_theme_web/controllers/error_html.ex - Add 404 template

Actions:

  1. Create about LiveView and template (copy from preview)
  2. Create contact LiveView and template (copy from preview)
  3. Add contact form submission handler
  4. Create 404 error template (copy from preview_pages/error.html.heex)
  5. Add routes: live "/about" and live "/contact"
  6. Write tests for static pages
  7. Test contact form submission

Router changes:

live "/about", ShopLive.About, :show
live "/contact", ShopLive.Contact, :show

Validation:

  • Visit /about and verify page renders
  • Visit /contact and test form submission
  • Visit invalid URL and verify 404 page shows with theme
  • Check all pages respect theme settings

Step 9: Wire Up CSS Cache Invalidation

Goal: Ensure CSS cache is invalidated when theme settings are saved

Files to modify:

  • lib/simpleshop_theme/settings.ex - Add cache invalidation to update_theme_settings/1
  • lib/simpleshop_theme_web/live/theme_live/index.ex - Ensure save_theme calls invalidation

Actions:

  1. Update Settings.update_theme_settings/1 to call CSSCache.invalidate() after save
  2. Update ThemeLive.Index.handle_event("save_theme") to trigger cache refresh
  3. Optionally warm cache after invalidation for first request performance
  4. Test cache invalidation works correctly

Code changes in Settings context:

def update_theme_settings(attrs) do
  current = get_theme_settings()
  changeset = ThemeSettings.changeset(current, attrs)

  case changeset.valid? do
    true ->
      updated = Ecto.Changeset.apply_changes(changeset)
      put_setting("theme_settings", updated, :json)

      # Invalidate CSS cache
      SimpleshopTheme.Theme.CSSCache.invalidate()

      # Optionally warm cache immediately
      css = SimpleshopTheme.Theme.CSSGenerator.generate(updated)
      SimpleshopTheme.Theme.CSSCache.put(css)

      {:ok, updated}
    false ->
      {:error, changeset}
  end
end

Validation:

  • Change theme settings in admin
  • Save theme
  • Visit public storefront
  • Verify changes are reflected immediately
  • Check cache is being used (add logging if needed)

Step 10: Add Cache Warming on Application Start

Goal: Pre-generate and cache theme CSS when application starts

Files to modify:

  • lib/simpleshop_theme/application.ex - Add cache warming after supervisor start

Actions:

  1. Add cache warming function to Application module
  2. Call after supervisor starts successfully
  3. Handle case where no theme settings exist yet
  4. Add logging for cache warming

Code changes:

defmodule SimpleshopTheme.Application do
  def start(_type, _args) do
    children = [
      # ... existing children ...
      SimpleshopTheme.Theme.CSSCache,
      # ... more children ...
    ]

    opts = [strategy: :one_for_one, name: SimpleshopTheme.Supervisor]
    result = Supervisor.start_link(children, opts)

    # Warm CSS cache on startup
    Task.start(fn -> warm_theme_cache() end)

    result
  end

  defp warm_theme_cache do
    try do
      settings = SimpleshopTheme.Settings.get_theme_settings()
      css = SimpleshopTheme.Theme.CSSGenerator.generate(settings)
      SimpleshopTheme.Theme.CSSCache.put(css)
      Logger.info("Theme CSS cache warmed successfully")
    rescue
      e -> Logger.warning("Failed to warm theme cache: #{inspect(e)}")
    end
  end
end

Validation:

  • Restart application
  • Check logs for "Theme CSS cache warmed successfully"
  • Visit storefront immediately (should be fast)
  • Verify no database queries for CSS generation on first request

Goal: Connect theme editor to storefront and vice versa

Files to modify:

  • lib/simpleshop_theme_web/components/shop/header.ex - Add admin link when authenticated
  • lib/simpleshop_theme_web/live/theme_live/index.html.heex - Add "View Shop" link

Actions:

  1. In shop header component, add conditional admin link for authenticated users
  2. In theme editor, add "View Shop" button in controls area
  3. Ensure links use proper route helpers
  4. Test navigation between admin and storefront

Shop header changes:

<%= if @current_user do %>
  <a href={~p"/admin/theme"} class="admin-link">
    Edit Theme
  </a>
<% end %>

Theme editor changes (add near "Save Theme" button):

<a href={~p"/"} target="_blank" class="btn btn-outline">
  View Shop
</a>

Validation:

  • When logged in on storefront, verify "Edit Theme" link appears
  • Click link and verify navigates to theme editor
  • In theme editor, click "View Shop" link
  • Verify opens storefront in new tab

Step 12: Testing and Polish

Goal: Comprehensive testing and UX improvements

Files to modify:

  • All test files - Add comprehensive coverage
  • Various LiveViews - Add loading states, error handling

Actions:

  1. Write comprehensive tests:

    • Test all storefront LiveViews
    • Test plug behavior
    • Test cache invalidation flow
    • Test theme application across all pages
    • Test responsive behavior
  2. Add loading states:

    • Product loading skeletons
    • Cart update feedback
    • Form submission states
  3. Error handling:

    • Handle missing products gracefully
    • Handle invalid routes
    • Handle network errors
  4. Performance optimization:

    • Verify CSS cache is working
    • Check database query counts
    • Test with many products (when available)
  5. Accessibility:

    • Check color contrast ratios
    • Verify keyboard navigation
    • Add ARIA labels where needed
  6. Mobile testing:

    • Test all pages on mobile viewport
    • Verify touch interactions work
    • Check responsive grid layouts
  7. Cross-browser testing:

    • Test in Chrome, Firefox, Safari
    • Verify CSS variables work correctly
    • Check font loading

Validation:

  • Run full test suite: mix test
  • All tests pass
  • No console errors
  • Good Lighthouse scores
  • Responsive on all devices

Summary of Files

Files to Create (23 files)

Shared Components (5 files):

  • lib/simpleshop_theme_web/components/shop/announcement_bar.ex
  • lib/simpleshop_theme_web/components/shop/header.ex
  • lib/simpleshop_theme_web/components/shop/footer.ex
  • lib/simpleshop_theme_web/components/shop/search_modal.ex
  • lib/simpleshop_theme_web/components/shop/product_card.ex

Infrastructure (2 files):

  • lib/simpleshop_theme_web/plugs/load_theme.ex
  • lib/simpleshop_theme_web/components/layouts/shop.html.heex

Storefront LiveViews (10 files):

  • lib/simpleshop_theme_web/live/shop_live/home.ex
  • lib/simpleshop_theme_web/live/shop_live/home.html.heex
  • lib/simpleshop_theme_web/live/shop_live/collection.ex
  • lib/simpleshop_theme_web/live/shop_live/collection.html.heex
  • lib/simpleshop_theme_web/live/shop_live/product.ex
  • lib/simpleshop_theme_web/live/shop_live/product.html.heex
  • lib/simpleshop_theme_web/live/shop_live/cart.ex
  • lib/simpleshop_theme_web/live/shop_live/cart.html.heex
  • lib/simpleshop_theme_web/live/shop_live/about.ex
  • lib/simpleshop_theme_web/live/shop_live/about.html.heex
  • lib/simpleshop_theme_web/live/shop_live/contact.ex
  • lib/simpleshop_theme_web/live/shop_live/contact.html.heex

Error Pages (1 file):

  • lib/simpleshop_theme_web/controllers/error_html/404.html.heex

Tests (6 files):

  • test/simpleshop_theme_web/plugs/load_theme_test.exs
  • test/simpleshop_theme_web/live/shop_live/home_test.exs
  • test/simpleshop_theme_web/live/shop_live/collection_test.exs
  • test/simpleshop_theme_web/live/shop_live/product_test.exs
  • test/simpleshop_theme_web/live/shop_live/cart_test.exs
  • test/simpleshop_theme_web/live/shop_live/about_test.exs

Files to Modify (9 files)

  • lib/simpleshop_theme_web/router.ex - Add plug, public routes, shop layout
  • lib/simpleshop_theme_web/components/layouts.ex - Add shop layout function
  • lib/simpleshop_theme/settings.ex - Add cache invalidation
  • lib/simpleshop_theme/application.ex - Add cache warming
  • lib/simpleshop_theme_web/live/theme_live/index.ex - Add "View Shop" link
  • lib/simpleshop_theme_web/live/theme_live/index.html.heex - Update to use shared components
  • lib/simpleshop_theme_web/live/theme_live/preview_pages.ex - Remove extracted components
  • All 7 preview page templates - Update component paths
  • lib/simpleshop_theme_web/components/shop/header.ex - Add admin link

Key Patterns to Follow

  1. CSS Application: Always use .shop-root class with data attributes on root element
  2. Component Reuse: Use shared components from components/shop/ directory
  3. Preview Data: Use PreviewData module for mock content until real Products context exists
  4. Cache Strategy: Always check CSSCache before generating CSS
  5. Theme Settings: Access via @theme_settings assign (provided by LoadTheme plug)
  6. Layout: Use :shop layout for all public pages
  7. Testing: Write tests alongside each LiveView
  8. Validation: Test each step before moving to next

Success Criteria

Public storefront accessible at / All pages (home, collection, product, cart, about, contact) render correctly Theme settings from admin are applied to storefront CSS is cached for performance Cache invalidates when theme is saved Data attributes drive theme styling All toggle features work (announcement bar, sticky header, etc.) Grid columns, layout width, and other layout settings work Logo and header image display correctly Navigation between admin and storefront works Empty states handle gracefully (no products) All tests pass Mobile responsive No console errors

Future Enhancements (After Phase 9)

  1. Products Context - Add real product management
  2. Orders & Checkout - Implement cart persistence and checkout flow
  3. Custom Domain Support - Allow users to use their own domain
  4. SEO Optimization - Meta tags, structured data, sitemaps
  5. Analytics Integration - Track visitor behavior
  6. Email Templates - Order confirmations, shipping notifications
  7. Multi-currency Support - International selling
  8. Advanced Shipping - Shipping rates, zones, carriers
  9. Discount Codes - Promotional codes and sales
  10. Customer Accounts - Registration, order history, wishlists

Notes

  • This implementation maintains perfect parity with the theme editor preview
  • No JavaScript required for theming - purely CSS-based
  • Self-contained in SQLite database (no external dependencies)
  • Performance optimized with ETS caching
  • Ready for multi-shop support in future (architecture supports it)
  • Follows Phoenix/LiveView best practices throughout
  • Mobile-first, accessible, performant

Estimated Complexity

  • Step 1 (Extract Components): Medium - Refactoring existing code
  • Step 2 (LoadTheme Plug): Easy - Simple plug implementation
  • Step 3 (Storefront Layout): Easy - Template creation
  • Step 4 (Home Page): Medium - First full LiveView
  • Step 5 (Collection Page): Medium - Filtering/sorting logic
  • Step 6 (Product Page): Medium - Variant selection, gallery
  • Step 7 (Cart Page): Medium - Cart operations
  • Step 8 (Static Pages): Easy - Simple templates
  • Step 9 (Cache Invalidation): Easy - Add function calls
  • Step 10 (Cache Warming): Easy - Application startup hook
  • Step 11 (Navigation Links): Easy - Add links
  • Step 12 (Testing & Polish): Large - Comprehensive testing

Total Effort: ~2-3 days for experienced Phoenix developer

Risk Assessment

Low Risk:

  • CSS system is proven in preview pages
  • No database schema changes needed
  • No breaking changes to existing code
  • Can test each step independently

Medium Risk:

  • Component extraction might miss edge cases
  • Cache invalidation timing could cause brief inconsistencies

Mitigation:

  • Comprehensive testing after each step
  • Keep preview pages working during refactor
  • Add logging for cache operations
  • Test cache invalidation thoroughly