Commit Graph

194 Commits

Author SHA1 Message Date
jamey
08fcd60eb6 improve analytics chart with hourly today view and readable labels
- add visitors_by_hour query for hourly breakdown on "today" period
- replace SVG-only chart with HTML/CSS grid layout (bars + labels)
- Y-axis scale with nice rounded max, midpoint, and zero
- X-axis date labels (formatted as "Feb 18") spaced evenly
- adaptive bar gaps (1px for sparse data, 0 for 365-day dense view)
- labels use real HTML text so they're readable on mobile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 23:28:35 +00:00
jamey
65e646a7eb add analytics v2 plan, demo seed data, and improved funnel display
- analytics-v2 plan with prioritised improvements (comparison mode, filtering, CSV export, entry/exit pages)
- seed script generating ~35k realistic events over 12 months (weighted traffic, referrers, devices, e-commerce funnel)
- funnel chart now shows overall conversion rate from product views instead of step-to-step percentages
- summary line with overall conversion rate and revenue

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:30:24 +00:00
jamey
f91b47f0c3 include browser/os/screen_size in e-commerce analytics events
All checks were successful
deploy / deploy (push) Successful in 1m37s
Event call sites (product_view, add_to_cart, checkout_start, purchase)
were only passing visitor_hash and pathname, leaving browser, OS, screen
size and country nil. Add AnalyticsHook.attrs/1 helper to extract common
analytics fields from socket assigns, and use it in all LiveView event
call sites. Checkout controller reads the same fields from the session.

Also fix plug analytics test to clear stale events before assertions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 21:13:47 +00:00
jamey
e26a02a0fb fix setup flow stale state and Stripe URL issues
All checks were successful
deploy / deploy (push) Successful in 1m9s
Onboarding: re-fetch setup_status() after provider/Stripe connect instead
of manually patching the local assigns, which could miss admin_created and
leave users stuck on the setup page with no way forward.

Dev config: respect PHX_HOST for endpoint URL so Stripe checkout redirects
to the correct host instead of always using localhost.

Stripe setup: detect private/LAN IPs (10.x, 172.16-31.x, 192.168.x) as
unreachable, not just localhost — prevents creating webhook endpoints that
Stripe can never reach.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:51:44 +00:00
jamey
2bd2e613c7 add privacy-first analytics with progressive event collection
All checks were successful
deploy / deploy (push) Successful in 3m20s
Three-layer pipeline: Plug for all HTTP requests (no JS needed), LiveView
hook for SPA navigations, JS hook for screen width. ETS-backed buffer
batches writes to SQLite every 10s. Daily-rotating salt for visitor hashing.
Includes admin dashboard with date ranges, visitor trends, top pages,
sources, devices, and e-commerce conversion funnel. Oban cron for 12-month
data retention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:50:55 +00:00
jamey
b0aed4c1d6 add Printify client test coverage with Req.Test stubs
All checks were successful
deploy / deploy (push) Successful in 1m15s
Same pattern as the Printful work: wire up base_options/0 so tests can
inject a Req.Test plug, fix unreachable 204 clause in delete, add
HTTP-level client tests and provider integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:35:24 +00:00
jamey
a45e85ef4c add Printful client test coverage with Req.Test stubs
All checks were successful
deploy / deploy (push) Successful in 1m10s
Wire up Req.Test plug for the Printful HTTP client so tests can stub
responses. Adds HTTP-level tests for the client, provider integration
tests, and mockup enricher tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:20:49 +00:00
jamey
75b9ff3156 use Oban for startup variant processing, add vips-heif
VariantCache now enqueues missing variants via OptimizeWorker instead
of processing directly with Task.async_stream. Simpler and uses the
existing job queue. Adds vips-heif to Docker runtime for HEIF support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:24:34 +00:00
jamey
162bf4ca53 add SQLite concurrency tests and bench task
BenchRepo for isolated concurrency testing against temp DB files.
Correctness tests prove WAL concurrent reads, IMMEDIATE transaction
mode vs DEFERRED upgrade failures, and PRAGMA application. Benchmark
tests (tagged :benchmark, excluded by default) measure throughput.

