Commit Graph

164 Commits

Author SHA1 Message Date
jamey
26d3bd782a add admin sidebar layout with responsive drawer navigation
- New admin root + child layouts with daisyUI drawer sidebar
- AdminLayoutHook tracks current path for active nav highlighting
- Split router into :admin, :admin_theme, :user_settings live_sessions
- Theme editor stays full-screen with back link to admin
- Admin bar on shop pages for logged-in users (mount_current_scope)
- Strip Layouts.app wrapper from admin LiveViews
- Remove nav from root.html.heex (now only serves auth pages)
- 9 new layout tests covering sidebar, active state, theme editor, admin bar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 08:35:22 +00:00
jamey
deea04885f restructure LiveView directories: admin/, shop/, auth/
Consolidates admin_live/, theme_live/, provider_live/ into admin/
(with theme/ and providers/ subdirs). Renames shop_live/ to shop/
and user_live/ to auth/. Updates all module names, router refs,
test files, CSS source paths, and dialyzer ignore.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:16:32 +00:00
jamey
e64bf40a71 add setup foundations: site gate, registration lockdown, coming soon page
- Settings.site_live?/0 and set_site_live/1 for shop visibility control
- Accounts.has_admin?/0 to detect single-tenant admin existence
- Registration lockdown: /users/register redirects when admin exists
- Setup.setup_status/0 aggregates provider, product, and stripe checks
- Coming soon page at /coming-soon with themed styling
- ThemeHook :require_site_live gate on all public shop routes
  - Site live → everyone through
  - Authenticated → admin preview through
  - No admin → fresh install demo through
  - Otherwise → redirect to coming soon
- Go live / take offline toggle on /admin/settings
- 648 tests, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 22:58:58 +00:00
jamey
093bdcc7a6 add admin redesign plan and update progress roadmap
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:51:42 +00:00
jamey
880f63e0b1 add setup wizard plan and update progress roadmap
Detailed plan for setup wizard, go-live gate, and registration
lockdown. Covers single-admin account creation, coming soon page,
admin setup checklist, and platform compatibility notes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 16:35:25 +00:00
jamey
8287222b54 use LiveView navigation and add SVG fallback dimensions to fix FOUC
All internal links used plain <a href>, causing full page reloads
between pages in the same live_session. Changed to <.link navigate>
for client-side navigation across layout, product, cart, base, and
content components.

Added explicit width/height attributes to all SVG icons so they
render at sensible sizes before CSS loads on initial page visit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:46:12 +00:00
jamey
0d583ca9a8 fix collection filters, hero spacing, sale filter, and error page CSS
- collection filter bar: horizontal scroll on mobile instead of wrapping
  across 3 rows, smaller pills at mobile sizes
- add sale collection filter at /collections/sale (filters on_sale products)
- hero :page variant: add consistent top padding (var(--space-2xl))
- contact page: remove redundant top padding (hero handles it now)
- error page: fix CSS path from /assets/app.css to /assets/css/app.css
  (broken in production due to asset fingerprinting)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 08:38:54 +00:00
jamey
7c9fe57e6e fix product card image swipe blocked by stretched-link overlay
The stretched-link ::after pseudo-element (z-index: 0) was covering
the image area, intercepting touch events. Give the image container
z-index: 1 so swipe gestures reach the scroll container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 08:22:13 +00:00
jamey
e9a824ec0b simplify footer categories: fetch directly instead of threading assigns
shop_footer now calls PreviewData.categories() itself, removing the
need to thread categories through CartHook, shop_layout, and all 8
page templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 08:20:50 +00:00
jamey
209ae7aee7 fix navigation links, footer categories, product card structure, and social icons
- add missing cta_href to hero section and error page CTAs
- replace hardcoded footer shop links with real product categories
- restructure product cards with stretched-link pattern so category
  badges link to their collection page
- unify social icons: footer and contact page share the same default
  links from a single source in content.ex
