No description
  • Python 98%
  • HTML 1.3%
  • Dockerfile 0.4%
  • Shell 0.3%
Find a file
Astounds a725147053
All checks were successful
CI/CD / ci (push) Successful in 3m25s
CI/CD / publish (push) Successful in 12m5s
refactor: migrate from eventlet to gevent for WebSocket support
- Replace eventlet with gevent + gevent-websocket in requirements.txt
- Update wsgi_ws.py, run_ws.py: monkey_patch_all() → gevent, async_mode="gevent"
- Update docker-entrypoint.sh: --worker-class gevent
- Update tests: SocketIO(async_mode="gevent") for gevent test client
- Update mypy.ini: [mypy-eventlet] → [mypy-gevent]
- Update all docs: README, development.md, api-reference.md, .env.example
- Doc fix: add missing RATELIMIT_DEFAULT to env vars table
2026-06-22 12:36:35 -05:00
.forgejo/workflows update 2026-06-21 14:59:11 -05:00
app feat: rate-limit POST /auth/register per IP via REGISTER_RATELIMIT env var (default 5/hour) 2026-06-21 21:09:30 -05:00
docs refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
tests refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
.dockerignore feat: add CI, Docker, docs; fix lint; refactor repos 2026-06-21 14:36:02 -05:00
.env.example refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
.gitignore docs: full documentation overhaul, WebSocket, .http and .gitignore fixes 2026-06-21 18:28:58 -05:00
config.py feat: rate-limit POST /auth/register per IP via REGISTER_RATELIMIT env var (default 5/hour) 2026-06-21 21:09:30 -05:00
docker-compose.yml docs: full documentation overhaul, WebSocket, .http and .gitignore fixes 2026-06-21 18:28:58 -05:00
docker-entrypoint.sh refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
Dockerfile fix: replace shell-form CMD with exec-form entrypoint for signal handling 2026-06-21 16:50:21 -05:00
LICENSE initial commit 2026-06-21 12:01:54 -05:00
mypy.ini refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
README.md refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
requirements-dev.txt docs: full documentation overhaul, WebSocket, .http and .gitignore fixes 2026-06-21 18:28:58 -05:00
requirements.txt refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
run.py feat: add ALLOW_REGISTRATION toggle, fix lint/type errors 2026-06-21 16:22:45 -05:00
run_ws.py refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00
sample.http fix: sample.http clean English, .http files with OTP and @otpCode 2026-06-21 20:59:42 -05:00
wsgi_ws.py refactor: migrate from eventlet to gevent for WebSocket support 2026-06-22 12:36:35 -05:00

Overrun API

API REST Flask con integración a OpenAI/OpenRouter, autenticación JWT + MFA (TOTP), chat streaming SSE, file upload, WebSocket typing indicators, logout real con token blacklist, password reset, y arquitectura limpia.

Stack

Capa Tecnología
Framework Flask (app factory)
ORM SQLAlchemy 2.0
DB SQLite (dev) / PostgreSQL (prod)
Auth JWT + MFA TOTP (pyotp) + JTI blacklist + OTP email
Validación Marshmallow
AI Providers OpenAI SDK / OpenRouter HTTP / Mock + streaming SSE
File Upload Multipart, extensiones configurables, ownership checks
WebSocket SocketIO (typing indicators, opt-in)
Security Bcrypt, CSP, HSTS, X-Frame-Options, rate limiting

Arquitectura

graph TD
    Client["Cliente"] --> API["REST API /api/v1"]
    Client --> WS["WebSocket /socket.io"]
    API --> Auth["Auth Routes"]
    API --> Chat["Chat Routes"]
    API --> Files["File Routes"]
    API --> Health["Health Route"]

    Auth --> AuthSvc["Auth Service"]
    AuthSvc --> UserRepo["User Repository"]
    AuthSvc --> OTPSvc["OTP Service"]
    AuthSvc --> MFASvc["MFA (TOTP)"]
    AuthSvc --> Blacklist["TokenBlacklist"]

    Chat --> ConvRepo["Conversation Repository"]
    Chat --> MsgRepo["Message Repository"]
    Chat --> AISvc["AI Service"]
    AISvc --> OpenAI["OpenAI Provider"]
    AISvc --> OpenRouter["OpenRouter Provider"]
    AISvc --> Mock["Mock Provider"]

    Files --> AttachRepo["Attachment Repository"]
    Files --> UploadDir[("uploads/")]

    WS --> ChatNS["ChatNamespace"]
    ChatNS --> ConvRepo

    UserRepo --> DB[("SQLite / PostgreSQL")]
    OTPSvc --> OTPRepo["OTP Repository"]
    OTPRepo --> DB
    ConvRepo --> DB
    MsgRepo --> DB
    Blacklist --> DB

    classDef api fill:#2b5797,color:#fff
    classDef svc fill:#0078d4,color:#fff
    classDef repo fill:#4a4a4a,color:#fff
    classDef prov fill:#2e7d32,color:#fff
    classDef db fill:#6a1b9a,color:#fff
    classDef client fill:#e65100,color:#fff
    class API,Auth,Chat,Files,Health api
    class AuthSvc,OTPSvc,AISvc,MFASvc svc
    class UserRepo,OTPRepo,ConvRepo,MsgRepo,Blacklist,AttachRepo repo
    class OpenAI,OpenRouter,Mock prov
    class WS,ChatNS client
    class UploadDir db
    class DB db
    class Client client

