An academic exchange platform for researchers, educators, and students working on AI in language learning and literacy. Built as a full-stack async application with Vue 3, FastAPI, PostgreSQL, and Redis.
Security-focused architecture. Dual-layer authentication validates both JWT signature and token revocation state (stored in Redis), ensuring immediate logout effect. Additional measures include Argon2id password hashing, CAPTCHA on login/registration, CSRF double-submit cookies, Nginx IP-level rate limiting, and per-endpoint atomic rate counters. File uploads validate magic bytes before storage, and PDF files pass through pikepdf to remove embedded scripts and auto-actions.
Structured backend with clear separation of concerns.
All SQL resides in app/repositories/, with services handling business logic, endpoints handling routing, and converters handling type mapping. An in-process async event bus (with Redis persistence) decouples side-effects like notifications and audit logging from the service calls that trigger them, preventing response blocking.
Real-time updates with multi-worker support. WebSocket connections use ticket-based authentication (30-second TTL, single-use) to avoid mixing session cookies with the WebSocket upgrade. Server-to-client push leverages Redis Pub/Sub for fan-out across multiple Uvicorn workers without requiring sticky sessions.
Comprehensive test coverage. 3,750+ backend unit tests with fully mocked asyncpg and Redis (no running database required), plus integration tests against the real database layer. 3,000+ frontend Vitest tests across 175+ files. All suites run in CI on every pull request.
Production-oriented infrastructure. Docker Compose setup, Nginx TLS termination, automatic Alembic migrations on startup, Celery workers with memory-leak guards, Redis with eviction policy, and support for PostgreSQL backups, certificate renewal, GDPR compliance, and optional monitoring (Datadog/Sentry).
- Rich-text editor (TipTap 3) with tables, inline images, and file attachments
- Full-text search with
websearch_to_tsquery— handles special characters, AND/OR logic, and date range filtering - Versioned post edits with full history viewer
- Threaded comments and per-comment emoji reactions
- Member post reporting with admin moderation queue
- Post co-authors for collaborative research
- Member-created groups with sub-admin delegation
- Per-SIG discussion feed and form management
- SIG-scoped member roster with role promotion
- Friends — send/accept/reject friend requests, unfriend
- Follow/Unfollow — follow other members to see their activity
- Block list — block users from interacting with you
- Friend recommendations — discover members with shared interests
- Albums/Galleries — organize and share research materials, images, and multimedia
- Citations & References — cite posts and track cited-by/citing backlinks between related content
- Recommendations — content suggestions based on member interests
- Q&A — question posts support upvote/downvote voting on answers and author-marked best answer highlighting
- Seven field types: text, textarea, single_choice, multiple_choice, dropdown, rating, file_upload
- Forms lock after first response (no silent schema changes mid-collection)
- Response viewer and async CSV export via Celery task
- Auto-save draft functionality to prevent data loss
- Customizable member profiles with avatars and bio
- Organization chart showing SIG structure and member roles
- Public user profiles displaying member posts
- Platform statistics dashboard with real-time metrics
- User management: ban/unban with forced session termination, bulk role change, GDPR anonymization
- Membership application review (GUEST → MEMBER promotion flow)
- Invite code lifecycle: per-member generation, soft revoke, hard delete, full audit trail
- Paginated audit log (Super Admin only): tracks LOGIN, LOGOUT, ROLE_CHANGE, BAN, INVITE_CODE_REVOKE, and more
- File audit and content moderation tools
- Site Settings: Super Admin can update the About page intro photo and bio text via an admin panel (
/admin/site-settings)
- VirusTotal async file scanning with scan-status polling endpoint
- Magic-byte MIME type validation before any write to object storage
- PDF sanitization via pikepdf (C++ qpdf engine): strips JS, auto-actions, macros
- GDPR Right to Erasure: deletion anonymizes PII, preserves referential integrity
- Privacy consent recorded per session (database for members, Redis for guests)
- Dual-layer rate limiting: Nginx IP zones + Redis atomic counters per endpoint
- Password policy: minimum 8 characters, requires uppercase, lowercase, digit, and special character
- WebSocket push: comments, reactions, mentions, and server-initiated force-logout
- Ticket-based WebSocket auth (one-time ticket, 30-second TTL)
- Redis Pub/Sub fan-out across multiple Uvicorn workers
- Unread notification badge and notification history
- 1-on-1 private messaging between members
- Message attachments (files) with 10MB per-message limit
- Edit and recall functionality (12-hour window)
- Read receipts for each message
- Conversation history with 50K character retention limit
- Automatic cleanup: files expire after 3 days, text after 7 days
- Respects user preferences: optional friends-only mode
Celery workers process on-demand tasks (VirusTotal scanning, CSV export, thumbnail generation, site data export). Celery Beat runs 15 scheduled operations:
- retry_failed_events — replay event bus failures (every 5 min)
- sync_guest_counter — reconcile guest session count (every 5 min)
- auto_close_expired_forms — close forms past deadline (every 5 min)
- reconcile_counters — fix post/comment counters (every 6 hours)
- cleanup_dm_expired_files — remove DM attachments past 3 days (hourly)
- cleanup_dm_expired_text — remove DM text past 7 days (hourly)
- compute_friend_recommendations — refresh recommendation scores (daily)
- cleanup_old_file_scans — purge stale VirusTotal scan records (daily)
- cleanup_old_audit_logs — archive old audit entries (daily)
- cleanup_dm_orphan_files — remove DM files in MinIO with no DB record (daily)
- cleanup_old_site_exports — delete expired site export archives (daily)
- cleanup_orphan_files — remove MinIO objects with no DB reference (weekly)
- cleanup_old_read_notifications — prune read notifications (weekly)
- cleanup_dm_orphan_quotas — release storage quota for phantom DM uploads (weekly)
- cleanup_empty_dm_conversations — remove conversations with no messages (weekly)
- Interface available in 17 languages via vue-i18n
- User language preference stored per account (
preferred_languagefield) - Locale selector available in the user profile
For a detailed system architecture — C4 diagrams, layered module maps, ER model, Redis topology, sequence diagrams for key request lifecycles, and the production deployment view — see
docs/architecture.md.
Browser
|
| :3000 (HTTP) / :3443 (HTTPS)
v
Nginx (reverse proxy · TLS termination · IP rate limiting)
|-- /api/v1/ws --> FastAPI WebSocket
|-- /api/ --> FastAPI HTTP :8000
`-- / --> Vue 3 SPA (static build)
|
v
FastAPI :8000
|-- asyncpg --> PostgreSQL :5432
|-- redis.asyncio --> Redis :6379
|-- boto3 --> MinIO :9000
|-- Celery tasks --> Redis broker DB 1
`-- Celery results --> Redis DB 2
All services communicate on a private Docker bridge network.
Only Nginx exposes ports to the host.
HTTP Request
|
v
app/api/v1/endpoints/ Validate schema (Pydantic) · extract deps · call service
|
v
app/services/ Enforce auth · apply business rules · publish domain events
|
v
app/repositories/ All SQL via asyncpg · returns raw Records · no Pydantic
|
v
PostgreSQL
app/converters/ asyncpg Record --> Pydantic schema (called by services)
app/core/event_bus.py Async pub/sub · handlers run without blocking the response
Caching strategies:
- User avatars: In-memory LRU cache (max 50 entries, 1-hour TTL)
- Public statistics: Redis cache (
public:statskey, 300-second TTL) - WebSocket tickets: Redis key-value with 30-second TTL, single-use consumption
Pagination:
- Cursor-based pagination with
COUNT(*) OVER()for total count in a single query - Form responses: Keyset pagination (
iter_responses_batched) avoids loading entire result sets - Post history: Capped at 50 entries per query with true total via window function
Concurrency control:
- Form max_respondents: PostgreSQL advisory locks (
pg_advisory_xact_lock) serialize concurrent submissions - Guest counter: Redis Lua script ensures atomic check-and-increment
- Member invites: Transaction-level checks prevent expired code reuse
- Audit entries: Append-only, no updates or deletes
| Component | Technology |
|---|---|
| Language | Python 3.12 |
| Web framework | FastAPI + Uvicorn (uvloop) |
| Database driver | asyncpg (fully async, parameterized queries) |
| Migrations | Alembic |
| Validation | Pydantic v2 |
| Task queue | Celery + Redis |
| Password hashing | Argon2id (via passlib) |
| Token signing | PyJWT |
| Object storage | boto3 (MinIO / S3-compatible) |
| HTML sanitization | nh3 |
| PDF sanitization | pikepdf (C++ qpdf engine) |
| CAPTCHA | captcha + Pillow |
| Logging | Loguru |
| Error tracking | Sentry SDK |
| APM | ddtrace (Datadog) |
| Component | Technology |
|---|---|
| Framework | Vue 3 (Composition API) |
| Language | TypeScript |
| Build tool | Vite 6 |
| CSS | Tailwind CSS v4 |
| State management | Pinia |
| Routing | Vue Router 4 |
| Rich text editor | TipTap 3 |
| HTTP client | Axios (with CSRF interceptor) |
| HTML sanitization | DOMPurify |
| Internationalization | vue-i18n 11 (17 languages) |
| Component | Technology |
|---|---|
| Database | PostgreSQL 15 |
| Cache / queue broker | Redis 7 (allkeys-lru eviction, 256 MB cap) |
| Object storage | MinIO (S3-compatible) |
| Reverse proxy | Nginx 1.27 (TLS, rate limiting, static files) |
| Containerization | Docker Compose |
| Monitoring | Datadog Agent + Sentry (optional) |
- Docker Engine 24+ and Docker Compose v2
- 8 GB RAM recommended (all services combined)
- 2 GB disk space for database, cache, and uploads
git clone https://github.com/Isaries/AI3L-Community.git
cd AI3L-Community
cp .env.example .envEdit .env and replace all changeme_* values:
SUPER_ADMIN_USERNAME/SUPER_ADMIN_PASSWORD— your initial admin accountSECRET_KEY— FastAPI session secret (min 32 chars)JWT_SECRET_KEY— JWT signing key- Database, Redis, MinIO credentials
MINIO_PUBLIC_URL— must behttp://localhost:19000in local dev (used in presigned URLs)
docker compose up --build # first time — builds images and runs Alembic migrations
docker compose up # subsequent runsOn first startup:
- PostgreSQL auto-runs Alembic migrations (schema setup)
- Redis initializes with
allkeys-lrueviction policy - Celery Beat starts scheduled tasks (file cleanup, guest cleanup)
- Super admin account is created from
.envvalues
./scripts/init-minio.shCreates the upload bucket and applies access policies. Only needed once after the first docker compose up.
| Service | URL | Purpose |
|---|---|---|
| Web application | http://localhost:3000 | Main SPA |
| FastAPI Swagger UI | http://localhost:18000/api/docs | API documentation (requires dev override) |
| MinIO console | http://localhost:19001 | File storage management |
- Visit http://localhost:3000
- Click "Register" (or use an invite code from admin panel)
- Complete CAPTCHA and registration form
- Log in as super admin → Dashboard → approve GUEST→MEMBER promotion
Fix: Ensure .env has MINIO_PUBLIC_URL=http://localhost:19000 before starting containers.
Fix: Change Nginx ports in docker-compose.yml or kill the conflicting process.
# macOS/Linux
lsof -i :3000 # find process
kill -9 <PID>Fix: Ensure PostgreSQL container is healthy:
docker compose logs postgres
docker compose exec postgres pg_isreadyNote: Unit tests run with mocked asyncpg/Redis. Integration tests require:
cd backend
INTEGRATION_TEST=1 pytest tests/ -vFix: Clear node_modules and reinstall:
cd frontend
rm -rf node_modules package-lock.json
npm installEnsure your Docker Desktop has ≥8 GB allocated. Check individual service limits in docker-compose.yml (FastAPI: 3GB, PostgreSQL: 4GB, etc.).
# Backend — no running database required (asyncpg and Redis are fully mocked)
cd backend
pytest tests/ -v
# ~3,750 unit tests + integration tests (set INTEGRATION_TEST=1 for integration)
# Frontend
cd frontend
npx vitest run
# ~3,080 tests across 175+ filesLast updated: 2026-05-08 — auto-generated on every push to main
| Metric | Value |
|---|---|
| Total lines added (all commits) | +335,846 |
| Total lines removed (all commits) | -59,044 |
| Backend source lines (excl. tests) | 31,859 |
| Frontend source lines (excl. tests) | 67,745 |
pie title Lines of Code by Language
"Python" : 120925
"TypeScript" : 95428
"Vue" : 27280
"CSS" : 134
| Suite | Test cases | Source lines | Test lines |
|---|---|---|---|
| Backend (pytest) | 3,693 | 31,859 | 85,691 |
| Frontend (Vitest) | 3,066 | 67,745 | 54,963 |
| Total | 6,759 | 99,604 | 140,654 |
Test-to-source ratio: 1.41 (140,654 lines of tests for every 99,604 lines of source)
| Metric | Value |
|---|---|
| REST API endpoints | 205 |
| Database migrations | 57 |
| Longest commit streak | 33 days |
| File | Lines |
|---|---|
backend/app/services/album.py |
1,181 |
frontend/src/views/about/OrgChartView.vue |
958 |
frontend/src/composables/usePostDetail.ts |
907 |
backend/app/services/form.py |
900 |
frontend/src/views/forms/FormView.vue |
875 |
| Author | Commits | Lines added | Lines removed |
|---|---|---|---|
| Isaries | 584 | +331,933 | -56,083 |
| github-actions[bot] | 126 | +1,397 | -1,396 |
| SW9526 | 29 | +6,191 | -2,058 |
| dependabot[bot] | 2 | +73 | -6 |
| AI3L Community | 2 | +240 | -150 |
| Document | Purpose |
|---|---|
docs/architecture.md |
Full system architecture with C4 diagrams, layered backend/frontend maps, ER model, Redis topology, request lifecycles, and deployment view (Mermaid) |
docs/security.md |
Security architecture, threat model, controls, and design rationale |
docs/authentication.md |
Session flow, token TTLs, CSRF, guest sessions, password policy |
docs/api-reference.md |
Complete REST and WebSocket API listing with auth requirements |
docs/environment.md |
All environment variable definitions, database config, cache settings |
docs/deployment.md |
Production deployment: TLS, Nginx, migrations, backups, production checklist |
docs/websocket.md |
WebSocket protocol: ticket auth, heartbeat, server message types |
docs/system-specification.md |
Full system design, data model, ERD, and feature specification |
| Document | Purpose |
|---|---|
backend/README.md |
Backend architecture, layer guide, repository patterns, testing |
frontend/README.md |
Frontend architecture, component library, composables, styling |
CONTRIBUTOR_ONBOARDING.md |
Git setup, branch workflow, PR process, development environment |
BACKEND_CONTRIBUTOR_GUIDE.md |
Backend open tasks with difficulty ratings and implementation guides |
FRONTEND_CONTRIBUTOR_GUIDE.md |
Frontend open tasks with difficulty ratings and implementation guides |
| Document | Purpose |
|---|---|
docs/audit/security-audit-2026-03-16.md |
21 security findings and fixes |
docs/audit/system-bugs-2026-03-16.md |
15 system bugs fixed with test coverage |
docs/audit/uiux-audit-2026-03-16.md |
55 UI/UX improvements across frontend |
docs/audit/backend-performance.md |
Performance optimization analysis and memory hardening |
docs/audit/frontend-performance.md |
Frontend performance metrics and optimization strategies |
docs/audit/database-optimization.md |
Database query optimization and indexing analysis |
All contributions go through pull requests targeting the backend or frontend integration branch — never directly to main. See CONTRIBUTOR_ONBOARDING.md for the full workflow.
Commit messages follow Conventional Commits: feat:, fix:, refactor:, test:, docs:, chore:.
- New feature? Start from the relevant
*_CONTRIBUTOR_GUIDE.mdto understand complexity, scope, and implementation order - Bug fix? Verify the bug exists with a test, then fix the root cause (not just the symptom)
- Performance issue? Profile first — check the audit reports in
docs/audit/for known bottlenecks - Security concern? Report privately; do not create a public issue
- Setup issues? Check the Troubleshooting section above
- Architecture questions? Read
docs/system-specification.mdandbackend/README.md - API usage? See
docs/api-reference.mdor visit http://localhost:18000/api/docs (Swagger UI, dev override) - Development patterns? Check the relevant contributor guide for code style, file structure, and testing conventions
- Want to contribute? Start with
CONTRIBUTOR_ONBOARDING.mdand pick a task from the contributor guides
All core features are implemented and tested. The platform is in production hardening phase — ongoing work focuses on performance optimization, security audits, and UI/UX polish.
See the Project Stats section for up-to-date metrics (auto-generated on every push to main).
Copyright (C) 2026 Isaries <leolove3very@gmail.com>
SW9526 <shaniawang06@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
This project is licensed under the GNU Affero General Public License v3.0 ??see the LICENSE file for the full text.
- You may use, study, modify, and redistribute this software freely.
- You must release your modifications under the same AGPL-3.0 license.
- If you run a modified version as a network service (e.g. host it as SaaS), you must make the complete source code of your modified version available to its users. This is the key difference between AGPL and GPL.
By submitting a pull request, you agree that your contribution will be licensed under the AGPL-3.0. For substantial contributions, the maintainers may ask you to sign a Contributor License Agreement (CLA) to preserve the project's flexibility for future dual-licensing.
