182 lines
6.8 KiB
Markdown
182 lines
6.8 KiB
Markdown
# 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
|
|
|
|
```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
|