47 lines
1.5 KiB
Python
47 lines
1.5 KiB
Python
import os
|
|
import logging
|
|
from flask import Flask
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
# Sentry — guarded on SENTRY_DSN being set, so earlier phases and local
|
|
# dev never silently depend on it (CLAUDE.md §22 Observability). Must
|
|
# be initialised before the Flask app is constructed so FlaskIntegration
|
|
# can instrument it.
|
|
SENTRY_DSN = os.getenv('SENTRY_DSN')
|
|
if SENTRY_DSN:
|
|
import sentry_sdk
|
|
from sentry_sdk.integrations.flask import FlaskIntegration
|
|
from sentry_sdk.integrations.rq import RqIntegration
|
|
|
|
def _scrub_sensitive_data(event, hint):
|
|
"""Removes headers (which may carry X-API-Key/session tokens) from Sentry events. PII must never reach Sentry."""
|
|
if 'request' in event:
|
|
event['request'].pop('headers', None)
|
|
return event
|
|
|
|
sentry_sdk.init(
|
|
dsn=SENTRY_DSN,
|
|
integrations=[FlaskIntegration(), RqIntegration()],
|
|
traces_sample_rate=0.1,
|
|
environment=os.getenv('FLASK_ENV', 'production'),
|
|
send_default_pii=False,
|
|
before_send=_scrub_sensitive_data,
|
|
)
|
|
|
|
from extensions import limiter, cors # noqa: E402
|
|
from api import api_bp # noqa: E402
|
|
|
|
# Entry point only — imports and wires everything together. Business
|
|
# logic lives in services/, data access in repositories/, routes in
|
|
# api.py. Nothing else belongs in this file per CLAUDE.md §5/§18.
|
|
app = Flask(__name__)
|
|
limiter.init_app(app)
|
|
cors.init_app(app)
|
|
app.register_blueprint(api_bp)
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=5000, debug=False)
|