mix bench.sqlite runs HTTP load scenarios against the full Phoenix
stack with --prod, --scale, --pool-size, and --busy-timeout options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:23:36 +00:00
jamey
04cdb62a8d add custom Swoosh adapter for MailerSend
All checks were successful
deploy / deploy (push) Successful in 1m23s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 23:48:06 +00:00
jamey
a0985bd07e fix Stripe webhook crash on struct access
All checks were successful
deploy / deploy (push) Successful in 1m0s
Stripe.Checkout.Session is a struct that doesn't implement Access,
so get_in with atom keys fails. Use direct struct field access instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 23:36:21 +00:00
jamey
762a2ee100 add Stripe connection step to launch checklist
All checks were successful
deploy / deploy (push) Successful in 1m10s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 23:26:13 +00:00
jamey
0ddafbd84f fix recovery login crash for users with password set
All checks were successful
deploy / deploy (push) Successful in 1m8s
login_user_by_magic_link raises for unconfirmed users with a password,
which is exactly what recovery creates. Use get_user_by_magic_link_token
directly and log in without the magic link guard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 22:52:46 +00:00
jamey
3dca9ad9d0 gate magic link login on verified email delivery
All checks were successful
deploy / deploy (push) Successful in 1m2s
The login page now only shows the magic link form when a test email has
been sent successfully, not just when an adapter is configured. Saving
email settings or disconnecting clears the flag so the admin must
re-verify after config changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 22:25:27 +00:00
jamey
b0607621f3 add admin account recovery via setup secret
All checks were successful
deploy / deploy (push) Successful in 1m33s
When email isn't configured, the login page now hides the magic link
form and shows a recovery link. The /recover page logs the setup secret
to server logs and lets the admin reset their password with it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 21:40:53 +00:00
jamey
194fec8240 namespace email settings keys per adapter
All checks were successful
deploy / deploy (push) Successful in 57s
Settings keys like api_key were shared across providers, so switching
from e.g. Postmark to SendGrid showed the old API key. Now each
adapter gets its own namespaced key (email_postmark_api_key, etc.)
so credentials persist independently and switching back pre-fills
previously saved values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:57:23 +00:00
jamey
366a1e6a48 add admin email settings page with provider selection
All checks were successful
deploy / deploy (push) Successful in 56s
Card radio component for picking email providers (SMTP, SendGrid, Mailjet, etc.)
with instant client-side switching via JS hook. Adapter configs are pre-rendered
and toggled without a server round-trip. Secrets are preserved when re-saving
with blank password fields. Includes from address field, test email sending,
and disconnect flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:29:34 +00:00
jamey
a2e46664c6 soften email warning banner copy, drop SMTP_HOST reference
All checks were successful
deploy / deploy (push) Successful in 59s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 10:44:46 +00:00
jamey
9d9bd09059 auto-confirm admin during setup, skip email verification
Some checks failed
deploy / deploy (push) Has been cancelled
Setup wizard no longer requires email delivery. Admin account is
auto-confirmed and auto-logged-in via token redirect. Adds setup
secret gate for prod (logged on boot), SMTP env var config in
runtime.exs, email_configured? helper, and admin warning banner
when email isn't set up. Includes plan files for this task and
the follow-up email settings UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 10:24:26 +00:00
jamey
8e818da651 only enable gzip static file serving in prod
All checks were successful
deploy / deploy (push) Successful in 52s
Avoids stale .gz files from mix assets.deploy shadowing freshly-built
dev assets. This was causing the admin to render with old DaisyUI dark
theme CSS even after the unified theme migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 08:56:51 +00:00
jamey
8f9ed5657f theme auth/setup pages and unify resets
Phase 7: add LoadTheme to base :browser pipeline so auth and setup
pages get theme settings. Update root.html.heex with .themed wrapper,
font preloads, layer declaration, and generated CSS injection.
Remove old data-theme JS toggle script.