Quick Start

python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# edit .env → set AI_PROVIDER, API keys
python run.py                    # REST only (dev)
python run_ws.py                 # REST + WebSocket (dev, gevent)

Endpoints

Auth

Método Ruta Descripción
POST /api/v1/auth/register Registrar usuario
POST /api/v1/auth/login Login (username/email/phone)
POST /api/v1/auth/refresh Refrescar access token
GET /api/v1/auth/me Perfil actual
PUT /api/v1/auth/me Editar perfil (username/email/phone)
PUT /api/v1/auth/me/password Cambiar contraseña
DELETE /api/v1/auth/me Eliminar cuenta (soft-delete)
POST /api/v1/auth/logout Logout real (revoca JTI)
POST /api/v1/auth/otp/send Enviar OTP por email
POST /api/v1/auth/otp/verify-email Verificar email con OTP
POST /api/v1/auth/password-reset/request Solicitar reset de contraseña
POST /api/v1/auth/password-reset/confirm Confirmar reset con OTP
POST /api/v1/auth/mfa/enroll Generar secreto TOTP
POST /api/v1/auth/mfa/verify Activar MFA
POST /api/v1/auth/mfa/verify-login Verificar MFA en login

Chat

Método Ruta Descripción
GET /api/v1/chat/models Listar modelos AI disponibles
GET /api/v1/chat/conversations Listar conversaciones
POST /api/v1/chat/conversations Crear conversación
GET /api/v1/chat/conversations/<id> Ver conversación + mensajes
PATCH /api/v1/chat/conversations/<id> Renombrar conversación
DELETE /api/v1/chat/conversations/<id> Eliminar conversación
POST /api/v1/chat/conversations/<id>/messages Enviar mensaje (+ streaming SSE)
PATCH /api/v1/chat/conversations/<id>/messages/<msg> Editar mensaje
DELETE /api/v1/chat/conversations/<id>/messages/<msg> Borrar mensaje

Files

Método Ruta Descripción
POST /api/v1/files/upload Subir archivo (multipart)
GET /api/v1/files/<id> Descargar archivo

Health

Método Ruta
GET /api/v1/health

Features

  • Chat streaming SSE — enviar "stream": true en mensaje para recibir tokens via Server-Sent Events
  • File upload — subir archivos (multipart), referenciar por ID al enviar mensajes
  • WebSocket typing indicators — opt-in con USE_WEBSOCKET=true, requiere worker gevent
  • Logout real — revoca el JWT via TokenBlacklist (JTI blacklist), tokens revocados son rechazados
  • Password reset — flujo request + confirm via OTP, reusa el sistema de email existente
  • Rate limit storage — intercambiable via RATELIMIT_STORAGE_URL (memory:// por defecto, redis:// para Redis/Valkey)
  • Registro bloqueableALLOW_REGISTRATION=false desactiva nuevos registros

Documentación

Recurso Descripción
sample.http Quick start con REST Client (VS Code)
docs/api-reference.md Schemas request/response, errores, seguridad, WebSocket
docs/auth-flow.md Flujo auth: dev vs prod, MFA TOTP, JWT, OTP, password reset
docs/development.md Guía dev: agregar endpoints, providers, WebSocket, convenciones
docs/openapi.yaml OpenAPI 3.1 spec (28 paths, servida en /api/v1/openapi.json)

Docker

docker compose up -d           # PostgreSQL + MailHog + App
docker compose logs -f app
docker compose down

WebSocket en producción: USE_WEBSOCKET=true docker compose up -d

Tests

FLASK_ENV=test python -m pytest tests/ -v

Security (OWASP)

  • CSP, HSTS, X-Frame-Options, X-Content-Type-Options en toda respuesta
  • Input validation + sanitización (bleach) en toda entrada usuario
  • Passwords hasheados con bcrypt
  • OTP codes hasheados con SHA-256, max 5 intentos
  • Rate limiting: 100 req/hora por IP (configurable)
  • JWT en headers, expiración corta, MFA step-up token 5min
  • JTI blacklist: tokens revocados en logout son rechazados automáticamente
  • CORS restringido a orígenes configurados

License

AGPL-3.0