- fix Site tab not loading theme state on direct URL navigation
- fix nav editor showing "Custom URL" for page links (detect by URL match)
- add Home option to nav page picker
- mark editor-reorganisation plan as complete
- add dynamic-url-customisation and draft-publish-workflow plans
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add discontinued status to products (soft-delete when removed from provider)
- add availability helpers to variants (available/out_of_stock/discontinued)
- add detailed sync audit logging (product created/updated/discontinued)
- add cost change detection with threshold alerts (5% warning, 20% critical)
- update cart to show unavailable items with appropriate messaging
- block checkout when cart contains unavailable items
- show discontinued badge on product pages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Custom page settings (title, slug, meta, published, navigation) now
appear as a collapsible section at the top of the Page tab. The
separate Settings tab has been fully removed.
- Add page_settings_section component to page_renderer.ex
- Remove dead :settings case from editor_panel_content
- Delete settings_editor.ex component entirely
- Remove SettingsEditor import from shop_components.ex
- Add .page-settings-* CSS styles
- Clean up old .settings-* CSS styles
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add header and footer nav editors to Site tab with drag-to-reorder,
add/remove items, and destination picker (pages, collections, external)
- Live preview updates as you edit nav items
- Remove legacy /admin/navigation page and controller (was saving to
Settings table, now uses nav_items table)
- Update error_html.ex and pages/editor.ex to load nav from nav_items table
- Update link_scanner to read from nav_items table, edit path now /?edit=site
- Add Site.default_header_nav/0 and default_footer_nav/0 for previews/errors
- Remove fallback logic from theme_hook.ex (database is now source of truth)
- Seed default nav items and social links during setup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Mark tasks 1-9 and 15-16 as done in editor-reorganisation plan
- Update plan status from Planned to In Progress
- Add implementation notes documenting social links architecture
- Update test count to 1800+ in PROGRESS.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Site context for managing site-wide content (social links, nav items,
announcement bar, footer content)
- Add SocialLink schema with URL normalization and platform auto-detection
supporting 40+ platforms via host and 25+ via URI scheme
- Add NavItem schema for header/footer navigation (editor UI coming next)
- Add SiteEditor component with collapsible sections for each content type
- Wire social links card block and footer to use database data
- Filter empty URLs from display in shop components
- Add DetailsPreserver hook to preserve collapsible section state
- Add comprehensive tests for Site context and SocialLink functions
- Remove unused helper functions from onboarding to fix compiler warnings
- Move sync_edit_url_param helper to group handle_editor_event clauses
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use async message passing for create_backup to update UI immediately.
Add phx-throttle and pointer-events:none to fully prevent double-clicks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move maybe_sync_editing_blocks to run after module.handle_params since
Content pages (about, delivery, privacy, terms) set @page in handle_params
rather than init. Previously editing_blocks would show stale content from
the previous page.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Install sqlcipher-dev in builder stage
- Configure exqlite to use system SQLCipher
- Add sqlcipher-libs to runtime image
- Exclude mockups/ from live reload patterns
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Include is_available flag in hydrated cart items
- Show unavailable message on cart items and product page
- Block add-to-cart for unavailable variants
- Redirect back to cart with error if checkout has unavailable items
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- SQLCipher-encrypted backup creation via VACUUM INTO
- Backup history with auto-pruning (keeps last 5)
- Pre-restore automatic backup for safety
- Restore from history or uploaded file
- Stats display with table breakdown
- Download hook for client-side file download
- SECRET_KEY_DB config for encryption at rest
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tasks C, H, I from the plan:
- Forgiving API key validation: add Printify UUID format and Printful
length validation, validate on blur for fast feedback, helpful error
messages with specific guidance
- External links UX: verified all external links use <.external_link>
component with target="_blank", rel="noopener noreferrer", icon, and
screen reader text
- Input styling WCAG compliance: increase input border contrast from
~3.3:1 to ~4.5-5:1 across all theme moods (neutral, warm, cool, dark)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add ?edit=page/theme/settings param when opening editor or switching tabs
- remove ?edit param when closing editor
- restore .themed class on shop_root for editor panel background tokens
- collapse editor when navigating back to URL without ?edit param
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All 7 phases done. Admins can now edit theme and page content directly
on the live shop via /?edit=theme, /?edit=page, or /?edit=settings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The shop_root.html.heex had duplicate .themed element with data-mood etc
attributes that were static (rendered once at page load). This prevented
live theme changes from visually updating since CSS matched the outer
stale element.
Fix: Remove data attributes from shop_root.html.heex, keeping only the
live-updated .shop-container.themed element inside the LiveView.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Phase 5 was already implemented (URL mode activation via ?edit param)
- Phase 6: Add RedirectController to redirect /admin/theme → /?edit=theme
- Update admin sidebar and dashboard links to point directly to /?edit=theme
- Delete old Admin.Theme.Index LiveView and template (no longer needed)
- Update tests for new redirect behavior
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 of unified editing: image upload handling in hook context.
- Configure uploads in Shop.Page mount for logo, header, icon
- Add upload UI components to theme_editor compact_editor
- Pass uploads through page_renderer to theme editor
- Add cancel_upload handler to PageEditorHook
Also fixes scroll position not resetting on patch navigation:
- Push scroll-top event when path changes in handle_params
- JS listener scrolls window to top instantly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When navigating between page types in the unified shop LiveView,
assigns from the previous page could persist and cause stale data
to appear or template errors. Now explicitly nils them out.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The provider_label function was accessing product.provider_type but
that field is on the provider_connection association, not the product
itself. Handle the case where the association may not be preloaded.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 3b of unified editing mode. The Settings tab now shows
context-specific forms: custom pages get editable title, slug,
meta, visibility and nav options; system pages get read-only info
with links to admin; product/collection pages show provider info.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace individual shop LiveViews with a single Shop.Page that dispatches
to page modules based on live_action. This enables patch navigation between
pages, preserving socket state (including editor state) across transitions.
Changes:
- Add Shop.Page unified LiveView with handle_params dispatch
- Extract page logic into Shop.Pages.* modules (Home, Product, Collection, etc.)
- Update router to use Shop.Page with live_action for all shop routes
- Change navigate= to patch= in shop component links
- Add maybe_sync_editing_blocks to reload editor state when page changes
- Track editor_page_slug to detect cross-page navigation while editing
- Fix picture element height when hover image disabled
- Extract ThemeEditor components for shared use
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Plan for auto-saving drafts with explicit publish. Visitors always see
published version, admins see their drafts while editing. Removes need
for beforeunload warnings since work is never lost.
Planned to follow unified-editing-mode completion.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fly.io internal health checks are made over HTTP, so they get redirected
to HTTPS with a 301 which fails the health check. Exclude /health path
from SSL enforcement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove global margin-left: auto from .shop-actions since it conflicts
with justify-content: space-between in the standard header layout.
Keep margin-left: auto only for the left layout variant where it's
needed. Also fix .shop-cart → .shop-actions selector in layer2.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
force_ssl must be set at compile time (in prod.exs), not runtime.
Phoenix validates compile-time config at boot and was crashing
because the value differed between compile and runtime.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add theme editing to the existing PageEditorHook, enabling on-site
theme customisation alongside page editing. The editor panel now has
three tabs (Page, Theme, Settings) and can be collapsed while
keeping editing state intact.
- Add theme editing state and event handlers to PageEditorHook
- Add 3-tab UI with tab switching logic
- Add transparent overlay for click-outside dismiss
- Add mobile drag-to-resize with height persistence
- Fix animation replay on drag release (has-dragged class)
- Preserve panel height across LiveView re-renders
- Default to Page tab on editable pages, Theme otherwise
- Show unsaved changes indicator on FAB when panel collapsed
- Fix handle_event grouping warning in admin theme
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- extract dominant colors from header images during optimization
- calculate WCAG contrast ratios against theme text color
- show warning in theme editor when text may be hard to read
- prevent hiding shop name when no logo is uploaded
- auto-enable shop name when logo is deleted
- fix image cache invalidation on delete
- add missing .hidden utility class
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create dedicated /admin/account page for user account management
- Move email, password, and 2FA settings from /admin/settings
- Add Account link to top of admin sidebar navigation
- Add TOTP-based two-factor authentication with NimbleTOTP
- Add TOTP verification LiveView for login flow
- Add AccountController for TOTP session management
- Remove Advanced section from settings (duplicated in dev tools)
- Remove user email from sidebar footer (replaced by Account link)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Hammer library for rate limiting with ETS backend
- Rate limit login (5/min), magic link (3/min), newsletter (10/min), API (60/min)
- Add themed 429 error page using bare shop styling
- Enable HSTS in production with rewrite_on for Fly proxy
- Add security hardening plan to docs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rewrote planning doc as a reference guide with:
- decision tree for choosing feedback type
- implementation patterns with code examples
- accessibility requirements
- common mistakes to avoid
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- use role="status" for info messages, role="alert" for errors
- add aria-live attribute (polite for info, assertive for errors)
- move phx-click to close button for better keyboard navigation
- add close buttons to shop flash messages
- add aria-hidden to decorative icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace put_flash with inline feedback for form saves:
- Media library: metadata save shows "Saved" checkmark
- Product show: storefront controls save shows "Saved" checkmark
- Newsletter campaign form: draft save shows "Saved" checkmark
Page-level outcomes (uploads, deletes, async operations) remain as
flash/banner messages — these are the correct pattern for non-form
actions.
Completes Task 4 of notification overhaul.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Progressive enhancement: provider form now works without JavaScript.
Forms POST to ProvidersController (create/update), which handles
validation and redirects with flash messages.
With JS: LiveView phx-submit handles save, navigates with flash.
Without JS: Form POSTs to controller, redirects with flash.
Completes Task 3 of notification overhaul (admin forms migration).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace put_flash calls with inline feedback for form saves:
- Email settings: "Now send a test email" after saving
- Settings: from address and signing secret saves
- Page editor: save button shows "Saved" checkmark
Inline feedback appears next to save buttons and auto-clears after
3 seconds. Banners (put_flash) remain for page-level outcomes like
deletions, state changes, and async operations.
Task 3 of notification overhaul. Theme editor skipped as it auto-saves.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the editor sheet into two distinct elements:
- .editor-fab: floating action button, always a pill in the corner
- .editor-panel: sliding panel that animates in/out independently
This enables proper CSS keyframe animations (slide-up/down on mobile,
slide-in/out on desktop) with a closing class for exit transitions.
Simplified the JS hook to only handle close behaviour.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>