Files
MathApp/CLAUDE.md

4.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

Django + DRF backend for Tadrisino, an educational app (Persian/Farsi). Codebase and API responses are in Persian; comments in source are Persian too.

Commands

source venv/bin/activate
python manage.py runserver
python manage.py migrate
python manage.py test                 # all tests
python manage.py test accounts        # single app
python manage.py test accounts.tests.SomeTestCase.test_something  # single test

Local dev requires DJANGO_DEBUG=1 (enables Swagger auth via DEV_MASTER_OTP/devOtp in responses). DEBUG defaults to False. Production also requires DJANGO_SECRET_KEY, DJANGO_ALLOWED_HOSTS (comma-separated), and CACHE_URL (Redis — required whenever DEBUG=False since rate limiting needs a shared cache; raises ImproperlyConfigured otherwise).

No pytest; uses Django's built-in test runner. No linter/formatter configured.

Docker (docker compose up --build) adds a local Loki+Grafana Alloy+Grafana log stack; not a production setup (still runserver, not gunicorn). See comments in docker-compose.yml, docker/alloy/config.alloy, and LOG_DIR in config/settings.py.

API docs: Swagger /api/docs/, Redoc /api/redoc/, admin /admin/.

Architecture

Apps (each owns its own models, one responsibility):

app responsibility key models
accounts identity, sessions, OTP auth User, Profile, Session, OTPCode
content lessons/curriculum Grade, Unit, Node, Lesson, Question, Choice, NodeProgress
progress stats, leaderboard, streaks UserStats, LeaderboardEntry, StreakRecord, UserHearts
ai_tutor AI assistant chat Conversation, Message, MessageFeedback
subscription plans Plan, Subscription
payment orders/transactions (incl. Cafe Bazaar IAP) Order, Transaction
discount discount codes/offers DiscountCode, Redemption, Offer, UserOffer
notifications notifications Notification
affiliate referral program AffiliateAccount, Conversion
support tickets/bug reports BugReport, Ticket, TicketMessage
family parental control FamilyLink, ParentalSettings, WeeklyReportLog
statuslog generic cross-app status-change log StatusChangeLog
campaigns messaging campaign storage only, no send logic yet MessageCampaign
config project settings, root urls, middleware —

Auth is custom, not Django's. accounts.User is deliberately not AUTH_USER_MODEL — it's an independent business model. Auth is a stateless signed bearer token (django.core.signing, no JWT library) issued/verified in accounts/authentication.py (TadrisinoTokenAuthentication, header Authorization: Bearer <token>), backed by accounts.Session. Missing/invalid header → anonymous request, not a hard failure; each view's permission class decides if auth is required.

Apps are decoupled by convention: instead of real FKs across app boundaries, code uses loose refs (user_id, object_id + label) so any app can be split out later. Don't add cross-app FKs — follow the existing loose-reference pattern.

Throttling: DRF ScopedRateThrottle with per-endpoint throttle_scope strings, rates centralized in REST_FRAMEWORK['DEFAULT_THROTTLE_RATES'] in config/settings.py. Guest users are throttled by IP (NUM_PROXIES setting controls how many XFF hops are trusted — must match real proxy count in prod or IP spoofing/throttle-bypass is possible). Adding a new sensitive endpoint means adding both a throttle_scope on the view and a matching rate entry in settings.

POST /api/ai/ask currently returns a stub; real model integration point is generate_tutor_answer in ai_tutor/views.py.

Structured logging: config.middleware.APIRequestLoggingMiddleware (last in MIDDLEWARE, closest to the view) logs every /api/ request as JSON (method/path/status/duration/user, no body/headers/secrets) via config/log_formatters.py.

SQLite is current DB (OPTIONS.timeout=20 to tolerate concurrent-write locks, e.g. campaigns tests); README notes Postgres migration is still pending.

SMS goes through Kavenegar (KAVENEGAR_API_KEY/KAVENEGAR_SENDER); failures return explicit 503, not a fake success.

Known gaps (per README pre-deploy checklist)

  • Still on SQLite, not Postgres.
  • Throttle rates need periodic review against real traffic.
  • DEV_MASTER_OTP (0000) must stay gated behind DEBUG — never enabled in prod.