This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is rDrama, a Reddit-like discussion forum application built with Flask and SQLAlchemy. The application consists of a Python backend with a React-based chat component.
- Backend: Python, Flask, SQLAlchemy, Redis, PostgreSQL
- Frontend: Jinja2 templates, vanilla JavaScript, React (chat component only)
- Package Management: Poetry (Python), Yarn (JavaScript/chat)
- Database: PostgreSQL with Alembic migrations
# Install dependencies
poetry install
# Run tests
./util/test.py
# Run database migrations
python3 -m flask db upgrade
# Run flask commands
python3 -m flask [command]
# OR
./util/command_flask.py [command]files/__main__.py- Main Flask application setup, configures services (THEMOTTE vs CHAT), database connections, Redis cache, rate limiting
-
files/routes/- HTTP route handlers organized by feature areaallroutes.py- Request/response handlers shared across services- Major route modules:
posts.py,comments.py,login.py,front.py,search.py admin/- Administrative functionality routes
-
files/classes/- SQLAlchemy ORM models- Key models:
User,Submission(posts),Comment - Warning: Uses wildcard imports internally - be careful with dependencies
- Key models:
-
files/helpers/- Utility functions and configurationsconfig/- Configuration constants and environment variables
-
files/templates/- Jinja2 templates for server-side rendering -
files/assets/- Static assets (CSS, JS, images) -
chat/- Separate React application for real-time chat functionality
- Migrations in
migrations/directory managed by Alembic - PostgreSQL database with extensive use of SQLAlchemy ORM
- Redis for caching and rate limiting
The application can run in different service modes (defined in files/helpers/config/const.py):
THEMOTTE- Main forum functionalityCHAT- Chat service only
-
Imports: Many files use wildcard imports (
from files.classes import *). Be careful when modifying imports as it can break unrelated parts of the codebase. -
Database Sessions: Uses SQLAlchemy scoped sessions (
db_session) configured in__main__.py -
Authentication: Session-based authentication with Redis backing
-
Rate Limiting: Configured via Flask-Limiter with Redis storage
-
Templates: Server-side rendering with Jinja2, client-side JavaScript for interactivity
Tests are located in files/tests/ and use pytest. Run all tests with:
./util/test.pyKey test fixtures are defined in files/tests/fixture_*.py files.
-
SQLAlchemy Session Expiration: After making HTTP requests in tests, database objects become detached from the session. To verify database changes after an HTTP request, re-query the object using
db_session.query(Model).get(id)ordb_session.query(Model).filter_by(...).first()instead of usingdb_session.refresh(obj).# ❌ WRONG - object is detached after HTTP request response, _ = util.post_with_formkey(client, f"/delete/comment/{comment.id}", data={}) db_session.refresh(comment) # This will fail with InvalidRequestError # ✅ CORRECT - re-query the object response, _ = util.post_with_formkey(client, f"/delete/comment/{comment.id}", data={}) comment_after = db_session.query(Comment).get(comment.id) assert comment_after.state_user_deleted_utc is not None
-
CSRF Protection (formkey): All POST requests in the application require a CSRF token called
formkey. In tests, useutil.post_with_formkey()helper function instead ofclient.post()directly:# ❌ WRONG - missing formkey, will return 302 redirect response = client.post("/delete/comment/123", data={}) # ✅ CORRECT - automatically fetches and includes formkey response, _ = util.post_with_formkey(client, "/delete/comment/123", data={})
The
post_with_formkey()helper automatically fetches a page (typically/submit) to extract the session's formkey, then includes it in the POST request data.
The application uses environment variables for configuration. These can be set in:
bootstrap/site_env- Site-specific configuration.env- Local overrides (takes precedence)
Key environment variables include:
SITE_ID- Site identifierDATABASE_URL- PostgreSQL connection stringCACHE_REDIS_URL- Redis connection stringSECRET_KEY- Flask secret keyENFORCE_PRODUCTION- Set to false for development