from flask import Flask, request, jsonify from functools import wraps import psycopg2 from psycopg2.extras import RealDictCursor import os import hashlib from datetime import datetime app = Flask(__name__) H_INSTANCIA = os.environ.get('H_INSTANCIA') DB_HOST = os.environ.get('DB_HOST', '172.17.0.1') DB_PORT = os.environ.get('DB_PORT', '5432') DB_NAME = os.environ.get('DB_NAME', 'corp') DB_USER = os.environ.get('DB_USER', 'corp') DB_PASSWORD = os.environ.get('DB_PASSWORD', 'corp') PORT = int(os.environ.get('PORT', 5054)) def get_db(): return psycopg2.connect( host=DB_HOST, port=DB_PORT, database=DB_NAME, user=DB_USER, password=DB_PASSWORD, cursor_factory=RealDictCursor ) def require_auth(f): @wraps(f) def decorated(*args, **kwargs): auth_key = request.headers.get('X-Auth-Key') if not auth_key or auth_key != H_INSTANCIA: return jsonify({'error': 'Unauthorized'}), 401 return f(*args, **kwargs) return decorated def generate_hash(data): return hashlib.sha256(f"{data}{datetime.now().isoformat()}".encode()).hexdigest()[:64] @app.route('/health', methods=['GET']) def health(): try: conn = get_db() cur = conn.cursor() cur.execute('SELECT 1') cur.close() conn.close() return jsonify({'status': 'healthy', 'service': 'feldman', 'version': '1.0.0'}) except Exception as e: return jsonify({'status': 'unhealthy', 'error': str(e)}), 500 @app.route('/s-contract', methods=['GET']) def s_contract(): return jsonify({ 'service': 'feldman', 'version': '1.0.0', 'contract_version': 'S-CONTRACT v2.1', 'description': 'Receives routed OK flows from ALFRED/JARED', 'endpoints': { '/health': {'method': 'GET', 'auth': False}, '/recibir': {'method': 'POST', 'auth': True, 'desc': 'Receive completed flow'}, '/completados': {'method': 'GET', 'auth': True, 'desc': 'List completed flows'}, '/stats': {'method': 'GET', 'auth': True, 'desc': 'Statistics'} } }) @app.route('/recibir', methods=['POST']) @require_auth def recibir(): data = request.get_json() or {} h_completado = generate_hash(str(data)) conn = get_db() cur = conn.cursor() cur.execute(''' INSERT INTO completados (h_completado, h_instancia_origen, h_ejecucion, flujo_nombre, datos, notas) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id, h_completado, created_at ''', ( h_completado, data.get('h_instancia_origen', 'unknown'), data.get('h_ejecucion', ''), data.get('flujo_nombre', ''), psycopg2.extras.Json(data), data.get('notas', '') )) result = cur.fetchone() conn.commit() cur.close() conn.close() return jsonify({'success': True, 'registro': dict(result), 'service': 'feldman'}) @app.route('/completados', methods=['GET']) @require_auth def completados(): limit = request.args.get('limit', 50, type=int) conn = get_db() cur = conn.cursor() cur.execute('SELECT * FROM completados ORDER BY created_at DESC LIMIT %s', (limit,)) records = cur.fetchall() cur.close() conn.close() return jsonify({'completados': [dict(r) for r in records], 'count': len(records)}) @app.route('/stats', methods=['GET']) @require_auth def stats(): conn = get_db() cur = conn.cursor() cur.execute('SELECT COUNT(*) as total FROM completados') total = cur.fetchone()['total'] cur.execute(''' SELECT DATE(created_at) as fecha, COUNT(*) as count FROM completados GROUP BY DATE(created_at) ORDER BY fecha DESC LIMIT 7 ''') por_dia = {str(r['fecha']): r['count'] for r in cur.fetchall()} cur.close() conn.close() return jsonify({'total': total, 'por_dia': por_dia}) if __name__ == '__main__': app.run(host='0.0.0.0', port=PORT, debug=False)