- add search implementation plan (docs/plans/search.md, deferred)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 08:17:19 +00:00
jamey
ac46c1504f remove redundant "view basket" link from cart drawer
The drawer now has full quantity controls, remove, subtotal, and
checkout — the link to the cart page added friction without value.
Cart page remains accessible via the basket icon in nav.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 00:32:15 +00:00
jamey
b3d1019cd4 add quantity controls to cart drawer via shared CartHook
Move increment/decrement handlers from Cart LiveView into CartHook so
they work from any page's drawer. Enable show_quantity_controls on the
drawer's cart_item_row. Scope cart tests to #main-content to avoid
duplicate button matches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 00:15:04 +00:00
jamey
3c73b98d2b fix PDP quantity selector and trust badge consistency
Wire up +/− buttons with phx-click events and handle_event handlers,
clamp to 1–99, reset to 1 after add-to-cart. Trust badges now use a
single hero-check-circle icon and sentence case text.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 23:15:09 +00:00
jamey
8775c2eeef drop redundant "Home" from PDP breadcrumbs
Logo already links home; breadcrumb now starts at category.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:59:34 +00:00
jamey
dc8bf28892 fix breadcrumb styling: semantic markup, chevron separators, mobile sizing
Rewrite breadcrumb as semantic ol/li with aria-current="page", CSS
chevron separators, 0.875em font size, and ellipsis truncation on
mobile for long product names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:58:26 +00:00
jamey
8445e9e8b1 replace PDP image gallery with scroll-snap carousel
Mobile: swipeable carousel with dot indicators, no lightbox trigger.
Desktop: carousel with thumbnail grid, prev/next arrows, click to
open existing lightbox. Keeps all lightbox appearance and behaviour.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:33:41 +00:00
jamey
1a69736734 add mobile swipe for product card images and fix dev asset caching
Product cards now use CSS scroll-snap on touch devices (mobile) for
swiping between images, with dot indicators and a JS hook for active
state. Desktop keeps the existing hover crossfade via @media (hover:
hover). Dots use size differentiation (WCAG 2.2 AA compliant) with
outline rings for contrast on any background.

