""" app/admin/__init__.py — Admin app factory (admin.mydomain.com). """ import logging from datetime import timedelta from flask import Flask from app.extensions import db, migrate, csrf, mail, scheduler, admin_login_manager, admin_jwt, limiter from app.security import apply_security_headers, check_admin_ip from config import get_config logger = logging.getLogger(__name__) def create_admin_app(config_override=None): flask_app = Flask( __name__, template_folder="../templates", static_folder="../static/admin", static_url_path="/static", ) # ── Config ──────────────────────────────────────────────── cfg = config_override or get_config() flask_app.config.from_object(cfg) # Admin portal uses a separate secret key and session cookie name import os flask_app.config["SECRET_KEY"] = os.environ.get( "ADMIN_SECRET_KEY", flask_app.config["SECRET_KEY"] ) flask_app.config["SESSION_COOKIE_NAME"] = "salon_pos_admin_session" flask_app.config["PERMANENT_SESSION_LIFETIME"] = timedelta( seconds=int(os.environ.get("SESSION_TIMEOUT_ADMIN", 3600)) ) flask_app.config["SESSION_COOKIE_HTTPONLY"] = True flask_app.config["SESSION_COOKIE_SAMESITE"] = "Lax" # ── Extensions ──────────────────────────────────────────── db.init_app(flask_app) migrate.init_app(flask_app, db) csrf.init_app(flask_app) mail.init_app(flask_app) limiter.init_app(flask_app) # Admin login manager admin_login_manager.login_view = "admin_auth.login" admin_login_manager.login_message_category = "warning" admin_login_manager.session_protection = "strong" admin_login_manager.init_app(flask_app) # Admin JWT admin_jwt.init_app(flask_app) # ── User loader ─────────────────────────────────────────── from app.models.platform import SystemUser @admin_login_manager.user_loader def load_admin_user(user_id: str): if not user_id.startswith("system:"): return None try: uid = int(user_id.split(":")[1]) except (ValueError, IndexError): return None return SystemUser.query.get(uid) # ── Security ────────────────────────────────────────────── apply_security_headers(flask_app) check_admin_ip(flask_app) # ── Blueprints ──────────────────────────────────────────── from app.admin.auth.routes import admin_auth_bp from app.admin.system_users.routes import system_users_bp from app.admin.tenants.routes import tenants_bp from app.admin.plans.routes import plans_bp from app.admin.billing.routes import billing_bp from app.admin.settings_override.routes import settings_override_bp from app.admin.audit_log.routes import audit_log_bp from app.admin.analytics.routes import analytics_bp for bp in [admin_auth_bp, system_users_bp, tenants_bp, plans_bp, billing_bp, settings_override_bp, audit_log_bp, analytics_bp]: flask_app.register_blueprint(bp) # ── Import all models for Migrate ───────────────────────── import app.models # noqa: F401 logger.info("Admin app created (env=%s)", flask_app.config.get("FLASK_ENV")) return flask_app