Bring in plan for phase 9

This commit is contained in:
Jamey Greenwood 2026-01-01 16:37:55 +00:00
parent 6d66d56b62
commit 48b1e0bc96
3 changed files with 1414 additions and 35 deletions

923
PHASE_9_PLAN.md Normal file
View File

@ -0,0 +1,923 @@
# 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:**
```elixir
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:**
```heex
<!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:**
```elixir
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:**
```elixir
# 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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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:**
```elixir
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
---
### Step 11: Update Navigation Links
**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:**
```heex
<%= if @current_user do %>
<a href={~p"/admin/theme"} class="admin-link">
Edit Theme
</a>
<% end %>
```
**Theme editor changes (add near "Save Theme" button):**
```heex
<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

419
PHASE_9_PROGRESS.md Normal file
View File

@ -0,0 +1,419 @@
# Phase 9: Storefront Integration - Progress Tracker
**Last Updated:** 2026-01-01
**Status:** Not Started
**Current Step:** Step 0 (Preparation)
## Quick Reference
- **Detailed Plan:** `.claude/plans/snuggly-forging-cat.md`
- **Main Plan:** `PLAN.md` (lines 643-690)
- **Spec:** `SPEC.md`
## Progress Overview
- [ ] Step 1: Extract Shared Components
- [ ] Step 2: Create LoadTheme Plug
- [ ] Step 3: Create Storefront Layout
- [ ] Step 4: Create Home Page LiveView
- [ ] Step 5: Create Collection Page LiveView
- [ ] Step 6: Create Product Detail Page (PDP) LiveView
- [ ] Step 7: Create Cart Page LiveView
- [ ] Step 8: Create Static Pages (About, Contact, Error)
- [ ] Step 9: Wire Up CSS Cache Invalidation
- [ ] Step 10: Add Cache Warming on Application Start
- [ ] Step 11: Update Navigation Links
- [ ] Step 12: Testing and Polish
**Completion:** 0/12 steps (0%)
---
## Step-by-Step Progress
### Step 1: Extract Shared Components
**Status:** ❌ Not Started
**Git Commit:** `refactor: extract shared shop components from preview pages`
**Goal:** Move reusable preview components to `components/shop/` for use in both admin and storefront
**Files to Create (5):**
- [ ] `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 (8):**
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages.ex` - Import new components
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/home.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/pdp.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/cart.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/about.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/contact.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/error.html.heex`
**Validation:**
- [ ] Run `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- [ ] Visit `/admin/theme` - verify all 7 preview pages still render
- [ ] No visual regressions
**Notes:**
---
### Step 2: Create LoadTheme Plug
**Status:** ❌ Not Started
**Git Commit:** `feat: add LoadTheme plug for public storefront`
**Goal:** Create plug that loads theme settings and CSS for every public request
**Files to Create (2):**
- [ ] `lib/simpleshop_theme_web/plugs/load_theme.ex`
- [ ] `test/simpleshop_theme_web/plugs/load_theme_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add plug to `:browser` pipeline
**Validation:**
- [ ] Run `mix test test/simpleshop_theme_web/plugs/load_theme_test.exs`
- [ ] Verify assigns available in requests
- [ ] Verify CSS cached and reused
**Notes:**
---
### Step 3: Create Storefront Layout
**Status:** ❌ Not Started
**Git Commit:** `feat: add shop layout with theme CSS injection`
**Goal:** Create dedicated layout for public storefront with theme CSS injection
**Files to Create (1):**
- [ ] `lib/simpleshop_theme_web/components/layouts/shop.html.heex`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/components/layouts.ex` - Add `shop/1` function
**Validation:**
- [ ] Inspect HTML - verify data attributes present
- [ ] Verify CSS injection works
- [ ] Layout compiles without errors
**Notes:**
---
### Step 4: Create Home Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add public home page with theme support`
**Goal:** Create public homepage LiveView using real/mock data
**Files to Create (3):**
- [ ] `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`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/", ShopLive.Home, :index`
**Validation:**
- [ ] Visit `/` - verify homepage renders
- [ ] Theme styles applied correctly
- [ ] Announcement bar toggle works
- [ ] Header layout variations work
- [ ] Sticky header toggle works
- [ ] Products display (mock data)
**Notes:**
---
### Step 5: Create Collection Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add collection/product grid page with filtering`
**Goal:** Create product collection/grid page with filtering and sorting
**Files to Create (3):**
- [ ] `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`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add routes for collections
**Validation:**
- [ ] Visit `/collections` and `/collections/:slug`
- [ ] Filter sidebar works
- [ ] Sort dropdown works
- [ ] Grid columns (2, 3, 4) work
- [ ] Card shadow setting respected
- [ ] Hover image toggle works
**Notes:**
---
### Step 6: Create Product Detail Page (PDP) LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add product detail page with gallery and variants`
**Goal:** Create individual product page with gallery, details, add to cart
**Files to Create (3):**
- [ ] `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`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/products/:slug"`
**Validation:**
- [ ] Visit `/products/:slug`
- [ ] Variant selection works
- [ ] Image gallery works
- [ ] Trust badges show/hide based on setting
- [ ] Reviews show/hide based on setting
- [ ] Related products show/hide based on setting
- [ ] Add to cart shows flash
- [ ] Gallery position (left/right) works
**Notes:**
---
### Step 7: Create Cart Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add shopping cart page with line items`
**Goal:** Create shopping cart page with line items and checkout
**Files to Create (3):**
- [ ] `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`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/cart"`
**Validation:**
- [ ] Visit `/cart`
- [ ] Quantity update works
- [ ] Remove item works
- [ ] Price calculations correct
- [ ] Empty cart state works
- [ ] Checkout button shows flash
- [ ] Button style setting respected
**Notes:**
---
### Step 8: Create Static Pages (About, Contact, Error)
**Status:** ❌ Not Started
**Git Commit:** `feat: add static pages (about, contact, 404) with theme support`
**Goal:** Create remaining static pages
**Files to Create (6):**
- [ ] `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`
- [ ] `test/simpleshop_theme_web/live/shop_live/about_test.exs`
- [ ] `test/simpleshop_theme_web/live/shop_live/contact_test.exs`
**Files to Modify (2):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add routes
- [ ] `lib/simpleshop_theme_web/controllers/error_html.ex` - Add 404 template (or create if missing)
**Validation:**
- [ ] Visit `/about` - page renders
- [ ] Visit `/contact` - form works
- [ ] Visit invalid URL - 404 shows with theme
- [ ] All pages respect theme settings
**Notes:**
---
### Step 9: Wire Up CSS Cache Invalidation
**Status:** ❌ Not Started
**Git Commit:** `feat: add CSS cache invalidation on theme save`
**Goal:** Ensure CSS cache invalidates when theme settings saved
**Files to Modify (2):**
- [ ] `lib/simpleshop_theme/settings.ex` - Add cache invalidation to `update_theme_settings/1`
- [ ] `lib/simpleshop_theme_web/live/theme_live/index.ex` - Ensure save triggers invalidation
**Validation:**
- [ ] Change theme in admin
- [ ] Save theme
- [ ] Visit storefront
- [ ] Verify changes reflected immediately
- [ ] Check cache being used
**Notes:**
---
### Step 10: Add Cache Warming on Application Start
**Status:** ❌ Not Started
**Git Commit:** `feat: add CSS cache warming on application startup`
**Goal:** Pre-generate and cache theme CSS when app starts
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme/application.ex` - Add cache warming after supervisor start
**Validation:**
- [ ] Restart application
- [ ] Check logs for "Theme CSS cache warmed successfully"
- [ ] Visit storefront immediately (should be fast)
- [ ] No DB queries for CSS on first request
**Notes:**
---
### Step 11: Update Navigation Links
**Status:** ❌ Not Started
**Git Commit:** `feat: add navigation between admin and storefront`
**Goal:** Connect theme editor to storefront and vice versa
**Files to Modify (2):**
- [ ] `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
**Validation:**
- [ ] When logged in on storefront, "Edit Theme" link appears
- [ ] Click link - navigates to theme editor
- [ ] In theme editor, click "View Shop" link
- [ ] Opens storefront in new tab
**Notes:**
---
### Step 12: Testing and Polish
**Status:** ❌ Not Started
**Git Commit:** `test: add comprehensive tests and polish for Phase 9`
**Goal:** Comprehensive testing and UX improvements
**Testing Areas:**
- [ ] All storefront LiveViews tested
- [ ] Plug behavior tested
- [ ] Cache invalidation flow tested
- [ ] Theme application across all pages tested
- [ ] Responsive behavior tested
**Polish Areas:**
- [ ] Loading states added
- [ ] Error handling complete
- [ ] Performance optimized
- [ ] Accessibility checked
- [ ] Mobile tested
- [ ] Cross-browser tested
**Validation:**
- [ ] Run `mix test` - all tests pass
- [ ] No console errors
- [ ] Good Lighthouse scores
- [ ] Responsive on all devices
**Notes:**
---
## Git Commit Log
Track all commits made during Phase 9 implementation:
```
# Commits will be added here as we progress
# Format: [YYYY-MM-DD HH:MM] <commit-hash> <commit-message>
```
---
## Issues / Blockers
Track any issues encountered:
- None yet
---
## Future Enhancements (Post-Phase 9)
1. Products Context - Add real product management
2. Orders & Checkout - Cart persistence and checkout flow
3. Custom Domain Support
4. SEO Optimization
5. Analytics Integration
6. Email Templates
7. Multi-currency Support
8. Advanced Shipping
9. Discount Codes
10. Customer Accounts
---
## Context Preservation
**Key Architectural Decisions:**
- CSS applied via `.shop-root` class with data attributes
- Same three-layer CSS system as theme editor
- LoadTheme plug provides `@theme_settings` and `@generated_css` assigns
- CSS cached in ETS via `CSSCache` GenServer
- Preview data used until real Products context exists
- Shared components in `components/shop/` directory
**Critical Files:**
- Theme editor: `lib/simpleshop_theme_web/live/theme_live/index.ex`
- CSS generator: `lib/simpleshop_theme/theme/css_generator.ex`
- Settings context: `lib/simpleshop_theme/settings.ex`
- Preview data: `lib/simpleshop_theme/theme/preview_data.ex`
**Current State (as of last update):**
- Theme editor fully functional at `/admin/theme`
- 8 presets working with real-time preview
- All customization options implemented
- Logo/header uploads with BLOB storage working
- SVG recoloring functional
- No public storefront routes yet (Phase 9 not started)
---
## How to Use This File
1. **Starting a new step:** Update the step status to "🚧 In Progress"
2. **Completing files:** Check off files as created/modified
3. **Finishing a step:**
- Mark step as "✅ Complete"
- Update completion percentage
- Make git commit with specified message
- Add commit to Git Commit Log section
4. **Encountering issues:** Add to Issues/Blockers section
5. **Taking notes:** Add to Notes field for each step
**For new conversations:** Read this file first to understand current progress and context.