Also fixes: no-image placeholder (SVG icon instead of broken img),
unnecessary wrapper div for single-image cards, and dev static asset
caching (was immutable for all envs, now only prod).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:24:52 +00:00
jamey
19b4a5bd59 add variants to all mock products and fix CSSCache race condition
All 16 mock products now have at least one variant so add-to-cart works
in demo mode. CSSCache.invalidate/0 rescues ArgumentError when the ETS
table doesn't exist yet (seed_defaults runs before CSSCache starts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:12:57 +00:00
jamey
90b0242a06 fix cart hydration for demo mode with mock products
Cart.hydrate/1 now falls back to PreviewData mock products when variant
IDs aren't found in the database, so add-to-cart works on fresh deploys
without synced Printify data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 08:20:59 +00:00
jamey
c5e353eba1 improve lighthouse scores: image priority and long-poll removal
- Add priority attr to product_card, thread through to responsive_image
- First 2 featured products get fetchpriority="high" and eager loading
- Remove longPollFallbackMs to avoid unnecessary fallback attempt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 23:43:01 +00:00
jamey
865e3563b6 fix production deployment: CSS, images and theme seeding
- Add @source for shop_components/ directory in app-shop.css (Tailwind
  wasn't scanning sub-modules after the refactor, dropping ~73 utilities)
- Remove overly aggressive .dockerignore rules that excluded mockup
  image variants needed by the responsive_image component
- Seed default theme settings on first boot via Release.seed_defaults/0
  in the supervision tree (seeds.exs doesn't run in releases)
- Fix PDP gallery images for mock data by appending -1200.webp to
  bare mockup base paths
- Update fly.toml format from fly launch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 23:42:56 +00:00
jamey
eb51385525 combine e2e and a11y testing into single roadmap item (Wallaby + A11yAudit)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:43:11 +00:00
jamey
e4444437bb update PROGRESS.md: mark PageSpeed CI as complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:29:51 +00:00
jamey
1f4e938ed1 enable gzip on Plug.Static unconditionally
Plug.Static with gzip: true serves .gz files when they exist
(created by phx.digest) and falls back to uncompressed otherwise.
The previous code_reloading? guard was needlessly conservative —
in dev without digested assets, there are no .gz files so nothing
changes. With the lighthouse task building prod assets, this gives
realistic transfer sizes (42KB JS vs 135KB).

Mobile lighthouse scores jump from 95-97 to 99-100.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:23:53 +00:00
jamey
516d0d0070 add mix lighthouse task for PageSpeed auditing
Single-file Mix task that runs Google Lighthouse against the shop
and checks scores against configurable thresholds. Builds production
assets (minified + digested) before auditing for realistic scores.
Waits for image variant cache to finish processing. Supports mobile/
desktop modes, custom thresholds, multiple pages. All 4 key pages
score 95+ on mobile, 97+ on desktop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:18:01 +00:00
jamey
88291f276b add observability: LiveDashboard in prod, error tracking, JSON logging
- Move LiveDashboard to /admin/dashboard behind session auth (all envs)
- Add ErrorTracker at /admin/errors for auto-captured exceptions
- Add Oban job and LiveView metrics to telemetry module
- Add logger_json for structured JSON logs in production
- Enable os_mon for CPU/disk/memory in LiveDashboard OS Data tab
- Extend logger metadata with oban_worker and oban_queue fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 17:02:21 +00:00
jamey
1ee37c853d add Docker deployment with Alpine image, release config and health check
- Alpine multi-stage Dockerfile (131 MB image)
- Release overlays (bin/server, bin/migrate), env.sh, Release module
- Health check endpoint at GET /health
- Fly.io config with SQLite volume mount
- Fix hardcoded paths in optimizer.ex and variant_cache.ex to use
  Application.app_dir/2 (breaks in releases where Plug.Static serves
  from a different directory than CWD)
- strip_beams: true in release config
- Optimised .dockerignore and .gitignore for mockup variants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:21:05 +00:00
jamey
eaa4bbb3fa add CI pipeline with credo and dialyzer
mix ci alias: compile --warning-as-errors, format --check-formatted,
credo, dialyzer, test. Credo configured with sensible defaults.
Dialyzer ignore file for false positives (Stripe types, Mix tasks,
ExUnit internals). Credo fixes: map_join, filter consolidation,
nesting extraction, cond→if simplification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 15:19:42 +00:00
jamey
518da36c8f add integration tests for product, cart and home pages
37 new LiveView integration tests covering the three previously
untested shop pages. Product detail tests cover variant selection,
price updates and add-to-cart. Cart tests use DB fixtures with
session seeding for hydration. Home tests cover hero, categories,
featured products and navigation links. 612 total tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 14:57:10 +00:00
jamey
3b8d5faf3b refactor: consolidate settings lookups and secrets loading
- Extract fetch_setting/1 in Settings (4 callsites → 1 repo lookup)
- Replace hardcoded load_stripe_config with registry-driven load_all
- Adding new secrets is now a one-line @secret_registry entry
- Mark DRY refactor plan as complete (all 8 items done)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 14:42:13 +00:00
jamey
3eacd91fda refactor: split shop_components.ex into 5 focused sub-modules
4,487-line monolith → 23-line facade + 5 modules:
- Base (inputs, buttons, cards)
- Layout (header, footer, mobile nav, shop_layout)
- Cart (drawer, items, order summary)
- Product (cards, gallery, variant selector, hero)
- Content (rich text, images, contact, reviews)

`use SimpleshopThemeWeb.ShopComponents` imports all sub-modules.
No single file over ~1,600 lines now.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 14:30:25 +00:00
jamey
cb4698bec8 refactor: extract Cart.build_state/1 as single source of truth for cart state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:24:39 +00:00
jamey
2825537136 refactor: extract common preview assigns helper in theme editor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:12:39 +00:00
jamey
8be1f90f2d refactor: extract shop_layout component to eliminate template boilerplate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:10:08 +00:00
jamey
e6d4fce656 refactor: extract ThemeHook to eliminate mount duplication
on_mount hook assigns theme_settings, generated_css, logo_image,
header_image, and mode for all public shop LiveViews. Removes
~70 lines of identical boilerplate and 18 unused aliases across
7 LiveViews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:59:33 +00:00
jamey
dd19281f4f docs: add codebase metrics and impact analysis to DRY refactor plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:42:58 +00:00
jamey
5b08591a55 docs: add DRY refactor plan and update progress
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:18:58 +00:00
jamey
db02c0b414 refactor: use assigns spread in page LiveView render functions
Replace verbose explicit attr passing with {assigns} spread for
home, contact, cart, product show and checkout success LiveViews.
Collection skipped (inline rendering, no template component).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 10:53:06 +00:00
jamey
5a43cfc761 feat: add default content pages for delivery, privacy and terms
Replace one-off ShopLive.About with generic ShopLive.Content that
handles all static content pages via live_action. Add delivery &
returns, privacy policy, and terms of service pages with sample
content. Update footer help links and theme editor preview.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 10:47:54 +00:00
jamey
0af8997623 feat: add transactional emails for order confirmation and shipping
Plain text emails via Swoosh OrderNotifier module. Order confirmation
triggered from Stripe webhook after payment, shipping notification
from Printify shipment webhook with polling fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 10:17:19 +00:00
jamey
3e19887499 feat: add Printify order submission and fulfilment tracking
Submit paid orders to Printify via provider API with idempotent
guards, Stripe address mapping, and error handling. Track fulfilment
status through submitted → processing → shipped → delivered via
webhook-driven updates (primary) and Oban Cron polling fallback.

- 9 fulfilment fields on orders (status, provider IDs, tracking, timestamps)
- OrderSubmissionWorker with retry logic, auto-enqueued after Stripe payment
- FulfilmentStatusWorker polls every 30 mins for missed webhook events
- Printify order webhook handlers (sent-to-production, shipment, delivered)
- Admin UI: fulfilment column in table, fulfilment card with tracking info,
  submit/retry and refresh buttons on order detail
- Mox provider mocking for test isolation (Provider.for_type configurable)
- 33 new tests (555 total), verified against real Printify API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 09:51:51 +00:00
jamey
02cdc810f2 feat: add order management admin with list and detail views
Admin UI at /admin/orders to view, filter, and inspect orders.
Adds list_orders/1 and count_orders_by_status/0 to the Orders
context, status filter tabs, clickable order table with streams,
and a detail page showing items, totals, and shipping address.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 21:59:14 +00:00
jamey
e6f8d7fa2a docs: add prioritised roadmap with all planned features
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:28:28 +00:00
jamey
d65eb725f7 docs: update progress with Stripe setup and checkout completion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 18:04:18 +00:00
jamey
eede9bb517 feat: add encrypted settings, guided Stripe setup, and admin credentials page
Store API keys and secrets encrypted in the SQLite database via the
existing Vault module (AES-256-GCM). The only external dependency is
SECRET_KEY_BASE — everything else lives in the portable DB file.

- Add encrypted_value column to settings table with new "encrypted" type
- Add put_secret/get_secret/delete_setting/secret_hint to Settings context
- Add Secrets module to load encrypted config into Application env at startup
- Add Stripe.Setup module with connect/disconnect/verify_api_key flow
  - Auto-creates webhook endpoints via Stripe API in production
  - Detects localhost and shows Stripe CLI instructions for dev
- Add admin credentials page at /admin/settings with guided setup:
  - Not configured: single Secret key input with dashboard link
  - Connected (production): status display, webhook info, disconnect
  - Connected (dev): Stripe CLI instructions, manual signing secret input
- Remove Stripe env vars from dev.exs and runtime.exs
- Fix CSSCache test startup crash (handle_continue instead of init)
- Add nav link for Credentials page

507 tests, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 17:12:53 +00:00
jamey
ff1bc483b9 feat: add Stripe checkout, order persistence, and webhook handling
Stripe-hosted Checkout integration with full order lifecycle:
- stripity_stripe ~> 3.2 with sandbox/prod config via env vars
- Order and OrderItem schemas with price snapshots at purchase time
- CheckoutController creates pending order then redirects to Stripe
- StripeWebhookController verifies signatures and confirms payment
- Success page with real-time PubSub updates from webhook
- Shop flash messages for checkout error feedback
- Cart cleared after successful payment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 08:30:17 +00:00
jamey
cff21703f1 fix: update demo content, fix broken links, and add cart item product links
- Replace all placeholder text with demo-aware copy that signals "replace me"
- Update USPs for POD accuracy (made to order, quality materials)
- Fix broken footer links (/delivery, /returns → /contact)
- Add real platform URLs to social icons with target="_blank"
- Make cart item images and names link to product pages
- Switch about page image to responsive_image component
- Add missing cart_status to collection page cart drawer
- Unify search hint text across all page templates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 23:33:22 +00:00
jamey
1bc08bfb23 feat: add cart page, cart drawer, and shared cart infrastructure
- Cart context with pure functions for add/remove/update/hydrate
- Price formatting via ex_money (replaces all float division)
- CartHook on_mount with attach_hook for shared event handlers
  (open/close drawer, remove item, PubSub sync)
- Accessible cart drawer with focus trap, scroll lock, aria-live
- Cart page with increment/decrement quantity controls
- Preview mode cart drawer support in theme editor
- Cart persistence to session via JS hook + API endpoint
- 19 tests covering all Cart pure functions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 19:39:37 +00:00
jamey
880e7a2888 feat: add dynamic variant selector with color swatches
- Fix Printify options parsing (Color/Size were swapped)
- Add extract_option_types/1 for frontend display with hex colors
- Filter option types to only published variants (not full catalog)
- Track selected variant in LiveView with price updates
- Color swatches for color-type options, text buttons for size
- Disable unavailable combinations
- Add startup recovery for stale sync status

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:17:48 +00:00
jamey
1b49b470f2 feat: add product image download pipeline for PageSpeed 100%
Downloads Printify CDN images via ImageDownloadWorker, processes
through Media pipeline (WebP conversion, AVIF/WebP variant generation),
and links to ProductImage via new image_id FK.

- Add image_id to product_images table
- ImageDownloadWorker downloads and processes external images
- sync_product_images preserves image_id when URL unchanged
- PreviewData uses local images for responsive <picture> elements
- VariantCache enqueues pending downloads on startup
- mix simpleshop.download_images backfill task

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 00:26:19 +00:00