Athar (أثر) is an open-source, self-hosted knowledge management system for student engineering teams and technical organizations. It connects projects, components, standard operating procedures (SOPs), engineering failures, tests, and lessons learned in one searchable knowledge base, helping teams preserve institutional knowledge as members graduate or leave.
Developed by Lycans AeroDesign, Athar began as a knowledge management solution for a university AeroDesign team and is designed to support other engineering teams as well.
Don't want to manage your own deployment?
We are exploring a managed hosting option for teams that want to use Athar without maintaining their own infrastructure. Hosting would be provided by Lycans AeroDesign and may be offered through a subscription-based plan.If your team would be interested in a hosted Athar instance, contact Lycans and let us know. Your interest will help us determine whether there is enough demand to launch a shared hosted service for teams.
Self-hosting will always remain available — you can deploy your own independent instance, own your data, and manage your infrastructure yourself.
Student engineering teams accumulate a huge amount of knowledge — designs, failures, SOPs, flight history, decisions, lessons learned — that mostly lives in people's heads and disappears when they graduate. Athar exists so a new member can search the system and understand not just what the team does, but why.
athar (أثر)
/ˈæ.θɑːr/— Arabic: a trace, mark, or remnant left behind by something that has passed.
The name reflects that purpose — the system exists to preserve the trace a team's work and decisions leave behind, so that knowledge outlives the people who created it.
The full product specification (vision, feature areas, roles/permissions, roadmap) lives in docs/VISION.md. Three principles sit above everything else in it:
- Self-hosted-first, multi-tenant-capable — a team can still clone/deploy their own fully independent instance and own their data outright, same as always; the backend is also genuinely multi-tenant now (an
Organizationmodel, every row scoped to it, self-service org creation alongside invite-based joining), so one deployment can serve several isolated organizations instead of exactly one. Seedocs/VISION.md§2 for the fuller status note on this. - Connected knowledge — knowledge objects (articles, components, projects, failures, SOPs, tests, documents, decisions...) link to each other so context is discoverable, not siloed.
- Backend-enforced authorization — the frontend is never a security boundary; every API request is authorized server-side, regardless of client.
General-purpose documentation tools can store engineering knowledge, but Athar is designed to connect that knowledge to the work itself.
- Connected engineering records: Link projects, components, failures, SOPs, tests, and lessons learned so information retains its context.
- Knowledge preservation: Keep engineering decisions and lessons accessible beyond the students who originally documented them.
- Training and onboarding: Turn existing team knowledge into structured courses and learning paths for new members.
- Self-hosted and open source: Deploy your own instance, control your infrastructure, and retain ownership of your team's data.
- Built for engineering teams: Combine documentation with structured engineering records rather than relying exclusively on pages and folders.
Athar is a set of modules that build on each other — Knowledge is the foundation everything else links back to; Training turns that knowledge into something new members can actually learn from; the platform pieces (RBAC, search, backups, i18n) exist so the other two are trustworthy and usable day to day.
- Knowledge — articles, Q&A, categories/tags (including a dedicated "everything tagged X" browse page, not just a search-box filter), attachments, and cross-linking between any two items, with a full draft → review → publish workflow and revision history. Use it for anything written down for other people to read: write-ups, decisions, answers to recurring questions. This is the wiki that stops answers from living only in someone's head or a lost chat thread.
- Engineering domain (Projects, Components, Failures, SOPs, Tests/experiments, Documents) — structured records for the practical side of the work: what you're building, the parts in it, what broke and why, the procedures you follow, and the tests that proved something worked. Use it instead of scattered spreadsheets/PDFs so a project's failures, tests, and procedures stay linked to each other and to the components involved, not just filed away separately. Components double as the workshop inventory — grid location, quantity and unit, condition, and a stock status that follows the quantity (In Stock / Low Stock / Missing, plus On Order and Retired), with a live summary and a "needs ordering" view — and sync both ways with an inventory spreadsheet through CSV import/export (matched by an Athar ID column, with a preview before anything changes).
- Training Center — structured courses (Course → Module → Lesson), with text/video/document/external-link/exercise lesson types, enrollment, per-lesson completion tracking, and lessons that reference existing Knowledge content instead of duplicating it. Use it to turn "what the team knows" into "how a new member learns it" — an actual onboarding path instead of relying on ad hoc mentorship.
- RBAC & multi-tenancy — five seeded roles (Guest, Member, Mentor, Subteam Head, Organization Admin), enforced on every API request server-side, plus full per-organization data isolation. Use it to trust that permissions are real access control, not just hidden buttons in the UI — and to safely host more than one team's data in a single deployment if you need to.
- Search — Postgres full-text search (ranked) with a trigram-similarity fallback for typos/partial matches, across every content type. A knowledge base only pays off if people can actually find what's already in it.
- Contribution scoring & activity feed — a weighted leaderboard (monthly/yearly/lifetime standings) and a live feed of publish/answer/review events. Use it to give visible credit for maintaining the knowledge base, which is otherwise thankless, unrewarded work.
- Backups — an org-scoped in-app export/restore (Settings > Backups) for admins, plus a whole-instance CLI backup for self-hosters. See Backups below.
- Internationalization — the full UI in English and Arabic (with RTL layout), not just the content. Use it if your team doesn't operate primarily in English.
| Backend | Django 6.1, Django REST Framework, drf-spectacular (OpenAPI), uv, Python 3.14 |
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS v4, a small custom Radix/cmdk-based UI kit (frontend/components/ui/) |
| Database | PostgreSQL 18 (via Docker), no SQLite fallback; search uses Postgres full-text search (SearchVector/SearchRank) with a trigram-similarity fallback for substring/typo matches, ranked by relevance |
| Background work | Redis + Celery (org-scoped backup export/restore - see Backups below - plus an hourly cleanup of uploads that were never attached to anything) |
| File storage | Local filesystem by default; set AWS_STORAGE_BUCKET_NAME to switch to any S3-compatible object storage instead (AWS S3, Cloudflare R2, Backblaze B2, self-hosted MinIO, ...) — see backend/.env.example |
| Deployment | Docker, Docker Compose, nginx reverse proxy in front of both the API and the frontend (rate limiting, security headers, health check, real HTTPS via Let's Encrypt/certbot in production - see nginx/templates/ and DEPLOYMENT.md) |
| CI/CD | GitHub Actions (backend + frontend CI, PR checks, manual release/publish) |
| Testing | Backend: DRF APITestCase suite (backend/*/tests.py), run via manage.py test |
git clone https://github.com/Lycans-AeroDesign/Athar.git
cd Athar
python scripts/generate_env.py # generates .env / backend/.env / frontend/.env with real secrets
docker compose up- Frontend: http://localhost:3000
- Backend: http://localhost:8000
- Nginx (reverse proxy in front of both the backend and frontend - see
nginx/templates/): http://localhost:80
For a production-shaped stack (gunicorn, standalone Next.js server, no bind mounts), pulling prebuilt images published by CI rather than building locally:
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -ddocker-compose.prod.yml requires SECRET_KEY, ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS, and DOMAIN to be set explicitly (no dev fallbacks). See DEPLOYMENT.md for the full checklist of what to change when deploying to a real server.
Backend (from backend/):
Requires a running Postgres instance and DATABASE_URL set in backend/.env (copy from backend/.env.example) - there is no SQLite fallback.
uv sync # install dependencies into .venv
uv run manage.py migrate # apply migrations
uv run manage.py runserver # start dev serverFrontend (from frontend/):
npm install
npm run dev # start dev server (Turbopack) at http://localhost:3000Copy backend/.env.example → backend/.env and frontend/.env.example → frontend/.env first (or run python scripts/generate_env.py).
backend/ Django project (config/, manage.py, pyproject.toml)
frontend/ Next.js app (app/, package.json)
nginx/templates/ reverse proxy config templates (dev vs. prod+HTTPS), see DEPLOYMENT.md
scripts/init_letsencrypt.sh one-time HTTPS bootstrap for a fresh deploy
DEPLOYMENT.md checklist for deploying to a real server
docker-compose.yml dev stack (hot reload, Postgres, nginx)
docker-compose.prod.yml prod-shaped stack (gunicorn, standalone Next.js, nginx)
scripts/generate_env.py generates local .env files with real secrets
docs/VISION.md full product specification
.github/ CI, PR automation, issue/PR templates
The frontend is fully translation-driven (next-intl) — no UI text is hardcoded, it all comes from frontend/i18n/messages/<locale>.json. Routes are locale-prefixed (/en/..., /ar/...).
Supported languages:
| Code | Language | Direction | Status |
|---|---|---|---|
en |
English | LTR | ✅ Fully supported (source language) |
ar |
العربية (Arabic) | RTL | ✅ Fully supported — frontend/i18n/messages/ar.json is kept in parallel with every key in en.json, genuinely translated (not a copy) |
A language only reaches "file exists" status once it's registered in frontend/i18n/request.ts (see below) and has a messages/<code>.json file — at that point it's selectable in Settings > General even before translation is complete, since next-intl has no per-key fallback. Update this table whenever a language's status changes.
To add a new language:
- Add its code to
localesinfrontend/i18n/request.ts. - Give it a display name (
localeNames) and text direction (localeDirections), also infrontend/i18n/request.ts. - Copy
frontend/i18n/messages/en.jsontofrontend/i18n/messages/<code>.jsonand translate the values (keep the same keys).
The language picker in Settings > General is generated from locales/localeNames, so the new language appears there automatically once its message file exists.
Two independent backup-and-restore paths, at two different scopes:
- An organization's own data (Settings > Backups, requires
organization.manage) — exports everything that organization owns as a downloadable, encrypted.atharfile (inside: amanifest.json, a CSV per table, plus the actual uploaded files): members, roles and role assignments, invitation codes, settings and branding, policies and acceptances, all knowledge/engineering/training content, attachments, and the audit log. Runs as a background Celery job so triggering it never ties up a request, however large the export -docker compose upalready starts theredisandcelery-workerservices needed for this, no extra setup step. The same page can restore from one of the organization's stored backups, or from an uploaded.atharfile (for example onto a fresh server after losing the old one). A restore is a full wipe-and-replace of the organization with original IDs and timestamps preserved. Members are matched by ID, then by email, and updated in place; anyone missing from the backup is deactivated rather than deleted; and the admin running the restore always keeps their account and admin access. Archives include members' password hashes (so everyone logs in as before after a restore), so they're always encrypted (AES-256-GCM, seebackend/core/crypto.py). Archives kept on the server are encrypted with a server key (BACKUP_ENCRYPTION_KEY, or derived fromSECRET_KEYwhen unset), and every download is encrypted with a passphrase the admin picks at download time. A downloaded file can be restored on any server with just that passphrase. Nothing else has to be copied across, and a lost passphrase can't be recovered. Plaintext.zipbackups downloaded before encryption existed can still be uploaded and restored. Uploaded archives are treated as untrusted: nothing in one can reference another organization's data, and a backup of a different organization that still exists on the server is rejected. Uploaded archives are capped at 5 GB, both in Django (BACKUP_UPLOAD_MAX_SIZE_MB) and in nginx for that one route (nginx/templates/locations.inc.template); raise both together if an organization outgrows it. - The whole instance (every organization) — a real
pg_dumpof the entire database plus a tarball of the local media directory (skipped if file storage is S3-compatible - see the Tech stack table above), written tobackend/backup_archives/. Deliberately CLI-only, not a web feature:is_superuseris break-glass/CLI-only everywhere else in this app, and Django admin itself isn't even registered outsideDEBUG(seebackend/config/urls.py), so there's no web-exposed "download/restore every organization's data" surface to get wrong. Restoring is a full wipe-and-replace of the entire database viapg_restore --clean --if-exists, gated behind an explicit--yesflag. Both files are encrypted with a passphrase. It's read from--passphrase-file, otherwise from theBACKUP_PASSPHRASEenvironment variable (for cron), otherwise prompted for. The database dump is encrypted aspg_dumpwrites it, so a plaintext dump never touches disk.
docker compose exec backend python manage.py create_full_backup
docker compose exec backend python manage.py restore_full_backup backup_archives/athar-db-<timestamp>.dump.enc --media-archive-path backup_archives/athar-media-<timestamp>.tar.gz.enc --yes- On the old server, go to Settings > Backups, create a backup, and download it with a passphrase. Keep that passphrase in a password manager.
- Set up the new server (see
DEPLOYMENT.md) and create an admin account there. - On the new server, go to Settings > Backups > Restore from File, pick the
.atharfile, and enter the passphrase.
For a whole-instance move, copy the .dump.enc and .tar.gz.enc files instead and run restore_full_backup with the same passphrase.
See CONTRIBUTING.md for commit conventions, backend/frontend conventions, and the PR checklist.
See SECURITY.md to report a vulnerability.
Apache License 2.0 © 2026 Lycans AeroDesign Team.