107
PLAN.md
View File

@ -170,9 +170,38 @@ test/simpleshop_theme_web/
└── theme_live_test.exs # LiveView integration tests
```
## Implementation Phases
## Implementation Status
### Phase 1: Database Foundation ✓
### Completed Phases (1-8): ✅
- ✅ Phase 1: Database Foundation
- ✅ Phase 2: CSS Architecture
- ✅ Phase 3: Smart Preview Data
- ✅ Phase 4: Theme LiveView (Basic)
- ✅ Phase 5: Preview Pages
- ✅ Phase 6: Customization Options
- ✅ Phase 6.5: Fix Theme Visual Application
- ✅ Phase 7: File Uploads (Logo & Header)
- ✅ Phase 8: Persistence & Polish
### Current Phase: Phase 9 - Storefront Integration 🚧
**See detailed Phase 9 plan at:** `.claude/plans/snuggly-forging-cat.md`
**Phase 9 Goal:** Apply the theme system to the actual public-facing storefront
**Key deliverables:**
- Public storefront routes (`/`, `/products/:slug`, `/collections`, `/cart`, etc.)
- Storefront LiveViews using real/mock data
- LoadTheme plug to inject theme settings and CSS
- CSS cache integration for performance
- Navigation between admin theme editor and public shop
- All 7 pages working on storefront (home, collection, product, cart, about, contact, error)
---
## Implementation Phases (Details)
### Phase 1: Database Foundation ✅
**Goal:** Set up Settings and Media models for site-wide configuration
**Steps:**
@ -611,45 +640,53 @@ The demo HTML uses data attributes (`data-mood="warm"`, `data-typography="editor
---
### Phase 9: Storefront Integration
### Phase 9: Storefront Integration 🚧
**Goal:** Apply theme to actual public-facing shop
**Steps:**
1. Create public shop routes in router:
- `get "/:shop_slug", ShopController, :show` (shop homepage)
- Or use domain-based routing for custom domains
2. Create `lib/simpleshop_theme_web/live/shop_live/` directory for storefront LiveViews
3. Create storefront page templates that respect theme settings:
- Use same CSS system as preview
- Load theme CSS from cache
- Render actual products (when they exist) or empty states
4. Create `lib/simpleshop_theme_web/plugs/load_shop_theme.ex`:
- Load shop by domain/slug
- Load theme CSS from cache
- Assign to `conn.assigns.theme_css`
5. Add theme CSS to root layout for storefront
6. Implement proper caching headers for theme CSS
7. Handle theme CSS cache warming on app startup
**Status:** Ready to implement - See detailed plan in `.claude/plans/snuggly-forging-cat.md`
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/*` (storefront pages)
- `lib/simpleshop_theme_web/plugs/load_theme.ex`
- `test/simpleshop_theme_web/live/shop_live_test.exs`
- `test/simpleshop_theme_web/plugs/load_theme_test.exs`
**High-level overview:**
1. Extract shared components from preview pages (header, footer, product card, etc.)
2. Create LoadTheme plug to inject theme settings and CSS into all public requests
3. Create dedicated shop layout with `.shop-root` class and data attributes
4. Build storefront LiveViews for all pages:
- Home (`/`)
- Collection (`/collections/:slug`)
- Product Detail (`/products/:slug`)
- Cart (`/cart`)
- About (`/about`)
- Contact (`/contact`)
- Error (404 page)
5. Wire up CSS cache invalidation when theme is saved
6. Add cache warming on application startup
7. Add navigation links between admin and storefront
8. Comprehensive testing and polish
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Public shop routes
- `lib/simpleshop_theme_web/components/layouts.ex` - Theme CSS injection
- Root layout template
**Key files to create (23 files):**
- 5 shared component modules in `components/shop/`
- 1 LoadTheme plug
- 1 shop layout template
- 6 storefront LiveView modules + templates
- 1 error page template
- 6 test files
**Git commit:** `feat: integrate theme system with public storefront`
**Key files to modify (9 files):**
- Router (add public routes and plug)
- Settings context (add cache invalidation)
- Application (add cache warming)
- Theme editor (add "View Shop" link)
- Preview pages (use shared components)
**Validation:**
- Run tests: `mix test`
- Visit public shop URL, verify theme applies correctly
- Change theme in admin, verify storefront updates
- Test CSS cache invalidation
- Verify performance with caching headers
**Detailed implementation plan:** See `.claude/plans/snuggly-forging-cat.md` for 12-step implementation guide with code examples, validation steps, and architectural decisions.
**Git commit strategy:** Commit after each major step (components extraction, plug creation, each LiveView, etc.)
**Validation approach:**
- Test theme editor still works after component extraction
- Test each storefront page individually as built
- Verify CSS cache invalidation flow
- Test navigation between admin and storefront
- Comprehensive testing in Step 12
---