# 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, reviews
- **Reviews** — verified purchase reviews with photos, admin moderation, JSON-LD markup
- **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
- 1851+ tests, CI with credo + dialyzer

## Getting started

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

### Setup

```bash
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

```bash
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:

```bash
# 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:

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

For Fly.io deployment:
```bash
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](https://dashboard.stripe.com/register)
2. Navigate to Admin > Settings in your shop
3. Paste your secret key and click "Connect Stripe"

For local webhook testing:
```bash
stripe listen --forward-to localhost:4000/webhooks/stripe
```

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

## Documentation

- [PROGRESS.md](PROGRESS.md) — current status and next tasks
- [ROADMAP.md](ROADMAP.md) — future vision and planned features
- [CLAUDE.md](CLAUDE.md) — coding guidelines and conventions
- [docs/plans/](docs/plans/) — feature implementation plans

## License

AGPL-3.0