Phase 8: upgrade admin/reset.css to a proper @layer reset matching
the shop reset structure. Remove dead theme toggle CSS rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:17:23 +00:00
jamey
65ea11c3a2 replace --color-* with --t-* tokens, delete bridge and .preview-frame
Phase 4: admin components and utilities now reference --t-* theme
tokens directly. Status colour tokens added to theme-semantic.css.
Bridge file (admin/themes.css) deleted.

Phase 5: removed duplicated .preview-frame CSS block (~160 lines).
Admin components and icons wrapped in @layer admin. Layer order
updated in admin_root to include admin layer.

Phase 6: added prefers-reduced-motion support (zeroes all durations
and disables animations). Migrated physical properties to logical
equivalents (text-align start/end, margin-inline, padding-inline,
inset-inline-end) across shop and admin CSS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:13:33 +00:00
jamey
d68768ad84 add theme bridge and .themed wrapper to admin
Phase 3: Rewrite admin/themes.css as a bridge mapping DaisyUI --color-*
variables to --t-* theme tokens. Admin components still reference
--color-base-100, --color-primary etc but these now resolve through the
bridge to the merchant's theme colours. Status colours (error, success,
warning, info) stay hardcoded.

Add .themed wrapper with data-mood to admin_root.html.heex. Remove the
old data-theme JS toggle script — dark mode now comes from the theme
system mood setting. Admin inherits theme colours, typography, and shape
from the merchant's chosen theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:56:43 +00:00
jamey
285aafa0b5 migrate accent colours from HSL to oklch, inject theme into admin
Phase 1: Replace hex_to_hsl with hex_to_oklch in CSSGenerator, output
--t-accent-l/c/h instead of --t-accent-h/s/l. All 46 HSL accent
references across theme-semantic.css, theme-layer2-attributes.css, and
shop/components.css replaced with oklch/color-mix equivalents. Dead
style*= attribute selectors for button variants replaced with proper
class-based selectors. Added color-scheme: light/dark to mood output.

Phase 2: Add LoadTheme plug to admin pipeline, extend AdminLayoutHook
with theme_settings and generated_css assigns, add font preloads and
generated CSS injection to admin_root.html.heex. No visual changes to
admin yet — .themed wrapper added in next phase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:53:42 +00:00
jamey
b06029079d improve error pages: minimal version when site not live
All checks were successful
deploy / deploy (push) Successful in 1m19s
Show a lightweight error page using admin.css when the shop isn't
live yet, avoiding broken theme dependencies. Also tidied up copy
to sentence case and shorter descriptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:19:21 +00:00
jamey
2563338a6a add logo to coming soon page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:19:15 +00:00
jamey
9efc0644ba fix 404/500 error pages loading wrong stylesheet
All checks were successful
deploy / deploy (push) Successful in 1m10s
error pages render shop-themed layout but were loading admin.css,
which has no shop component styles. switch to shop.css.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:02:07 +00:00
jamey
b05b696681 rework setup wizard into phased flow
All checks were successful
deploy / deploy (push) Successful in 3m30s
phase 1 (no admin): show only the email form
phase 2 (admin created, not logged in): "check your inbox" gate with
  "wrong email? start over" link that deletes the unconfirmed user
phase 3 (logged in via magic link): show provider + stripe steps

