Files
beanflows/web/CHANGELOG.md
Deeman 4b7d4d5a74 Update from Copier template v0.4.0
- Accept RBAC system: user_roles table, role_required decorator, grant_role/revoke_role/ensure_admin_role functions
- Accept improved billing architecture: billing_customers table separation, provider-agnostic naming
- Accept enhanced user loading with subscription/roles eager loading in app.py
- Accept improved email templates with branded styling
- Accept new infrastructure: migration tracking, transaction logging, A/B testing
- Accept template improvements: Resend SDK, Tailwind build stage, UMAMI analytics config
- Keep beanflows-specific configs: BASE_URL 5001, coffee PLAN_FEATURES/PLAN_LIMITS
- Keep beanflows analytics integration and DuckDB health check
- Add new test files and utility scripts from template

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-02-19 22:22:13 +01:00

4.5 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

[Unreleased]

Changed

  • Role-based access control: user_roles table with role_required() decorator replaces password-based admin auth
  • Admin is a real user: admins authenticate via magic links; ADMIN_EMAILS env var auto-grants admin role on login
  • Separated billing entities: billing_customers table holds payment provider identity; subscriptions table holds only subscription state
  • Multiple subscriptions per user: dropped UNIQUE constraint on subscriptions.user_id; upsert_subscription finds by provider_subscription_id

Added

  • Simple A/B testing with @ab_test decorator and optional Umami data-tag integration (UMAMI_SCRIPT_URL / UMAMI_WEBSITE_ID env vars)
  • user_roles table and grant_role() / revoke_role() / ensure_admin_role() functions
  • billing_customers table and upsert_billing_customer() / get_billing_customer() functions
  • role_required(*roles) decorator in auth
  • is_admin template context variable
  • Migration 0001_roles_and_billing_customers.py for existing databases

Removed

  • ADMIN_PASSWORD env var and password-based admin login
  • provider_customer_id column from subscriptions table
  • admin/templates/admin/login.html

Changed

  • Provider-agnostic schema: generic provider_customer_id / provider_subscription_id columns replace provider-prefixed names (stripe_customer_id, paddle_customer_id, lemonsqueezy_customer_id) — eliminates all Jinja conditionals from schema, SQL helpers, and route code
  • Consolidated subscription_required decorator: single implementation in auth/routes.py supporting both plan and status checks, reads from eager-loaded g.subscription (zero extra queries)
  • Eager-loaded g.subscription: load_user in app.py now fetches user + subscription in a single JOIN; available in all routes and templates via g.subscription

Added

  • transactions table for recording payment/refund events with idempotent record_transaction() helper
  • Billing event hook system: on_billing_event() decorator and _fire_hooks() for domain code to react to subscription changes; errors are logged and never cause webhook 500s

Removed

  • Duplicate subscription_required decorator from billing/routes.py (consolidated in auth/routes.py)
  • get_user_with_subscription() from auth/routes.py (replaced by eager-loaded g.subscription)

Changed

  • Email SDK migration: replaced raw httpx calls with official resend SDK in core.py
    • Added from_addr parameter to send_email() for multi-address support
    • Added EMAIL_ADDRESSES dict for named sender addresses (transactional, etc.)
  • Paddle SDK migration: replaced raw httpx calls with official paddle-python-sdk in billing/routes.py
    • Checkout, manage, cancel routes now use typed SDK methods (PaddleClient, CreateTransaction)
    • Webhook verification uses SDK's Verifier instead of hand-rolled HMAC
    • Added PADDLE_ENVIRONMENT config for sandbox/production toggling
    • Added _paddle_client() helper factory
  • Dependencies: resend replaces httpx for email; paddle-python-sdk replaces httpx for Paddle billing; httpx now only included for LemonSqueezy projects
  • Worker send_email task handler now passes through from_addr

Added

  • scripts/setup_paddle.py — CLI script to create Paddle products/prices programmatically (Paddle projects only)

Changed

  • Pico CSS → Tailwind CSS v4 — full design system migration across all templates
    • Standalone Tailwind CLI binary (no Node.js) with make css-build / make css-watch
    • Brand theme with component classes (.btn, .card, .form-input, .table, .badge, .flash, etc.)
    • Self-hosted Commit Mono font for monospace data display
    • Docker multi-stage build: CSS compiled in dedicated stage before Python build

Removed

  • Pico CSS CDN dependency
  • custom.css (replaced by Tailwind input.css with @layer components)
  • JetBrains Mono font (replaced by self-hosted Commit Mono)

Fixed

  • Admin template collision: namespaced admin templates under admin/ subdirectory to prevent Quart's template loader from resolving auth's login.html or dashboard's index.html instead of admin's
  • Admin user detail: stripe_customer_id hardcoded regardless of payment provider — now uses provider-aware Copier conditional (Stripe/Paddle/LemonSqueezy)

Added

  • Initial project scaffolded from quart_saas_boilerplate