Go to file
jamey 04ce28ca29
All checks were successful
deploy / deploy (push) Successful in 1m16s
fix page settings section and blocks not showing in editor
Two bugs fixed:

1. Page Settings section wasn't appearing for system pages because
   Defaults.for_slug didn't return all required fields (type,
   meta_description, published, etc). Also changed page_renderer
   to use bracket notation for safer field access.

2. Blocks weren't loading when navigating directly to ?edit=page
   because the PageEditorHook's handle_params ran before Shop.Page
   assigned @page. Added pending page mode mechanism: hook sets a
   flag when edit mode is requested but @page is nil, then Shop.Page
   calls maybe_enter_pending_page_mode after @page is assigned.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-29 20:30:36 +01:00
.gitea/workflows switch deploy workflow to local docker build 2026-02-20 18:58:14 +00:00
assets complete editor panel reorganisation polish 2026-03-29 18:50:07 +01:00
config add Site context with social links editor and site-wide settings 2026-03-28 10:09:33 +00:00
docs complete editor panel reorganisation polish 2026-03-29 18:50:07 +01:00
lib fix page settings section and blocks not showing in editor 2026-03-29 20:30:36 +01:00
priv add Site context with social links editor and site-wide settings 2026-03-28 10:09:33 +00:00
rel rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
test add nav editors to Site tab with live preview 2026-03-28 22:19:48 +00:00
.credo.exs add CI pipeline with credo and dialyzer 2026-02-08 15:19:42 +00:00
.dialyzer_ignore.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
.dockerignore fix production deployment: CSS, images and theme seeding 2026-02-08 23:42:56 +00:00
.envrc.example update docs and progress tracking 2026-03-13 13:34:36 +00:00
.formatter.exs mix phx.new simpleshop_theme --database sqlite3 --adapter bandit --binary-id 2025-12-30 12:26:26 +00:00
.gitignore add database backup and restore admin page 2026-03-13 13:33:29 +00:00
.mcp.json chore: add MCP config for Claude Code + Tidewave integration 2026-01-31 13:49:07 +00:00
AGENTS.md docs: consolidate project tracking into PROGRESS.md 2026-01-31 14:06:07 +00:00
CLAUDE.md add progressive enhancement guidelines to CLAUDE.md 2026-03-04 23:28:21 +00:00
Dockerfile add sqlcipher support to docker build 2026-03-13 13:34:28 +00:00
fly.toml disable auto-stop to prevent cold start latency 2026-03-02 09:35:03 +00:00
LICENSE add AGPL-3.0 license file 2026-03-02 01:02:27 +00:00
mise.toml feat: add cart page, cart drawer, and shared cart infrastructure 2026-02-06 19:39:37 +00:00
mix.exs separate account settings from shop settings 2026-03-08 18:42:29 +00:00
mix.lock separate account settings from shop settings 2026-03-08 18:42:29 +00:00
PROGRESS.md complete editor panel reorganisation polish 2026-03-29 18:50:07 +01:00
README.md update docs and progress tracking 2026-03-13 13:34:36 +00:00
ROADMAP.md reference SEO enhancements plan in progress and roadmap 2026-03-10 08:54:15 +00:00

Berrypod

A customisable e-commerce storefront for print-on-demand sellers, built with Phoenix LiveView. Professional shops without design expertise, privacy-respecting by default, fully self-hostable.

Features

Shop

Complete storefront with all the pages you need:

  • Home — hero banner, category navigation, featured products, newsletter
  • Products — grid layout with hover effects, sorting, filtering by collection
  • Product detail — image gallery with per-colour filtering, variant selector, related products
  • Cart — drawer + full page, quantity controls, shipping estimate, cross-tab sync
  • Checkout — Stripe-hosted checkout with shipping costs, order confirmation
  • Custom pages — CMS pages at any URL with 26 block types
  • Legal pages — auto-generated privacy, delivery, and terms from actual shop settings
  • Search — FTS5 full-text search with live modal, keyboard nav, ARIA
  • Contact — contact form with order status lookup

Admin

  • Theme editor — 8 presets, real-time preview, comprehensive customisation
  • Page builder — drag-free block editor with undo/redo, live editing on shop pages
  • Analytics — privacy-first, cookie-free, comparison mode, CSV export
  • Orders — status tracking, fulfilment timeline, provider submission
  • Media library — image management with alt text, usage tracking, orphan detection
  • Activity log — global event feed, "needs attention" tab, contextual retry
  • URL redirects — auto-redirect on slug change, 404 monitoring, dead link scanning
  • Email settings — 10 adapter options, test email, env var precedence
  • Print providers — Printify + Printful with sync, orders, shipping, webhooks