removes the confusing redirect to /users/log-in after account creation.
users now stay on /setup throughout the entire setup process.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:07:07 +00:00
jamey
a78a1db847 fix admin font loading and theme CSS cache miss bug
add system font stack to admin reset CSS so setup/admin pages render
sans-serif on all devices instead of falling through to browser default.
pass path_resolver to CSSGenerator.generate on cache miss paths so
font URLs resolve to digested paths in production.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:39:41 +00:00
jamey
f6a38bb48f fix muted text invisible in dark mode on setup and dashboard pages
Replace non-existent --color-base-content-60 variable (with hard-coded
black fallback) with color-mix(in oklch, var(--color-base-content) 60%,
transparent) which adapts to the current theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 01:07:25 +00:00
jamey
c2caeed64d add setup onboarding page, dashboard launch checklist, provider registry
- new /setup page with three-section onboarding (account, provider, payments)
- dashboard launch checklist with progress bar, go-live, dismiss
- provider registry on Provider module (single source of truth for metadata)
- payments registry for Stripe
- setup context made provider-agnostic (provider_connected, theme_customised, etc.)
- admin provider pages now fully registry-driven (no hardcoded provider names)
- auth flow: fresh installs redirect to /setup, signed_in_path respects setup state
- removed old /admin/setup wizard
- 840 tests, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 00:34:06 +00:00
jamey
2007279fc6 replace dead Tailwind classes in shop pages with custom CSS
Coming soon page was unstyled after Tailwind removal — replaced
utility classes with proper component CSS. Also removed dead h-full
classes from shop_root layout, adding height: 100% to the shop reset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:27:52 +00:00
jamey
5834be870f add providers, LiveDashboard, errors links to admin sidebar
Providers was a hidden page with no nav link. Also adds
LiveDashboard and ErrorTracker to the sidebar footer, and
styles the provider dropdown menu items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 08:30:02 +00:00
jamey
559798206f extract setup wizard to dedicated /admin/setup page
Move the setup stepper out of the dashboard into its own LiveView.
Dashboard now redirects to setup when site isn't live, and shows
stats-only view once live. Also cleans up button component variant
handling, fixes alert CSS, and removes stale demo.html.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 23:55:42 +00:00
jamey
9528700862 rename project from SimpleshopTheme to Berrypod
All modules, configs, paths, and references updated.
836 tests pass, zero warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:23:15 +00:00
jamey
82583822f5 remove Tailwind + DaisyUI theme + heroicons plugin, admin fully custom CSS (Phase 7)
replace Tailwind CLI with esbuild for admin CSS bundling. admin now uses
hand-written utility classes (admin/utilities.css), static heroicon CSS
generated by mix generate_admin_icons, plain CSS colour themes extracted
from DaisyUI plugin config, and minimal resets. rename app.css to admin.css
for clarity alongside shop.css. delete vendor/daisyui-theme.js and
vendor/heroicons.js. no Tailwind dependency remains in the project.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:15:28 +00:00
jamey
af0b0c217f replace DaisyUI components with admin CSS, remove DaisyUI plugin (Phase 6)
Add admin/components.css with custom admin-* component classes replacing
all DaisyUI component usage across admin LiveViews, auth pages, layout,
and core_components. Delete daisyui.js vendor file (246KB). Theme plugin
stays for color variables until Phase 7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 23:05:01 +00:00
jamey
b25e04d1b2 load shop.css in admin layout for theme editor preview
The theme editor preview renders shop components inline. After removing
shop Tailwind (Phase 5c), those components use semantic CSS classes from
shop.css which wasn't loaded in the admin layout. Added a layer ordering
declaration to keep shop reset below Tailwind base in the cascade.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 20:07:52 +00:00
jamey
f5f6374f7b replace Tailwind in content + collection, remove shop Tailwind entirely (Phase 5c)
- Replace all Tailwind utilities in content.ex and collection.ex with
  semantic CSS classes (content body, contact form, cards, reviews, etc.)
- Delete app-shop.css (Tailwind shop entry point)
- Remove shop Tailwind config from config.exs, dev.exs, mix.exs
- Remove shop Tailwind stylesheet link from shop_root.html.heex
- Add collection filter bar, empty state, and select dropdown styles
- Fix filter pill sizing (use theme font vars instead of hardcoded rem)
- Fix active pill contrast (tinted accent background + dark accent text)
- Fix --t-text-on-accent fallback for pill legibility
- Add padding/font-size to .themed-select

