13 Commits
Author SHA1 Message Date
Bentlybro e5efd669b2 Register the / -> login redirect in the app factory
The root route lived only in run.py (dev server), so gunicorn wsgi:app
never registered it and the bare domain 404'd in every deployment. Move
it into create_app so dev and prod both redirect / to the login page.
2026-07-06 14:52:18 +01:00
Bentlybro 6642f71b70 Fix stale docs and remove dead code paths
- run.py and the __init__ SocketIO comment referenced the eventlet
  worker; production uses gthread. Copy-pasting the old run.py guidance
  would have redeployed the exact config wsgi.py warns against.
- README/CLAUDE tech-stack tables said Flask 2.3.3 (actual: 3.1.3);
  CLAUDE architecture tree listed a rule_cache.py that doesn't exist.
- Drop the per-request token count that was computed and stored on the
  content object but never read (the AI paths recount as needed).
- Remove the conflicting-AI-decisions manual-review branch: the pipeline
  early-exits on the first AI match, so it could never see >1 AI result.
- Read/reset the process-global cache-store counter under the cache lock
  so it can't tear against the locked increment.
2026-07-06 13:09:24 +01:00
Bentlybro 478ca18ad8 Phase 0 hardening + batched AI moderation + websocket/perf fixes
Security / correctness
- Privilege escalation: rule/api-key/project-update routes now gate on
  can_manage_members instead of is_member; plain members could previously
  rewrite or disable moderation rules and delete API keys.
- Project.is_owner() AttributeError on non-admin API-user deletion (route
  + template) replaced with user_id comparison.
- Flask-Limiter on /auth/login, /auth/register, /auth/change-password,
  and /api/moderate (per API key id).
- Remove silent SECRET_KEY fallback: docker-compose fails hard if unset;
  production config validator refuses to boot without SECRET_KEY and
  OPENAI_API_KEY.
- Require verified email in Google OAuth auto-link flow.
- User-supplied regex now evaluated via the regex package with a 1s
  timeout, closing the ReDoS vector.
- Cap batched AI chunk count (max 40) and concurrent workers (200 -> 10).
- openai>=2.32 (from 1.55.3 so reasoning_effort kwarg works); add regex,
  Flask-Limiter, gunicorn, eventlet, psycogreen; drop the stdlib-shadowing
  pypi asyncio package.

Production runtime
- New wsgi.py: eventlet.monkey_patch + psycogreen.patch_psycopg so DB
  queries cooperate with the event loop; sets SOCKETIO_ASYNC_MODE=eventlet
  for app startup.
- Dockerfiles run as non-root app user and CMD gunicorn with
  --worker-class eventlet. run.py refuses FLASK_CONFIG=production so a
  misconfigured deploy fails loudly.
- cloudbuild.yaml stops managing env vars/secrets on deploy — it was
  about to clobber secret-backed env vars with plain ones. Runtime config
  is now owned by the Cloud Run service.

SocketIO async-mode fix (was causing full site lockup during API calls)
- async_mode picked via SOCKETIO_ASYNC_MODE env var, default "threading".
  The previous sys.modules auto-detect false-positived because
  flask_socketio / python-engineio import eventlet on load whenever it is
  installed, pinning a non-monkey-patched eventlet server in front of
  blocking stdlib I/O.

Real-time dashboard updates
- New content_received WebSocket event fires when the API accepts a
  submission; UI renders a "Processing…" row immediately and updates it
  in place when moderation_update arrives.
- Fix stale updated_at timestamp in moderation_update payloads.

Batched AI rule evaluation
- Replace the per-rule parallel fan-out (N OpenAI calls) with a single
  batched call evaluating all AI-prompt rules at once. On a 6-rule
  default project this drops safe-content cost from 5-12s to ~1-4s.
- response_format=json_object + max_completion_tokens=4000 so the model
  emits strict JSON and stops at the close-brace.
- OPENAI_REASONING_EFFORT config: minimal/low/medium/high for gpt-5 /
  o-series; accepts "none" on gpt-5.4. Works around the gpt-5-nano case
  where reasoning tokens ate the full output budget and returned empty
  responses.

Client errors
- Malformed / non-UTF-8 JSON bodies now return 400 with a clear message
  about UTF-8 encoding instead of a generic 500.

Logging
- Single INFO line per moderation: the existing
  "Content <id>: decision in Zs" summary.
- Per-stage timing, websocket scheduling, and batched-AI call details
  moved to DEBUG so they are available when diagnosing latency without
  cluttering steady-state logs.
2026-04-21 16:01:18 +01:00
Bentlybro 8953dccc21 Update run.py 2025-09-29 11:18:15 +01:00
Bentlybro 3f008c0031 Revert "Switch to Gunicorn for production deployment"
This reverts commit 8f08dd39a3.
2025-09-29 11:16:40 +01:00
Bentlybro 8f08dd39a3 Switch to Gunicorn for production deployment
Updated Dockerfile to use Gunicorn with eventlet for production server. Added gunicorn and eventlet to requirements.txt. Modified run.py to use debug mode for local development only, separating production and development server configurations.
2025-09-29 10:46:35 +01:00
Bentlybro 35986bcd68 Update unsafe Werkzeug logic for deployment
Refines the condition for allowing unsafe Werkzeug by checking for production environment via FLASK_CONFIG and CI variable, improving deployment safety and compatibility with Cloud Run.
2025-09-25 14:16:41 +01:00
Bentlybro 57165d1300 Enable unsafe Werkzeug for CI/testing environments
Adds the CI environment variable to the e2e-test workflow and updates run.py to allow unsafe Werkzeug when running in testing or CI environments. This change ensures compatibility with automated test setups.
2025-09-15 14:55:54 +01:00
Bentlybro b96037ae69 Refactor analytics logic to database service
Moved analytics and statistics queries from route handlers to new async methods in DatabaseService for admin, API, and project analytics. Updated routes to use these service methods, improving separation of concerns and maintainability. Added type annotations and minor code cleanups across several modules.
2025-09-15 11:57:43 +01:00
Bentlybro c78017eb3d autopep8 + flake8 + isort
Reorganized imports and formatting across models and routes for better readability and maintainability. Improved consistency in model field definitions, relationship declarations, and route logic. No functional changes, but code is now easier to follow and modify.
2025-08-20 16:19:26 +01:00
Bentlybro 7a8a0bec77 Refactor AI moderation for model config and performance
Updated AI moderation pipeline to support configurable OpenAI model, context window, and output tokens via environment variables. Improved chunking logic for large content, streamlined prompt templates, and enhanced connection pooling for OpenAI client. Reduced logging verbosity in core services and added retry logic for database initialization. Updated documentation to reflect new architecture and configuration options.
2025-08-13 16:41:49 +01:00
Bentlybro 01c2814a5b Enhance database config and logging, add Jinja2 filter
Added USE_DIRECT_POSTGRES config to support direct PostgreSQL connections and updated requirements with supabase and psycopg2-binary. Refactored app initialization to improve database setup, admin user creation, and added a custom Jinja2 filter for object-to-dict conversion. Improved logging configuration in run.py to reduce noise from Flask and SocketIO.
2025-07-29 19:39:06 +01:00
Bentlybro 635805353d Initial code! 2025-07-29 12:52:14 +01:00