Technical highlights

  • Hand-written CSS with three-layer architecture (9.8 KB gzipped shop, 17.8 KB admin)
  • SQLite with BLOB storage, IMMEDIATE transactions, WAL, mmap
  • SQLCipher encryption at rest (AES-256, optional for dev, required for prod)
  • Image optimisation pipeline (AVIF/WebP/JPEG responsive variants via Oban)
  • ETS caching for CSS, pages, redirects, favicons
  • 99-100 PageSpeed mobile, no-JS support across all key flows
  • 1679+ tests, CI with credo + dialyzer

Getting started

Prerequisites

  • Elixir 1.19+
  • Erlang/OTP 28+
  • Node.js 20+ (for esbuild asset bundling)

Setup

git clone <repo-url>
cd berrypod
mix setup       # install deps, create DB, run migrations, build assets
mix phx.server  # start dev server at localhost:4000

Visit http://localhost:4000/setup to create your admin account and connect a print provider.

Running tests

mix test              # all tests
mix test path/to.exs  # specific file
mix precommit         # compile warnings + format + test (run before committing)

Project structure

lib/berrypod/                    # core business logic
├── accounts.ex                  # user accounts + auth
├── analytics.ex                 # privacy-first pageview tracking
├── activity_log.ex              # system event logging
├── cart.ex                      # session-based cart
├── media.ex                     # image uploads, optimisation, media library
├── newsletter.ex                # email list + campaigns
├── orders.ex                    # order lifecycle + fulfilment
├── pages.ex                     # page builder (blocks, cache, defaults)
├── products.ex                  # products, variants, categories
├── providers.ex                 # POD provider abstraction (Printify, Printful)
├── redirects.ex                 # URL redirects + dead link monitoring
├── search.ex                    # FTS5 full-text search
├── settings.ex                  # theme + shop settings
├── shipping.ex                  # shipping rates + country detection
├── theme/                       # CSS generation, presets, ETS cache
└── workers/                     # Oban background jobs

lib/berrypod_web/                # web layer
├── components/
│   ├── layouts/                 # app, admin, and shop layouts
│   ├── shop_components/         # shop UI (product cards, cart, gallery, etc.)
│   └── block_editor_components.ex
├── live/
│   ├── admin/                   # admin LiveViews (orders, pages, media, etc.)
│   ├── shop/                    # shop LiveViews (home, collection, product, etc.)
│   └── auth/                    # authentication
├── page_renderer.ex             # generic block-to-component dispatch
└── controllers/                 # Stripe webhooks, favicons, images, cart API

assets/css/
├── shop/                        # shop component styles
├── admin/                       # admin component styles
├── theme-layer1-primitives.css  # design tokens
├── theme-layer2-attributes.css  # theme-specific values
└── theme-layer3-semantic.css    # component styles

Database encryption

Berrypod uses SQLCipher to encrypt the entire SQLite database at rest. Two independent secrets provide defence in depth:

Secret Purpose
SECRET_KEY_BASE Phoenix sessions, Cloak field encryption
SECRET_KEY_DB SQLCipher whole-database encryption

Development

Encryption is optional for development. To test locally with encryption:

# Generate a key (hex-only recommended)
openssl rand -hex 32

# Set environment variable
export SECRET_KEY_DB="your-hex-key"

# Recreate database with encryption
mix ecto.reset
mix phx.server

Without SECRET_KEY_DB, the database is unencrypted.

Production

Both secrets are required. Generate them:

mix phx.gen.secret  # → SECRET_KEY_BASE
openssl rand -hex 32  # → SECRET_KEY_DB (or mix phx.gen.secret)

For Fly.io deployment:

fly secrets set SECRET_KEY_BASE="..." SECRET_KEY_DB="..."

Backup and restore

Admin > Backup provides:

  • Database stats (size, encryption status, table breakdown)
  • Download backup (encrypted with same key)
  • Restore from backup (validates key matches)

Key management:

  • Lost key = lost data. No recovery possible.
  • Store keys securely (password manager, secrets manager).
  • Backups are portable — copy file + set same key = working shop.

Stripe setup

  1. Create a Stripe account
  2. Navigate to Admin > Settings in your shop
  3. Paste your secret key and click "Connect Stripe"

For local webhook testing:

stripe listen --forward-to localhost:4000/webhooks/stripe

Test cards: 4242 4242 4242 4242 (success), 4000 0000 0000 0002 (declined).

Documentation

License

AGPL-3.0