Shop pages now use zero Tailwind. Admin Tailwind remains for Phase 6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 19:07:15 +00:00
jamey
04b6ee3f37 replace Tailwind utilities in product + cart components with CSS (Phase 5b)
Remove ~140 Tailwind utility classes from product.ex and cart.ex, replacing
with semantic CSS classes in components.css. Delete helper functions that
generated Tailwind class strings (card_classes, image_container_classes,
content_padding_class, title_classes, hero_cta_classes, grid_classes).
Use data-* attributes for variant styling, grid columns, and sticky
positioning. Update theme-layer2 selectors for renamed classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:32:48 +00:00
jamey
fc9c33ab0c replace Tailwind utilities in layout + page templates with CSS (Phase 5a)
Absorb ~100 Tailwind utility classes from layout.ex and all page
templates into semantic CSS rules in components.css. Uses theme font-size
vars (--t-text-small, --t-text-caption) instead of rem to respect the
theme's em-based scaling system.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:03:35 +00:00
jamey
84de1c37c5 extract content + template inline styles to CSS classes (Phase 4)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 08:01:32 +00:00
jamey
f337f51799 extract layout.ex and cart.ex inline styles to CSS classes (Phase 3)
Move ~104 inline style= attributes from layout.ex (55) and cart.ex (49)
into named CSS classes in components.css. Remove conflicting unlayered
nav link rule from theme-semantic.css that was previously masked by
inline styles. Only dynamic values (background-image URLs, logo height)
remain as inline styles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 01:19:56 +00:00
jamey
2af2d782d5 extract product.ex inline styles to CSS component classes (Phase 2)
Move ~80 inline style= attributes from product.ex into ~40 CSS classes
in @layer components. Only genuinely dynamic values (hex colours,
background-image URLs) remain as inline styles. Pre-declare CSS layer
order in shop_root.html.heex so reset < components in the cascade.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 00:13:03 +00:00
jamey
fcd1b1ce80 wire shop.css alongside Tailwind for CSS migration (Phase 1)
- esbuild profile for shop.css bundling (dev watcher + build aliases)
- shop.css loaded as second stylesheet in shop_root layout
- LiveView display:contents rule in reset layer
- updated Lighthouse + Screenshots tasks for new esbuild target

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:45:13 +00:00
jamey
5fa93f4e75 add CSS migration foundation and screenshot tooling (Phase 0)
- CSS file structure with @layer declaration (reset, layout, components, utilities, overrides)
- Layout primitives: .stack, .cluster, .row, .auto-grid, .container-page, .with-sidebar, .center
- mix screenshots task using Playwright for visual regression testing
- Golden baseline captured (10 pages x 4 breakpoints = 40 screenshots)
- No visual changes — new CSS not wired into any layout yet

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:37:29 +00:00
jamey
504c895157 cap gallery image width to max available variant
Gallery was hardcoding 1200px width, breaking for images with smaller
source dimensions where only 400/800 variants exist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:48:03 +00:00
jamey
3158a94f0b progressive enhancement for collection filter pills
Flex-wrap base (no JS needed, active pill always visible). JS hook
switches to horizontal scroll with scroll-into-view when pills exceed
2.5 rows on mobile. Desktop always wraps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:47:51 +00:00
jamey
bb358f890b consolidate image serving and clean up pipeline
Move all image URL logic into ProductImage.url/2 and thumbnail_url/1,
remove dead on-demand generation code from Optimizer, strip controller
routes down to SVG recolor only, fix mockup startup check to verify all
variant formats, and isolate test image cache directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:47:41 +00:00
jamey
81e94d0d65 add admin products list and detail pages
Read-mostly admin views for synced products: filterable/sortable list
with inline visibility toggle, and detail page with images grid,
variants table, storefront controls form, and provider edit links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 08:48:51 +00:00