diff --git a/src/app.py b/src/app.py index 3f78311..3072561 100644 --- a/src/app.py +++ b/src/app.py @@ -585,6 +585,11 @@ from src.api.api_v1 import api_v1_bp, init_api_v1_helpers from src.api.audit import audit_bp from src.api.docs import docs_bp +# Marketing redesign 2026 blueprints (Phase 1: B-1.2) +from src.marketing import marketing_bp +from src.billing import billing_bp +from src.legal import legal_bp + # Database initialization (extracted to src/init_db.py) from src.init_db import initialize_database with app.app_context(): @@ -632,6 +637,14 @@ csrf.exempt(api_v1_bp) # API v1 uses token auth, not CSRF app.register_blueprint(audit_bp) app.register_blueprint(docs_bp) +# Marketing redesign 2026 blueprints (Phase 1: B-1.2) +# - marketing_bp at "/" (placeholder; coexists with recordings_bp.index, resolved in B-1.3) +# - billing_bp at /checkout/* (routes added in B-2.7 and B-2.8) +# - legal_bp at /legal/* (routes added in B-2.9) +app.register_blueprint(marketing_bp) +app.register_blueprint(billing_bp) +app.register_blueprint(legal_bp) + # File monitor and scheduler initialization functions below # Startup functions (extracted to src/config/startup.py) diff --git a/src/billing/__init__.py b/src/billing/__init__.py new file mode 100644 index 0000000..198bed2 --- /dev/null +++ b/src/billing/__init__.py @@ -0,0 +1,11 @@ +"""Billing blueprint - Stripe Checkout, webhook, subscription management. + +Mounted at /checkout/* prefix for the customer-facing checkout flow. The +/webhooks/stripe route (added in B-2.8) bypasses the prefix and is also +csrf-exempted. + +Routes added in Tasks B-2.7 (checkout) and B-2.8 (webhook). +""" +from flask import Blueprint + +billing_bp = Blueprint('billing', __name__, url_prefix='/checkout') diff --git a/src/legal/__init__.py b/src/legal/__init__.py new file mode 100644 index 0000000..b7a7a05 --- /dev/null +++ b/src/legal/__init__.py @@ -0,0 +1,11 @@ +"""Legal blueprint - Conditions, Confidentialite (Loi 25), Cookies, Remboursement, +Accessibilite, Mentions. + +Mounted at /legal/* prefix. Content rendered from markdown files in +src/legal/content/ (added in Task B-2.9). + +Routes added in Task B-2.9. +""" +from flask import Blueprint + +legal_bp = Blueprint('legal', __name__, url_prefix='/legal') diff --git a/src/marketing/__init__.py b/src/marketing/__init__.py new file mode 100644 index 0000000..bfdc56e --- /dev/null +++ b/src/marketing/__init__.py @@ -0,0 +1,11 @@ +"""Marketing blueprint - landing pages, public content, SEO/GEO assets. + +Mounted at root "/" (no url_prefix). Coexists with the legacy /api/* and /app/* +blueprints. Routes added incrementally in Phase 2 (Tasks A-2.x). +""" +from flask import Blueprint + +marketing_bp = Blueprint('marketing', __name__) + +# Import routes module so it registers route handlers via decorators +from . import routes # noqa: E402,F401 diff --git a/src/marketing/routes.py b/src/marketing/routes.py new file mode 100644 index 0000000..4ae1429 --- /dev/null +++ b/src/marketing/routes.py @@ -0,0 +1,20 @@ +"""Marketing routes - minimal Phase 1 placeholder. + +Real templates and content arrive in Tasks A-2.1 through A-2.8. +""" +from flask import Response + +from . import marketing_bp + + +@marketing_bp.route('/') +def landing(): + """Placeholder root route. + + Phase 1: returns a minimal HTML response so the route exists for tests. + Phase 2 (A-2.1): replaced with proper template render. + """ + return Response( + '
DictIA marketing - Phase 1 bootstrap
', + mimetype='text/html' + ) diff --git a/tests/test_blueprint_registration.py b/tests/test_blueprint_registration.py new file mode 100644 index 0000000..75e290b --- /dev/null +++ b/tests/test_blueprint_registration.py @@ -0,0 +1,66 @@ +"""Tests for Phase 1 blueprint registration (B-1.2). + +Verifies that the 3 new marketing-redesign blueprints (marketing, billing, +legal) register correctly on the global Flask app, in addition to the +existing api/auth/recordings/etc. blueprints. + +Pattern: no conftest.py, env vars set at module load time, then import +src.app.app directly. Mirrors the convention used by tests/test_audit.py. +""" + +import os +import sys + +# Add the parent directory to the path to import app (mirrors test_audit.py) +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +os.environ.setdefault('SQLALCHEMY_DATABASE_URI', 'sqlite:///:memory:') +os.environ.setdefault('SECRET_KEY', 'test-secret-key-for-blueprint-registration') + +from src.app import app # noqa: E402 + + +def test_marketing_blueprint_registered(): + assert 'marketing' in app.blueprints, ( + f"Expected marketing blueprint, found: {list(app.blueprints.keys())}" + ) + + +def test_billing_blueprint_registered(): + assert 'billing' in app.blueprints, ( + f"Expected billing blueprint, found: {list(app.blueprints.keys())}" + ) + + +def test_legal_blueprint_registered(): + assert 'legal' in app.blueprints, ( + f"Expected legal blueprint, found: {list(app.blueprints.keys())}" + ) + + +def test_marketing_landing_route_exists(): + """The marketing blueprint should expose at least a placeholder root route.""" + rules = [str(r) for r in app.url_map.iter_rules() if r.endpoint.startswith('marketing.')] + assert any('/' in r for r in rules), ( + f"Expected marketing blueprint to have a route, found: {rules}" + ) + + +def test_legal_blueprint_has_url_prefix(): + """Legal blueprint should be mounted at /legal/* prefix.""" + rules = [str(r) for r in app.url_map.iter_rules() if r.endpoint.startswith('legal.')] + assert all('/legal' in r for r in rules), ( + f"Expected /legal/ prefix on all legal routes, found: {rules}" + ) + + +def test_billing_blueprint_has_url_prefix(): + """Billing blueprint should be mounted at /checkout/* prefix. + + Phase 1 minimum: blueprint is registered but may have no routes yet. + Routes added in B-2.7 (checkout) and B-2.8 (webhook). + """ + rules = [str(r) for r in app.url_map.iter_rules() if r.endpoint.startswith('billing.')] + # Allow billing routes that don't start with /checkout (e.g. /webhooks/stripe added later) + # but at least placeholder /checkout/