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>
330 lines
20 KiB
Markdown
330 lines
20 KiB
Markdown
# SimpleShop Progress
|
|
|
|
> Single source of truth for project status and task tracking.
|
|
|
|
## Current Status
|
|
|
|
**Working:**
|
|
- Theme editor with 8 presets, instant switching, full customization
|
|
- Image optimization pipeline (AVIF/WebP/JPEG responsive variants)
|
|
- Shop pages (home, collections, products, cart, about, contact, error, delivery, privacy, terms)
|
|
- Mobile-first design with bottom navigation
|
|
- 100% PageSpeed score
|
|
- Variant selector with color swatches and size buttons
|
|
- Session-based cart with real variant data (add/remove/quantity, cross-tab sync)
|
|
- Cart drawer and cart page with hydrated product info
|
|
- Stripe Checkout with order persistence and webhook handling
|
|
- Admin credentials page with guided Stripe setup flow
|
|
- Encrypted settings for API keys and secrets
|
|
- Search modal with keyboard shortcut
|
|
- Transactional emails (order confirmation, shipping notification)
|
|
- Demo content polished and ready for production
|
|
|
|
**Tier 1 MVP complete.** CI pipeline done. Hosting & deployment done (including observability). PageSpeed CI done (99-100 mobile, 97+ desktop). Next up: usability fixes from user testing, then remaining Tier 2 items (Litestream backup, e2e tests).
|
|
|
|
## Usability Issues (from user testing, Feb 2025)
|
|
|
|
Issues found during hands-on testing of the deployed prod site on mobile and desktop.
|
|
|
|
**Approach:** One issue at a time, test and verify each fix before moving on.
|
|
|
|
**Principles:**
|
|
- **Semantic, minimal HTML** — achieve everything with the simplest markup possible
|
|
- **Progressive enhancement** — HTML and CSS first, then LiveView, JS only as a last resort
|
|
- **Fully accessible** — WCAG 2.1 AA compliant, proper focus management, ARIA where needed, keyboard navigable
|
|
- **Mobile-first responsive** — design for small screens first, enhance for larger viewports
|
|
- **Appropriate interactions** — touch-friendly on mobile (swipe, tap), hover/keyboard for desktop users
|
|
|
|
### Mobile / touch
|
|
- [x] Product photos require double-tap on mobile (hover state blocks first tap)
|
|
- [x] Product photos should be swipeable on mobile (hover-to-reveal is desktop-only)
|
|
- [x] Product card second image: swipe to reveal on mobile (currently hover-only)
|
|
|
|
### Product detail page
|
|
- [x] PDP image gallery: scroll-snap carousel with dots (mobile), thumbnails + arrows + lightbox (desktop)
|
|
- [x] Product category breadcrumbs look bad — review styling/layout
|
|
- [x] Quantity selector on product page doesn't work
|
|
- [x] Trust badges: two different tick icons, should use sentence case not title case
|
|
- [ ] Real product variants need testing and refinement with live data
|
|
|
|
### Cart
|
|
- [x] Should be able to change quantity in the cart drawer (currently only on cart page?)
|
|
- [x] Cart drawer button → "view basket" feels redundant — streamline the flow
|
|
- [ ] Shipping costs: add Stripe shipping options or query Printify for dynamic rates
|
|
|
|
### Navigation & links
|
|
- [ ] Search doesn't work (modal opens but no results/functionality)
|
|
- [ ] "Shop the collection" button/link does nothing
|
|
- [ ] Footer "New arrivals" and "Best sellers" links don't go anywhere
|
|
- [ ] Should be able to tap a category badge on product cards to go to that category
|
|
- [ ] Footer social icons should match the "Find me on" icons from the contact page
|
|
|
|
### Collections / all products
|
|
- [ ] Categories on all-products page are too spaced out
|
|
|
|
### Content pages
|
|
- [ ] Hero title spacing differs between content pages (about, delivery, etc.) — contact is fine
|
|
|
|
### Sale / filtering
|
|
- [ ] Should there be a "Sale" section or filter for discounted products?
|
|
|
|
### Errors
|
|
- [ ] 404 page is broken
|
|
|
|
## Roadmap
|
|
|
|
### Tier 1 — MVP (can take real orders and fulfil them)
|
|
|
|
1. ~~**Order management admin**~~ — ✅ Complete (02cdc81). Admin UI at `/admin/orders` with status filter tabs, streamed order table, and detail view showing items, totals, and shipping address.
|
|
2. ~~**Orders & fulfilment**~~ — ✅ Complete. Submit paid orders to Printify, track fulfilment status (submitted → processing → shipped → delivered), webhook-driven status updates with polling fallback, admin UI with submit/refresh actions.
|
|
3. ~~**Transactional emails**~~ — ✅ Complete. Plain text order confirmation (on payment via Stripe webhook) and shipping notification (on dispatch via Printify webhook + polling fallback). OrderNotifier module, 10 tests.
|
|
4. ~~**Default content pages**~~ — ✅ Complete (5a43cfc). Generic `ShopLive.Content` LiveView handles about + 3 policy pages (delivery, privacy, terms) via `live_action`. Rich text with list blocks, footer links updated, theme editor preview. 10 tests (575 total).
|
|
|
|
### Tier 2 — Production readiness (can deploy and run reliably)
|
|
|
|
5. ~~**Hosting & deployment**~~ — ✅ Complete. Alpine Docker image (131 MB), Fly.io config, release overlays, health check endpoint, hardcoded path fixes for releases. Observability: LiveDashboard in prod behind admin auth, ErrorTracker for exception capture, JSON structured logging, Oban/LiveView telemetry metrics, os_mon for CPU/disk/memory.
|
|
6. **Litestream / SQLite replication** — Litestream for continuous SQLite backup to S3-compatible storage. Point-in-time recovery. Simple sidecar process, no code changes needed, works with vanilla SQLite. For the hosted platform (Tier 5), evaluate [Turso](https://turso.tech/) (libSQL fork of SQLite) with embedded read replicas via [ecto_libsql](https://github.com/ocean/ecto_libsql) adapter — gives multi-node reads without a separate replication daemon, but adds a dependency on the libSQL fork.
|
|
7. ~~**CI pipeline**~~ — ✅ Complete. `mix ci` alias: compile --warning-as-errors, deps.unlock --unused, format --check-formatted, credo, dialyzer, test. Credo configured with sensible defaults. Dialyzer with ignore file for false positives (Stripe types, Mix tasks, ExUnit internals). 612 tests, 0 failures.
|
|
8. ~~**PageSpeed in CI**~~ — ✅ Complete. `mix lighthouse` task runs Google Lighthouse against the shop with configurable thresholds. Builds production assets (minified + digested + gzipped), waits for image variant cache, checks all 4 categories. Mobile: 99-100, Desktop: 97-100 across all pages. Unconditional gzip on Plug.Static.
|
|
9. **End-to-end & accessibility tests** — Wallaby browser tests for critical flows (browse → add to cart → checkout → order confirmation) with A11yAudit assertions baked into each test. Covers the happy path, key error cases, and WCAG 2.1 AA compliance in one pass. Wallaby drives a headless Chrome, A11yAudit wraps axe-core for automated a11y checks within ExUnit. Focus management, ARIA labels, keyboard navigation, colour contrast — all verified as part of the e2e suite rather than a separate audit.
|
|
|
|
### Tier 3 — Compliance & quality
|
|
|
|
10. **Privacy-respecting analytics** — Self-hosted, cookie-free analytics. Plausible, Umami, or a lightweight custom solution. No Google Analytics, no third-party tracking. GDPR-friendly by design.
|
|
11. **AGPL licensing & code hosting** — Currently AGPL-3.0. Decide on GitHub vs Codeberg vs self-hosted Forgejo. Set up proper LICENSE file, contribution guidelines, and release process.
|
|
12. **Security (Paraxial.io)** — Runtime application security monitoring for Elixir. Bot detection, rate limiting, vulnerability scanning. Evaluate whether it fits the self-hosted model.
|
|
|
|
### Tier 4 — Growth & content
|
|
|
|
13. **Page editor** — Database-driven pages with drag-and-drop sections. Extend the theme system to custom pages beyond the defaults. Replaces the static content pages from Tier 1 with editable versions.
|
|
14. **Newsletter & email marketing** — Email list collection (signup forms). Campaign sending for product launches, sales. Can be simple initially (collect emails, send via Swoosh) or integrate with a service.
|
|
15. **Product page improvements** — Pre-checkout variant validation (verify Printify availability). Cost change monitoring/alerts. Better image gallery (zoom, multiple angles).
|
|
|
|
### Tier 5 — Platform vision
|
|
|
|
16. **Hosted platform** — Marketing/brochure site for SimpleShop as a service. Subscribe/sign-up flow. Multi-tenancy with per-tenant databases. Stripe Connect for customer shops (each merchant connects their own Stripe account via OAuth).
|
|
17. **Migration & export** — Let shop owners export their data (products, orders, customers, theme settings). Import from other platforms (Shopify, WooCommerce). Portable data as a selling point for the self-hosted story.
|
|
18. **Internationalisation (i18n)** — Multi-language support via Gettext (already in Phoenix). Currency formatting. RTL layout support. Per-shop locale configuration. **Note:** `ex_money`/`ex_cldr` are currently used *only* for `Cart.format_price/1` (a single GBP formatting call) but add ~13 MB to the release (ex_cldr 9.5 MB, digital_token 3.7 MB, ex_cldr_numbers, ex_cldr_currencies). Consider replacing with a simple `format_price/2` function that handles GBP/EUR/USD directly — all three use 2 decimal places and are trivial to format. Re-add `ex_money` later if proper locale-aware number formatting is needed (e.g., German `12.345,67 €`).
|
|
|
|
---
|
|
|
|
## Feature Areas
|
|
|
|
### Theme System
|
|
**Status:** Complete
|
|
|
|
- 8 theme presets (Gallery, Studio, Boutique, etc.)
|
|
- Three-layer CSS architecture (primitives, attributes, semantic)
|
|
- Instant theme switching via CSS custom property injection
|
|
- Logo/header image uploads with SVG recoloring
|
|
- Self-hosted fonts (10 typefaces, GDPR compliant)
|
|
- ETS-cached CSS generation
|
|
|
|
### Image Optimization
|
|
**Status:** Complete
|
|
|
|
- Oban background job processing
|
|
- Responsive `<picture>` element (AVIF/WebP/JPEG)
|
|
- Only generates sizes <= source dimensions
|
|
- Disk cache for variants (regenerable from DB)
|
|
- `mix optimize_images` task for mockups
|
|
- On-demand JPEG fallback generation
|
|
- Product image download pipeline (downloads Printify CDN images, processes through Media pipeline)
|
|
- ImageDownloadWorker downloads and links images to ProductImage
|
|
- PreviewData uses local images for responsive `<picture>` elements
|
|
- Startup recovery re-enqueues pending downloads
|
|
- `mix simpleshop.download_images` backfill task
|
|
|
|
See: [docs/plans/image-optimization.md](docs/plans/image-optimization.md) for implementation details
|
|
|
|
### Products & Provider Integration
|
|
**Status:** Complete
|
|
|
|
- [x] Products context with schemas (c5c06d9)
|
|
- [x] Provider abstraction layer
|
|
- [x] Printify client integration
|
|
- [x] Product/variant/image schemas
|
|
- [x] Admin Provider Setup UI (`/admin/providers`) - connect, test, sync
|
|
- [x] ProductSyncWorker with pagination, parallel processing, error recovery
|
|
- [x] Slug-based fallback matching for changed provider IDs
|
|
- [x] Printify webhook endpoint with HMAC verification (a9c15ea)
|
|
- Note: Printify only supports `product:deleted` and `product:publish:*` events (no `product:updated`)
|
|
- [x] Product image download pipeline (1b49b47)
|
|
- Downloads Printify CDN images via ImageDownloadWorker
|
|
- Processes through Media pipeline (WebP conversion, AVIF/WebP variants)
|
|
- Startup recovery and `mix simpleshop.download_images` backfill
|
|
- [x] Variant selector component (880e7a2)
|
|
- Color swatches with hex colors, size buttons
|
|
- Fixed Printify options parsing (Color/Size swap bug)
|
|
- Filters to only published variants (not full catalog)
|
|
- Price updates on variant change
|
|
- Startup recovery for stale sync status
|
|
|
|
#### Future Enhancements (post-MVP)
|
|
- [ ] Pre-checkout variant validation (verify availability before order)
|
|
- [ ] Cost change monitoring/alerts (warn if Printify cost increased)
|
|
- [ ] OAuth platform integration (appear in Printify's "Publish to" UI)
|
|
|
|
#### Technical Debt
|
|
- [x] Mox provider mocking for fulfilment tests (Provider.for_type configurable via app env)
|
|
|
|
See: [docs/plans/products-context.md](docs/plans/products-context.md) for implementation details
|
|
See: [docs/plans/printify-integration-research.md](docs/plans/printify-integration-research.md) for API research & risk analysis
|
|
|
|
### Cart & Checkout
|
|
**Status:** Complete
|
|
|
|
- [x] Cart drawer component with slide-over panel (1bc08bf)
|
|
- [x] Cart page with item list and order summary (1bc08bf)
|
|
- [x] Shared CartHook for cross-page cart events (1bc08bf)
|
|
- [x] CartPersist JS hook for localStorage backup
|
|
- [x] Add-to-cart with flash status feedback
|
|
- [x] Cart item links to product pages
|
|
- [x] Session-based cart with real variants (1bc08bf)
|
|
- Cart stores {variant_id, qty} tuples in session
|
|
- Hydrates with real product data via Products context
|
|
- Cross-tab sync via PubSub, session persistence via CartController API
|
|
- [x] Stripe Checkout integration (ff1bc48, stripity_stripe ~> 3.2)
|
|
- Stripe-hosted Checkout with redirect flow
|
|
- Webhook handler for checkout.session.completed/expired
|
|
- Signature verification via CacheRawBody + construct_event
|
|
- Shipping address collection during checkout
|
|
- [x] Order/OrderItem schemas and context (ff1bc48)
|
|
- Order number format: SS-YYMMDD-XXXX
|
|
- Payment status tracking (pending → paid/failed)
|
|
- Price snapshots in OrderItem (protects against changes)
|
|
- Idempotent webhook processing
|
|
- [x] Checkout success page with real-time PubSub updates
|
|
- [x] Cart clearing after successful payment
|
|
|
|
See: [ROADMAP.md](ROADMAP.md) for design notes
|
|
|
|
### Admin Settings & Stripe Setup
|
|
**Status:** Complete
|
|
|
|
- [x] Encrypted settings infrastructure (eede9bb)
|
|
- `encrypted_value` column on settings table
|
|
- `put_secret/2`, `get_secret/2`, `has_secret?/1`, `secret_hint/1`
|
|
- AES-GCM encryption via `SECRET_KEY_BASE`
|
|
- Secrets loaded into Application env on startup via `Secrets.load_all/0`
|
|
- [x] Guided Stripe setup flow (eede9bb)
|
|
- `Stripe.Setup` module: connect, disconnect, verify, auto-create webhook
|
|
- Three-state admin UI: not configured, connected (production), connected (dev/localhost)
|
|
- Auto-creates Stripe webhook endpoint on production hosts
|
|
- Dev mode shows Stripe CLI instructions for localhost
|
|
- Manual signing secret input for dev/advanced use
|
|
- API key verification via `Stripe.Balance.retrieve/2`
|
|
- [x] Admin credentials page at `/admin/settings` (eede9bb)
|
|
- Single Secret key input with "Connect Stripe" button
|
|
- Masked key hints (e.g. `sk_test_•••789`)
|
|
- Disconnect button clears keys from DB and Application env
|
|
- CSSCache test startup crash fixed (handle_continue pattern)
|
|
|
|
### Orders & Fulfilment
|
|
**Status:** Complete
|
|
|
|
- [x] Orders context with schemas (ff1bc48)
|
|
- [x] Stripe Checkout integration with webhook handling
|
|
- [x] Order management admin UI (02cdc81, Roadmap #1)
|
|
- Order list with status filter tabs (all/paid/pending/failed/refunded) and counts
|
|
- Streamed table with row click navigation to detail
|
|
- Order detail with info card, shipping address, line items table with totals
|
|
- Nav link in admin bar, 15 tests
|
|
- [x] Printify order submission and fulfilment tracking (Roadmap #2)
|
|
- 9 fulfilment fields on orders (status, provider_order_id, tracking, timestamps)
|
|
- `submit_to_provider/1` with idempotent guard, error handling, address mapping
|
|
- `refresh_fulfilment_status/1` polls provider for status updates
|
|
- OrderSubmissionWorker (Oban, :checkout queue, max_attempts: 3)
|
|
- FulfilmentStatusWorker (Oban Cron, every 30 mins, :sync queue)
|
|
- Printify order webhook handlers (sent-to-production, shipment:created, shipment:delivered)
|
|
- Stripe webhook auto-enqueues submission after payment confirmed
|
|
- Admin UI: fulfilment badge column, fulfilment card with tracking, submit/refresh buttons
|
|
- Mox provider mocking for test isolation, 33 new tests (555 total)
|
|
- [x] Transactional emails (Roadmap #3)
|
|
- OrderNotifier module with plain text emails via Swoosh
|
|
- Order confirmation sent from Stripe webhook after payment + address/email updates
|
|
- Shipping notification sent from Printify shipment webhook + polling fallback
|
|
- Guards for missing customer_email, graceful tracking info handling
|
|
- 10 tests (565 total)
|
|
|
|
See: [docs/plans/products-context.md](docs/plans/products-context.md) for schema design
|
|
|
|
### DRY Refactor
|
|
**Status:** Complete
|
|
|
|
All 8 items from the plan done. Key wins: ThemeHook eliminated mount duplication, shop_layout saved ~195 lines, shop_components split into 5 focused modules (largest file dropped from 4,487 to ~1,600 lines), Settings repo lookups consolidated via `fetch_setting/1`, secrets loading made scalable via registry pattern.
|
|
|
|
See: [docs/plans/dry-refactor.md](docs/plans/dry-refactor.md) for full analysis and plan
|
|
|
|
### Shop Page Integration Tests
|
|
**Status:** Complete
|
|
|
|
All shop pages now have LiveView integration tests (612 total):
|
|
|
|
- **Product detail page** (15 tests) — rendering, breadcrumbs, variant selection, price updates, add-to-cart, related products, fallback for unknown IDs
|
|
- **Cart page** (10 tests) — empty state, item display with DB fixtures, order summary, increment/decrement, remove, checkout button
|
|
- **Home page** (12 tests) — hero section, category nav, featured products, image+text section, navigation links
|
|
- **Collection page** (16 tests, pre-existing) — category filtering, sorting, URL params
|
|
- **Content pages** (10 tests, pre-existing) — about, delivery, privacy, terms
|
|
|
|
### CI Pipeline
|
|
**Status:** Complete
|
|
|
|
- `mix ci` alias: compile --warning-as-errors → deps.unlock --unused → format --check-formatted → credo → dialyzer → test
|
|
- `mix precommit` alias: compile --warning-as-errors → deps.unlock --unused → format → test
|
|
- Credo with tuned config (disabled AliasUsage, ModuleDoc, PredicateFunctionNames; relaxed line length, nesting, complexity)
|
|
- Dialyzer with ignore file for known false positives (Stripe library types, Mix.Task dev-only modules, ExUnit internals)
|
|
- All credo issues resolved (map_join, filter consolidation, nesting extraction)
|
|
- 612 tests, 0 failures
|
|
|
|
### Hosting & Deployment
|
|
**Status:** Complete
|
|
|
|
- Alpine Docker image (131 MB), Fly.io config, release overlays
|
|
- Health check endpoint at `/health`
|
|
- Hardcoded path fixes for releases (`Application.app_dir/2`)
|
|
- LiveDashboard at `/admin/dashboard` behind admin auth (all envs)
|
|
- ErrorTracker at `/admin/errors` — auto-captures Phoenix/LiveView/Oban exceptions, stored in SQLite, pruner for resolved errors
|
|
- JSON structured logging in prod via `logger_json` (machine-parseable)
|
|
- Oban job duration/count and LiveView mount/event telemetry metrics
|
|
- os_mon for CPU, disk, and OS memory in LiveDashboard
|
|
|
|
### Page Editor
|
|
**Status:** Future (Tier 4)
|
|
|
|
Database-driven pages with drag-and-drop sections. Initially, default content pages (terms, privacy, delivery) will be static templates (Tier 1), later made editable via the page editor.
|
|
|
|
See: [docs/plans/page-builder.md](docs/plans/page-builder.md) for design
|
|
|
|
---
|
|
|
|
## Completed Work Reference
|
|
|
|
| Feature | Commit | Notes |
|
|
|---------|--------|-------|
|
|
| PageSpeed CI | 516d0d0 | `mix lighthouse` task, prod asset build, gzip, 99-100 mobile scores |
|
|
| Observability | eaa4bbb | LiveDashboard in prod, ErrorTracker, JSON logging, Oban/LV metrics, os_mon |
|
|
| Hosting & deployment | — | Alpine Docker, Fly.io, health check, release path fixes |
|
|
| PDP image gallery | 8445e9e | Scroll-snap carousel, dots, thumbnails, arrows, lightbox, 9 tests |
|
|
| CI pipeline | — | mix ci/precommit aliases, credo, dialyzer, 621 tests |
|
|
| Default content pages | 5a43cfc | Generic Content LiveView, delivery/privacy/terms pages, 10 tests |
|
|
| Transactional emails | — | Plain text order confirmation + shipping notification, 10 tests |
|
|
| Printify order submission & fulfilment | — | Submit, track, webhooks, polling, admin UI, 33 tests |
|
|
| Order management admin | 02cdc81 | List/detail views, status filters, 15 tests |
|
|
| Encrypted settings & Stripe setup | eede9bb | Guided setup flow, encrypted secrets, admin credentials page |
|
|
| Stripe checkout & orders | ff1bc48 | Stripe Checkout, webhooks, order persistence |
|
|
| Demo content & link fixes | cff2170 | Broken links, placeholder text, responsive about image |
|
|
| Cart UI infrastructure | 1bc08bf | Cart drawer, cart page, CartHook, CartPersist |
|
|
| Variant selector | 880e7a2 | Color swatches, size buttons, price updates |
|
|
| Product image download | 1b49b47 | PageSpeed 100% with local images |
|
|
| Wire shop to real data | c818d03 | PreviewData uses Products context |
|
|
| Printify webhooks | a9c15ea | Deletion + publish events |
|
|
| Products context Phase 1 | c5c06d9 | Schemas, provider abstraction |
|
|
| Admin provider setup UI | 5b736b9 | Connect, test, sync with pagination |
|
|
| Oban Lifeline plugin | c1e1988 | Rescue orphaned jobs |
|
|
| Image optimization | Multiple | Full pipeline complete |
|
|
| Self-hosted fonts | - | 10 typefaces, 728KB |
|
|
| Mobile bottom nav | - | Fixed tab bar |
|
|
| PageSpeed 100% | - | All optimizations |
|
|
| Theme presets (8) | - | Gallery, Studio, etc. |
|