# Berrypod: Project Overview > Generated April 2026. For current status, see [PROGRESS.md](../PROGRESS.md). ## Technology Stack | Layer | Technology | |-------|------------| | Framework | Phoenix 1.8, LiveView 1.1 | | Language | Elixir 1.19, OTP 28 | | Database | SQLite (via Ecto + ecto_sqlite3) | | HTTP Server | Bandit | | Background Jobs | Oban 2.19 | | Payments | Stripe | | Image Processing | Image (VIPS-based) | | Asset Build | esbuild | | Testing | ExUnit, Mox, LazyHTML | --- ## Project Structure ``` lib/ ├── berrypod/ # Core business contexts │ ├── accounts/ # User auth, TOTP │ ├── products/ # Products, variants, provider connections │ ├── orders/ # Orders, line items, abandoned carts │ ├── media/ # Image upload, optimization │ ├── pages/ # CMS pages, block editor │ ├── theme/ # CSS generation, presets │ ├── settings/ # Site configuration │ ├── analytics/ # Privacy-first tracking │ ├── providers/ # Printify/Printful abstraction │ ├── shipping/ # Rates, country detection │ ├── newsletter/ # Subscribers, campaigns │ ├── reviews/ # Product reviews │ ├── activity_log/ # Event logging │ └── redirects/ # URL redirects, 404 tracking └── berrypod_web/ # Web layer ├── live/admin/ # Admin LiveViews ├── live/shop/ # Shop LiveViews ├── components/ # UI components ├── controllers/ # HTTP controllers └── plugs/ # Request middleware ``` --- ## Core Business Contexts ### Products (`lib/berrypod/products/`) - Products synced from POD providers (Printify/Printful) - Variants with pricing, cost, availability tracking - Image optimization pipeline (WebP conversion, AVIF/JPEG variants at 400/800/1200px) - Denormalized fields: `cheapest_price`, `in_stock`, `on_sale` - Status flow: draft → active → archived → discontinued ### Orders (`lib/berrypod/orders/`) - Order numbers: `SS-YYMMDD-XXXX` format - Payment tracking: pending → paid → failed → refunded - Fulfilment: unfulfilled → submitted → processing → shipped → delivered - Abandoned cart recovery (24hr inactivity triggers) - Stripe session/payment intent tracking ### Media & Images (`lib/berrypod/media/`, `lib/berrypod/images/`) - BLOB storage in SQLite - Lossless WebP conversion on upload (26-41% smaller) - Dominant color extraction for header images - Async variant generation via Oban workers - Usage tracking across products, pages, themes ### Pages (`lib/berrypod/pages/`) - 14 system pages + unlimited custom CMS pages - Block-based editor with **26 block types** (hero, text, gallery, grid, testimonials, etc.) - ETS caching with DB fallback - Auto-redirect creation when URLs change - Navigation menu integration ### Theme (`lib/berrypod/theme/`) - **3-layer CSS architecture:** 1. Primitives (CSS custom properties) 2. Attributes (theme-specific rules) 3. Semantic (component styles) - 8 presets: Gallery, Studio, Boutique, etc. - Instant switching via CSS variable injection (no reload) - WCAG contrast checking ### Analytics (`lib/berrypod/analytics/`) - Privacy-first: no cookies, no personal data, GDPR-friendly - Visitor hashing with daily-rotating salt - Event types: pageview, product_view, add_to_cart, checkout_start, purchase - Metrics: unique visitors, bounce rate, top pages, sources, countries, devices - E-commerce funnel tracking with revenue ### Providers (`lib/berrypod/providers/`) - Behaviour-based abstraction layer - **Printify**: 800+ products from 90+ print providers - **Printful**: In-house production with warehousing - Operations: test connection, fetch products, submit orders, track status, fetch shipping rates ### Reviews (`lib/berrypod/reviews/`) - 1-5 star ratings with text + images (up to 3) - Verified purchase badge - Moderation workflow: pending → approved/rejected - Rating denormalization to products ### Newsletter (`lib/berrypod/newsletter/`) - Double opt-in with confirmation emails - Plain text only (no tracking pixels) - Campaign scheduling and bulk sending - Global suppression list --- ## Database Schema (26 Schemas) **Core entities:** - `User`, `UserToken` - Authentication - `Product`, `ProductImage`, `ProductVariant` - Catalog - `ProviderConnection` - POD credentials (encrypted) - `Order`, `OrderItem`, `AbandonedCart` - Commerce - `Page`, `NavItem`, `SocialLink` - Content - `Image`, `FaviconVariant` - Media - `ShippingRate` - Rates by country/provider - `Review` - Product reviews - `Newsletter.Subscriber`, `Newsletter.Campaign` - Email - `Analytics.Event` - Tracking - `ActivityLog.Entry` - System events - `Redirects.Redirect`, `BrokenUrl`, `DeadLink` - URLs - `Setting` - Configuration (JSON, encrypted) --- ## Background Jobs (Oban) ### Scheduled (cron) | Schedule | Worker | Purpose | |----------|--------|---------| | Every 30min | `FulfilmentStatusWorker` | Poll provider for order updates | | Every 6hr | `ScheduledSyncWorker` | Product sync | | Daily 3am | `RetentionWorker` | Delete old analytics | | Daily 3:30am | `DeadLinkCheckerWorker` | Scan for broken links | | Every 5min | `ScheduledCampaignWorker` | Send scheduled campaigns | ### On-demand - `ProductSyncWorker` - Sync products from provider - `ImageDownloadWorker` - Download product images - `OptimizeWorker` - Generate image variants - `OrderSubmissionWorker` - Submit to fulfilment - `ReviewRequestWorker` - Send review request after delivery - `CampaignSendWorker` - Newsletter campaigns --- ## Web Layer ### Admin LiveViews (`/admin/*`) - Dashboard, Analytics, Orders, Products, Providers - Settings, Media, Pages, Newsletter, Reviews - Activity log, Backup, Redirects ### Shop LiveViews (public) - Home, Collections, Products, Cart, Checkout - Contact (with order lookup), Search, Review forms - Custom CMS pages via catch-all route `/:slug` ### Key Routes | Path | Purpose | |------|---------| | `/` | Shop home | | `/collections/:slug` | Category browsing | | `/products/:id` | Product detail | | `/cart` | Shopping cart | | `/admin` | Admin dashboard | | `/admin/orders` | Order management | | `/admin/pages` | Page editor | | `/admin/media` | Media library | | `/admin/analytics` | Analytics dashboard | | `/admin/theme` | Theme editor | | `/:slug` | Custom pages (catch-all) | --- ## Asset Pipeline **No Tailwind** - Hand-written CSS with: - `@layer` for cascade organization - Native CSS nesting - `oklch()` color function - CSS custom properties for theming **Bundles:** - `berrypod` - Main JS - `berrypod_shop_css` - Storefront styles - `berrypod_admin_css` - Admin styles - `berrypod_theme_css` - Dynamic theme CSS --- ## Key Features ### For Shop Owners - Product sync from Printify/Printful with image optimization - Block-based CMS page builder (26+ block types) - Live theme editor with 8 presets - Privacy-first analytics (no cookies, GDPR-friendly) - Order management with fulfilment tracking - Abandoned cart recovery emails - Newsletter with double opt-in - Product review system with moderation - Activity log for system events ### For Customers - Product browsing with collections/filters - Session-based shopping cart - Stripe checkout - Order lookup via email - Review submissions --- ## Security & Performance ### Security - Vault encryption for secrets - CSRF protection, secure headers - TOTP two-factor auth for admin - Webhook signature verification (Stripe, Printify, Printful) ### Performance - ETS caching (settings, theme CSS, pages, redirects) - Streams for LiveView collections - Batch analytics flushing - Image variants with lazy generation - Pagination throughout --- ## Outstanding Work ### Active Plans (Ready to Implement) #### 1. Profit-Aware Pricing & Sales ([plan](plans/profit-aware-pricing.md)) ~16h | Task | Est | Status | |------|-----|--------| | Fix Printful cost sync (catalog API cross-reference) | 45m | planned | | Cost snapshot on orders (`unit_cost`, `gross_profit`) | 1.5h | planned | | Exact Stripe fees from Balance Transaction API | 45m | planned | | Tax toggle + Stripe Tax integration | 1.5h | planned | | Admin profit dashboard (margins, P&L) | 3h | planned | | Profit-aware price editor (live margin display) | 2h | planned | | Sales & promotions (%, fixed, scoped, scheduled) | 3h | planned | | Margin guard (prevent profit-killing discounts) | 1h | planned | | Announcement bar for active sales | 1.5h | planned | #### 2. Competitive Gaps - Phase 1: Core Commerce ([plan](plans/competitive-gaps.md)) ~17h | Task | Est | Status | |------|-----|--------| | Customer authentication schema | 2h | planned | | Customer auth flows (login, register, reset) | 3h | planned | | Link orders to customers | 1.5h | planned | | Customer account dashboard | 2h | planned | | Saved addresses | 1.5h | planned | | Guest checkout linking | 1h | planned | | PayPal SDK integration | 2h | planned | | PayPal checkout flow | 3h | planned | | PayPal webhooks | 1.5h | planned | #### 3. Competitive Gaps - Phase 2: Retention & Growth ~14h | Task | Est | Status | |------|-----|--------| | Returns schema | 1.5h | planned | | Return request flow | 2h | planned | | Return admin | 2h | planned | | Return policy settings | 1h | planned | | Email sequence schema | 2h | planned | | Sequence triggers & sending | 3h | planned | | Sequence admin | 2h | planned | | Customer data export (GDPR) | 1.5h | planned | | Customer data deletion (GDPR) | 2h | planned | #### 4. Competitive Gaps - Phase 3: Scale ~7h | Task | Est | Status | |------|-----|--------| | Blog post type | 3h | planned | | Staff accounts & RBAC | 4h | planned | #### 5. SEO Enhancements ([plan](plans/seo-enhancements.md)) ~21h | Task | Est | Status | |------|-----|--------| | Per-page noindex/nofollow + meta descriptions | 2h | planned | | Enhanced Organization schema | 2h | planned | | Image sitemap entries | 1h | planned | | SEO preview panel (Google + social cards) | 4h | planned | | Focus keyword & SEO score/checklist | 4h | planned | | FAQ block with FAQPage schema | 2h | planned | | Google Search Console OAuth integration | 6h | planned | #### 6. Draft-then-Publish Workflow ([plan](plans/draft-publish-workflow.md)) ~31h | Phase | Description | Est | |-------|-------------|-----| | 0 | Site-level publishing (coming soon → live) | 1.5h | | 1 | Page versions and drafts (auto-save, publish/discard) | 7h | | 2 | Theme drafts | 4h | | 3 | Settings drafts | 4h | | 4 | Version history and rollback (diff view, history panel) | 5.5h | | 5 | Image soft delete and trash (usage check, restore, auto-purge) | 4.5h | | 6 | Polish and pruning (conflict handling, retention worker) | 4.25h | Key features: auto-save drafts, explicit publish, version history with rollback, image trash/recycle bin, tiered version retention. --- ### Platform/Business Items | Task | Status | |------|--------| | Platform/marketing site (brochure, pricing, sign-up) | planned | | Separation of platform site vs AGPL open source core | planned | --- ### Production Hardening | Item | Description | |------|-------------| | Litestream / SQLite replication | Continuous backup to S3, point-in-time recovery | | End-to-end & accessibility tests | Wallaby browser tests, WCAG 2.1 AA | | Security monitoring | Paraxial.io for runtime security, bot detection, rate limiting | | AGPL licensing | LICENSE file, contribution guidelines, release process | --- ### Future Enhancements | Feature | Description | |---------|-------------| | Multiple print providers | Route products to different providers based on cost/type | | Product page improvements | Pre-checkout validation, cost monitoring, better gallery | | Editable email templates | Admin UI for customizing transactional emails | | Hosted platform infrastructure | Multi-tenancy, OAuth connect for providers/payments | | Migration & export | Shopify/WooCommerce import, data export | | Internationalisation | Multi-language (Gettext), currency formatting, RTL | --- ### Summary by Priority **High priority (core commerce):** 1. Customer accounts + PayPal (~17h) 2. Profit-aware pricing + sales (~16h) **Medium priority (polish):** 3. SEO enhancements (~21h) 4. Draft-then-publish workflow (~31h) 5. Returns system (~6.5h) 6. Email sequences (~7h) **Lower priority (scale):** 7. Blog post type (3h) 8. Staff accounts & RBAC (4h) 9. Platform site (TBD) **Total estimated remaining:** ~100-120h of planned work, plus the larger platform vision items. --- ## Design Philosophy 1. **"One theme, infinite variations"** — one solid foundation with curated customisation 2. **Constrained creativity** — limit choices to prevent poor design outcomes 3. **No professional photography required** — works with product mockups 4. **Mobile-first** — all features work on touch devices 5. **Ethical design** — no dark patterns or fake urgency 6. **Privacy-first** — cookie-free analytics, GDPR-compliant cart recovery, no tracking pixels