Doctrine ship-fit compliance with module substitutions for Alliance Auth
Project description
Fit Check (aa-fitcheck)
Doctrine ship-fit compliance for Alliance Auth, with module substitutions as a first-class concept.
The engine knows every EVE module's variant family (the data behind Pyfa's right-click
"Variations" menu) and grades each substitution against the policy your fitting team sets.
A doctrine that requires a Heat Sink II can still pass when the pilot fits an Imperial Navy
Heat Sink — because the engine knows both modules belong to the same family and your policy
allows it. Mutated/abyssal modules are compared attribute-by-attribute using EVE's own
highIsGood semantics. No existing Alliance Auth plugin does this level of fit verification.
Major Features
Substitution Engine
Three substitution policies per module slot, assigned with bipartite matching so overlapping candidate sets are never mis-allocated:
| Policy | Description |
|---|---|
| Strict (exact) | Only the listed module passes. |
| Standard (variant family) | Any module in the SDE variant family, filtered by allowed meta groups (e.g. "Tech II or Faction only"). |
| Flexible (meet-or-beat) | Any module — including mutated/abyssal — whose EVE attributes meet or exceed the doctrine baseline in every required dimension. |
Explicit overrides (include/exclude) per slot let admins allow specific cross-family swaps or ban specific modules regardless of the general policy.
Abyssal / Mutated Module Support
Abyssal modules are handled transparently across all intake paths:
- Pyfa EFT export — mutation blocks parsed automatically from the extended EFT format.
- Manual entry — a guided stats form, flagged Self-reported to reviewers.
- ESI-verified — rolled attribute values fetched from the pilot's actual in-game assets
via the public dynamic-items endpoint, matched per asset
item_id.
Per-attribute pass/fail tables appear inline in the compliance verdict. Admins can set minimum- attribute windows per module (e.g. "propmod must roll at least 120% signature radius bonus") via an abyssal-bounds modal with dual-handle range sliders.
Per-Doctrine Policy Snapshots
A fit can belong to several doctrines, each with its own independent policy rules:
- Attaching a fit to a doctrine clones its item policies into a snapshot owned by that assignment.
- Editing one doctrine's policy never affects another's or the source fit's defaults.
- A full override + abyssal-attribute editor is available per (doctrine, fit) assignment, directly from the fit page.
ESI Integration
| Capability | ESI Scope |
|---|---|
| Pilot inventory validation + Frigate Escape Bay content | esi-assets.read_assets.v1 |
| Structure names + location (system / region) | esi-universe.read_structures.v1 |
| Implant verification | esi-clones.read_implants.v1 |
| Saved-fittings intake (import fits saved in EVE) | esi-fittings.read_fittings.v1 |
| Save-to-EVE (push a fit into the in-game Fittings panel) | esi-fittings.write_fittings.v1 |
| Mutated/abyssal roll verification | Public dynamic-items endpoint (unauthenticated) |
Enable all five scopes on your EVE application at developers.eveonline.com/applications — the same app whose Client ID/Secret Auth uses for SSO. A scope that isn't enabled on the application fails with
invalid_scopeat login. Pilots then grant the scopes per feature via SSO (assets + structures are bundled into one grant; implants and saved-fittings are granted on demand); structure names additionally require the character to have docking access.
Pilots validate their ships directly from their hangar without pasting any text. ESI-sourced
submissions carry the real asset item_id so the engine always re-pulls current data on re-check.
Proactive Member Fit Checks
Fleet leadership can scan hangars before a fleet forms rather than waiting for pilots to submit:
- Alliance-wide: see every member's ships alongside per-ship compliance verdicts.
- Corp-scoped: corps-only leaders see only their own corporation.
- Two permission levels keep scanning rights granular without custom roles.
Category-Driven Visibility & Group Gating
DoctrineCategory controls access to both doctrines and fits:
- Selected-OR groups: pilot qualifies if they hold any one of the selected groups.
- Required-AND groups: pilot must hold every required group simultaneously.
- Both conditions combine with OR; items with no categories are public.
- Managers and reviewers bypass all category gates.
Categories carry a custom color for visual identification and appear as filterable chips on the Doctrines tab.
colcrunch fittings Integration
If your alliance already uses colcrunch fittings:
- One-click import of existing doctrine and fit libraries (doctrines, fits, BOMs).
- On-demand "Pull updates" re-syncs BOMs when the fittings team publishes changes, while preserving every compliance policy and override.
fittingsis a soft dependency: all code paths no-op cleanly when it is not installed.
Review Workflow
- Filterable review queue (by pilot, doctrine, verdict, status).
- Approve (comment optional) or reject (comment required — pilot sees exactly what to fix).
- Stale badges flag submissions graded against an outdated fit version.
- Full audit log per submission with actor, action, and comment.
- AA notifications on decision (immediate or periodic digest); Discord delivery is automatic via
aa-discordnotifywhen installed.
Additional Features
Pilot Quality-of-Life
- Copy as EFT — one-click clipboard export of the doctrine fit in EFT format.
- Copy Buy All — aggregated multibuy list (hull + all modules, charges, and bay contents, grouped and summed) ready to paste into EVE's Multibuy window.
- Save to EVE — push the doctrine fit directly into the pilot's in-game Fittings panel via SSO.
- Missing Modules — the review form generates a paste-ready deficit multibuy list of everything a pilot still needs.
Compliance Sections
Every part of a ship fit is checked independently. Slot sections match exactly (order never matters); bay and cargo sections require "at least N":
| Section | Behaviour |
|---|---|
| High / Mid / Low / Rig / Subsystem | Exact quantity, any slot order |
| Drone Bay / Fighter Bay | At least N of each type per squadron |
| Cargo | Refit spares with full substitution; implant requirements declared here |
| Implants | ESI-verified from pilot clone; required implants carried in cargo or the fleet hangar pass as a refit; unverifiable submissions warn but never auto-fail |
| Boosters | Warn-only — never a hard fail regardless of mode; boosters carried in cargo or the fleet hangar pass as a refit |
| Fuel Bay | Isotope quantity check for capitals, warn-only |
| Frigate Escape Bay | ESI-verified content; configurable enforcement mode |
Loaded charges are pooled into cargo on both sides: a doctrine specifying "4 Artillery Cannons needing 4 crystals" passes whether the crystals are loaded or in the hold.
Policy Editor
No Django admin needed for day-to-day policy tuning:
- Per-item: policy mode, allowed meta groups, quantity leeway (Qty%), notes.
- Override chips: cross-family includes or per-slot excludes, with a search-filtered picker.
- Abyssal bounds modal: per-attribute acceptance windows for mutated modules.
- Named Compliance Policies apply a slot-group ruleset to multiple fits in one action.
- Pre-built policies ship ready to use — Strict, Standard, Flexible, and No Enforcement (ten slot rules each). Built-ins are seeded automatically and are superuser-only to edit and can never be deleted, so managers can apply them without risk of losing a shared baseline.
- Disable / Enable any policy (built-in or custom): disabled policies drop out of the "apply" picker while fits that already use them keep their per-module settings.
- Created / updated / disabled dates show on the policies list and edit page; fits and doctrines show their created and updated dates too.
- Every policy change bumps the fit version and flags existing submissions as stale.
Site-Wide Enforcement Settings
Global REJECT / POLICY / WARN / IGNORE modes for each optional section, configured in-app:
- Implants
- Boosters
- Fuel Bay
- Frigate Escape Bay
POLICY mode defers to the per-item policy editor; the other modes override it site-wide.
Always-Current Game Data
- Local SDE mirror: ~9,400 types, ~130k attribute values, ~5,600 mutaplasmid mappings.
- Includes CCP's official
dynamicItemAttributesdata — no community supplement required. - Daily Celery beat task checks CCP's official build pointer after downtime and refreshes automatically when a new build ships.
Installation
-
Install into your Auth venv:
pip install aa-fitcheck
-
Add
"eveuniverse"and"fitcheck"toINSTALLED_APPSinlocal.py. -
Add the ESI contact email CCP requires for third-party apps (skip if already set for django-esi):
ESI_USER_CONTACT_EMAIL = "you@example.com"
-
Run migrations and load the static data:
python manage.py migrate python manage.py fitcheck_load_sde
-
Add the SDE refresh task to
local.py:CELERYBEAT_SCHEDULE["fitcheck_update_sde_data"] = { "task": "fitcheck.tasks.update_sde_data", "schedule": crontab(minute="30", hour="12"), # daily, after CCP's 11:00 downtime }
-
Restart Auth and assign permissions.
Optional: Secure Groups smart filter
To auto-manage Auth groups from doctrine compliance, install with the
securegroups extra (requires allianceauth-securegroups):
pip install aa-fitcheck[securegroups]
Add "securegroups" to INSTALLED_APPS, run python manage.py migrate, and a
Smart Filter: Fit Compliance becomes available in Secure Groups. The plugin
works normally without it — the filter simply isn't offered.
Permissions
| Permission | Purpose |
|---|---|
fitcheck.basic_access |
See the app, visible doctrines, submit own fits, validate own ships, Save-to-EVE |
fitcheck.manage_doctrines |
Create/edit doctrines, import fits, set policies, assign fits to doctrines |
fitcheck.review_submissions |
Review queue, approve/reject any submission |
fitcheck.secure_group_management |
Review and approve submissions only — cannot edit doctrines or standards |
fitcheck.manage_policies |
Create/edit named compliance policies |
fitcheck.view_compliance_reports |
Org-wide compliance reports (planned) |
fitcheck.view_member_inventory |
Browse alliance-wide members' ships and run proactive fit checks |
fitcheck.view_own_corp_inventory |
Browse own corporation members' ships (corp-scoped proactive checks) |
Settings
| Setting | Default | Purpose |
|---|---|---|
FITCHECK_SDE_SOURCE_URL |
Official CCP JSONL bundle | Static-data archive URL |
FITCHECK_NOTIFY_REVIEWERS |
True |
Notify reviewers on new submissions |
FITCHECK_REVIEWER_DIGEST |
False |
Periodic digest instead of per-submission pings (schedule fitcheck.tasks.send_review_digest) |
FITCHECK_ESI_CONTACT |
ESI_USER_CONTACT_EMAIL |
Contact email in the ESI User-Agent header |
Section-level enforcement modes (Implants, Boosters, Fuel Bay, Frigate Escape Bay) are managed
through the in-app Enforcement Settings page — no local.py changes required.
Integration (Python API)
Other plugins can query a user's doctrine compliance through the stable Python API in
fitcheck.services.api — no REST layer, no reaching into internals. A user is compliant
when they have a submission whose engine verdict passes (COMPLIANT / COMPLIANT_SUBS); by
default the check also requires the submission to be current (not stale) and not
reviewer-rejected. Pass require_approved=True to additionally require a reviewer's approval.
from fitcheck.services import api
# Is this user compliant with a doctrine (any one of its fits) or a specific fit?
api.is_user_compliant(user, doctrine=doctrine) # -> bool
api.is_user_compliant(user, fit=fit, require_approved=True)
# The submission that proves it (newest qualifying one), or None.
api.get_qualifying_submission(user, doctrine=doctrine)
# A ComplianceResult (.is_compliant, .submission, .verdict) for one user…
api.get_user_compliance(user, doctrine=doctrine)
# …or for many users in a single query (built for bulk audits).
for result in api.iter_user_compliance(users, doctrine=doctrine):
...
Target a doctrine= (compliant with any fit graded under it), a fit= (that specific
fitting standard), or both.
Secure Groups
With the optional securegroups extra installed (see Installation), a Smart Filter: Fit
Compliance lets an admin require doctrine/fit compliance for membership of an Auth group —
e.g. a "Shield Supers" group that only holds pilots with a compliant Hel or Wyvern fit. The
filter is backed by the compliance API above and honours the same staleness / approval options.
Roadmap
Versions follow Semantic Versioning; the table is ordered by priority, not pinned to specific version numbers (those are assigned at release).
| Milestone | Scope |
|---|---|
| Shipped | Full substitution engine with bipartite matching; abyssal/mutated modules; per-doctrine policy snapshots; pre-built and custom named compliance policies (with disable/enable); ESI inventory validation; ESI saved-fittings intake (check fits saved in EVE's Fittings panel without an EFT paste); implant, booster, fuel bay, and Frigate Escape Bay verification (implants/boosters carried as cargo or fleet-hangar refit pass); category-driven visibility with group gating; proactive alliance/corp member checks; colcrunch fittings import and re-sync; pilot QoL tools (Save-to-EVE, Copy Buy All, Copy as EFT); submission-detail review with a per-section captured-loadout panel; review workflow with audit log and notifications; cross-plugin compliance Python API; optional Secure Groups smart filter |
| Next | Compliance reports + CSV export (view_compliance_reports); CI (GitHub Actions, tox py310–312); i18n pass |
| Later | Corporation-role internal audits (corp members with the right EVE roles audit ships in corp hangars against doctrines, no approval flow); aa-srp integration (compare a loss's killmail fit to doctrines/fits/substitutions during SRP review); bulk "audit all my fits" for pilots; per-doctrine reviewer scoping; override-chip allow/forbid toggle |
See CHANGELOG.md for released and in-progress changes.
Development
uv venv .venv --python 3.12
uv pip install -e .[tests] fakeredis
python manage.py test fitcheck
License: GPL-3.0-or-later.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aa_fitcheck-1.1.0.tar.gz.
File metadata
- Download URL: aa_fitcheck-1.1.0.tar.gz
- Upload date:
- Size: 266.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2023782f0ade5ac6effa4dd03b4e7cef3fd2fa24e948294e7807b7e7c71950f
|
|
| MD5 |
b623c86d8a56c2250220ad3e77926772
|
|
| BLAKE2b-256 |
f00d05a96f1201a33b57cd4d47d2cd6753b56a78b15b41dfb2c99b7ffeb95cf7
|
Provenance
The following attestation bundles were made for aa_fitcheck-1.1.0.tar.gz:
Publisher:
publish.yml on TrueMessenger/aa-fitcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aa_fitcheck-1.1.0.tar.gz -
Subject digest:
d2023782f0ade5ac6effa4dd03b4e7cef3fd2fa24e948294e7807b7e7c71950f - Sigstore transparency entry: 1863474719
- Sigstore integration time:
-
Permalink:
TrueMessenger/aa-fitcheck@fcd804435850169f1341ca3dd53a86e38ef133f0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/TrueMessenger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fcd804435850169f1341ca3dd53a86e38ef133f0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aa_fitcheck-1.1.0-py3-none-any.whl.
File metadata
- Download URL: aa_fitcheck-1.1.0-py3-none-any.whl
- Upload date:
- Size: 335.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97c26d254e049a8800f2d516a62c63e751fdde9198e65c2c9186b1360c76c4bb
|
|
| MD5 |
5369d7c477be2aae1988860167a81f88
|
|
| BLAKE2b-256 |
142ca3b61a9fc7c3aeffbc60e92b77738b8e041b820c7067b204cf496db07bef
|
Provenance
The following attestation bundles were made for aa_fitcheck-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on TrueMessenger/aa-fitcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aa_fitcheck-1.1.0-py3-none-any.whl -
Subject digest:
97c26d254e049a8800f2d516a62c63e751fdde9198e65c2c9186b1360c76c4bb - Sigstore transparency entry: 1863474819
- Sigstore integration time:
-
Permalink:
TrueMessenger/aa-fitcheck@fcd804435850169f1341ca3dd53a86e38ef133f0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/TrueMessenger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fcd804435850169f1341ca3dd53a86e38ef133f0 -
Trigger Event:
push
-
Statement type: