""" Flask application factory for Garmin Health Lab. Run directly (`python app.py`) for development, or serve with Gunicorn: gunicorn wsgi:app -b 0.0.0.0:5000 """ import os from flask import Flask, jsonify, send_from_directory from flask_cors import CORS import db from config import CORS_ORIGINS, PORT, STATIC_DIR from routes import auth, garmin, health, analysis def create_app(): app = Flask(__name__) CORS(app, resources={r"/api/*": {"origins": CORS_ORIGINS}}, supports_credentials=True) # Create tables once at startup (idempotent). db.init_db() # In production the built React app is served by this same process, so the # deployment is a single port with no reverse proxy to configure. In # development STATIC_DIR does not exist and the CRA dev server serves the # UI instead — hence the guard rather than an unconditional route. has_ui = bool(STATIC_DIR) and os.path.isfile(os.path.join(STATIC_DIR, "index.html")) @app.route("/") def index(): if has_ui: return send_from_directory(STATIC_DIR, "index.html") return jsonify({"name": "Garmin Health Lab API", "version": "1.0.0"}) @app.route("/api/health/status") def health_status(): return jsonify({"status": "ok", "db": db.DB_TYPE}) app.register_blueprint(auth.bp, url_prefix="/api/auth") app.register_blueprint(garmin.bp, url_prefix="/api/garmin") app.register_blueprint(health.bp, url_prefix="/api/health") app.register_blueprint(analysis.bp, url_prefix="/api/analysis") @app.errorhandler(404) def not_found(_e): # API paths always answer in JSON. Everything else falls through to the # SPA so client-side routes (/settings, /recommendations, ...) survive a # page reload instead of 404-ing. from flask import request if has_ui and not request.path.startswith("/api/"): asset = request.path.lstrip("/") if asset and os.path.isfile(os.path.join(STATIC_DIR, asset)): return send_from_directory(STATIC_DIR, asset) return send_from_directory(STATIC_DIR, "index.html") return jsonify({"error": "not found"}), 404 @app.errorhandler(500) def server_error(_e): return jsonify({"error": "internal error"}), 500 return app app = create_app() if __name__ == "__main__": app.run(host="0.0.0.0", port=PORT, debug=False)