import json import os from dotenv import load_dotenv from flask import Flask, jsonify from flask_cors import CORS from flask_jwt_extended import JWTManager from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy # Create extensions but don't initialize them yet db = SQLAlchemy() migrate = Migrate() jwt = JWTManager() cors = CORS() load_dotenv(override=True) def create_app(config_name=None): """Application factory pattern""" app = Flask(__name__) # Load configuration if config_name is None: config_name = os.environ.get("FLASK_ENV", "development") from app.config import config_by_name app.config.from_object(config_by_name[config_name]) print("----------------------------------------------------------") print(f"------------------ENVIRONMENT: {config_name}-----------------------") print(json.dumps(dict(app.config), indent=2, default=str)) print("----------------------------------------------------------") # Initialize extensions with app db.init_app(app) migrate.init_app(app, db) jwt.init_app(app) cors.init_app( app, resources={r"/api/*": {"origins": app.config.get("CORS_ORIGINS", "*")}} ) # Initialize Celery from app.celery import init_celery init_celery(app) # Import models (required for migrations) # Register blueprints from app.routes import api_bp, health_bp, home_bp from app.routes.kanban import kanban_bp app.register_blueprint(api_bp, url_prefix="/api") app.register_blueprint(health_bp, url_prefix="/health") app.register_blueprint(home_bp) app.register_blueprint(kanban_bp, url_prefix="/api") # Global error handlers @app.errorhandler(404) def not_found(error): print(f"404 Error: {error}") return jsonify({"error": "Not found"}), 404 @app.errorhandler(500) def internal_error(error): print(f"500 Error: {error}") return jsonify({"error": "Internal server error"}), 500 @app.errorhandler(422) def validation_error(error): print(f"422 Error: {error}") return jsonify({"error": "Validation error"}), 422 @app.teardown_appcontext def shutdown_session(exception=None): """Remove session at end of request to return connection to pool""" db.session.remove() return app