Skip to content

Latest commit

 

History

1,036 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GW2Analytics

CI Migration test Security scan Docker build Cache warmup codecov Latest tag

Modern combat analytics platform for Guild Wars 2 WvW (World vs World).

Independent third-party platform — no dps.report, no Elite Insights web. WvW combat logs (.zevtc) are parsed locally and stored in a stable internal model from which all analytics, API, and frontend derive.

What's new

Release Highlights
v0.15.0 GlobalStatsBar, timeline activity toggle, CSV removal, heatmap in Analyse, arq-worker, tab fix, unit tests.
v0.14.3 PlayerPositionHeatmap canvas component + presence_pct math fix.
v0.14.2 Plan 173: 14 boon uptimes + presence % + 14 outgoing boons in Combat Readout. Grouped bars + tooltips.
v0.14.1 Slow-path blob walk tests (3 hermetic tests for _contributions_from_blob_walk).
v0.14.0 CI guard against legacy db.query() reintroduction. Coverage plan updated.
v0.13.9 Zero legacy SQLAlchemy queries — last db.query() migrated to select().
v0.13.8 backfill_role_detection tests (67%→85%). Redundant limiter.reset() cleanup.
v0.13.7 Rate limiting integration tests. Guilds route tests (0%→70%).
v0.13.6 Players route coverage (30%→69%). Guilds router mounted in main.py.

See CHANGELOG.md for the full per-release history.

Highlights

  • 🎯 Per-target / per-subgroup / per-skill roll-ups on every fight — DPS, healing, and buff removals via stable pydantic aggregations with deterministic ordering + cross-field invariants.
  • 📈 Account-level historical timelines — per-day / per-fight bucketing, linear / log Y-axis, and player-name resolution on the fight drilldown's TargetFilter.
  • 🔌 Webhook subscriptions for parse-completion notifications — HMAC-SHA256 signed, 3-attempt retry + DLQ + replay, with SSRF block (HTTPS-only + universal private-IP gate).
  • 🎭 Heuristic role detection — per-(fight, account) DPS / HEAL / STRIP / BOON / MIXED classification from the 3 magnitudes + spec/profession hint table.
  • 📊 Per-player timeline overlay — one per-bucket series per player agent for multi-line chart overlays.
  • 🎨 GW2Mists-inspired frontend — dark palette, sticky glass header, inline SVG logo, favicon, and Next.js <Link> navigation.
  • ⚔️ Combat-readout UI — per-player Damage / Heal / Boons / Defense 4-table roll-up via /fights/[id]?tab=readout (default tab), with native HTML sortable tables, boon In/Out columns (14 boons), GlobalStatsBar (squad DPS/Heal/Strips/Cleanses/CC/Healers/Supports), compact FightSummaryCards (Top 3 per category), timeline activity toggle ("Toute la durée" / "Activité seulement"), and 2D position heatmap with play/pause animation.
  • 🧪 Comprehensive multi-layer test suite — pytest (libs + apps) + vitest (web components) + Playwright e2e (web flows), 117 tests, 84% coverage, all gated and green.
  • 🛡️ Audit hardening — Caddyfile HSTS/CSP, CI pip-audit/pnpm-audit, Next.js error boundaries, headers() defense-in-depth, Trivy filesystem scan + detect-secrets pre-commit hook.
  • 📊 Observability — OpenTelemetry tracing (FastAPI + SQLAlchemy + Redis) with OTLP HTTP export, structured JSON logging, Prometheus metrics endpoint, Grafana dashboard.
  • 📦 Pure monorepo — libs/gw2_core (no I/O), libs/gw2_evtc_parser (replaceable Protocol), libs/gw2_analytics (frozen pydantic), apps/api (FastAPI), web (Next.js).
  • 🔧 Zero legacy SQLAlchemy — all production queries use select() (SQLAlchemy 2.x style). CI guard prevents regression.
  • ⚡ Arq worker — dedicated background worker process for .zevtc parsing, eliminating in-request GIL contention on parallel uploads.

Architecture

                               gw2_evtc_parser
                                      │
                                      ▼ produces
                                   gw2_core ◀──constrains── gw2_analytics
                                      │
                                      ▼
                                 apps/api  ──gw2_api_client── GW2 v2
                                      │
                                      ▼
                                 web (Next.js)
Component Role
libs/gw2_core Stable Pydantic models (combat + API). Single source of truth. No I/O.
libs/gw2_evtc_parser Binary .zevtc parser behind an EvtcParser Protocol. V1.3 layout.
libs/gw2_analytics Single-, multi-fight, and event-driven aggregations. Frozen pydantic shapes with deterministic ordering + cross-field invariants.
libs/gw2_api_client Typed async httpx wrapper for the Guild Wars 2 REST API v2.
apps/api FastAPI gateway. MinIO blobs + Alembic + Postgres.
web Next.js frontend. AG Grid Community tables + SSR fetches.

API Surface

Method Path Description
POST /api/v1/uploads Ingest a .zevtc log; returns 201 (parse runs in background).
GET /api/v1/uploads/{id} Upload metadata.
GET /api/v1/fights[/{id}] List fights (paginated) or fetch a single fight.
GET /api/v1/fights/{id}/events Per-target trio (DPS + healing + buff removal) + per-bucket event windows.
GET /api/v1/fights/{id}/squads Per-subgroup roll-up.
GET /api/v1/fights/{id}/skills Per-skill hit count + damage / heal / strip totals.
GET /api/v1/fights/{id}/readout Combat readout — per-player Damage / Heal / Boons / Defense 4-table roll-up.
GET /api/v1/fights/{id}/timeline?window_s=N Per-fight temporal view (3-series, M:SS relative time).
GET /api/v1/fights/{id}/timeline/players Per-player timeline overlay.
GET /api/v1/fights/{id}/players/{account}/skills Per-player skill roll-up + loadout.
GET /api/v1/players?profession=&limit=&offset= Cross-fight player roll-up (paginated).
GET /api/v1/players/{account_name:path} Player profile + per-fight breakdown.
GET /api/v1/players/{account_name:path}/timeline Account-level historical timeline.
POST/GET/DELETE /api/v1/webhooks[/{id}] Webhook subscription management (HTTPS-only URLs).
GET /api/v1/health/summary Operational drift probe.
GET /api/v1/healthz Liveness probe.

Screenshots

Route Capture
/ Landing
/upload Upload flow
/fights Fights grid
/players Players grid
/players/[account_name] Player profile
/fights/[id]?tab=replay Replay drilldown

Quickstart

# 1. Install uv (Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. Install all monorepo deps including libs + apps
uv sync

# 3. Install git hooks
uv run pre-commit install

# 4. Bring up the infra (Postgres + MinIO + Redis + arq-worker)
#    The arq-worker handles .zevtc parsing in a dedicated background
#    process with its own GIL, avoiding in-request latency.
docker compose up -d

#    If the infra is already running from a previous version, start
#    just the new arq-worker:
#    docker compose up -d arq-worker

# 5. Configure local app env (DB + S3 creds; never commit the real .env)
cp .env.example .env

# 6. Apply the Postgres schema
cd apps/api && uv run alembic upgrade head && cd ../..

# 7. Boot the API (http://localhost:8000/docs)
uv run fastapi dev apps/api/src/gw2analytics_api/main.py

# 8. Frontend
cd web
pnpm install
pnpm dev   # http://localhost:3000

Development

# Run all backend checks (lint + typecheck + tests)
uv run ruff check libs apps
uv run pytest libs apps -q

# Run all frontend checks (typecheck + lint + tests)
cd web
pnpm typecheck && pnpm lint && pnpm test:unit

Documentation

File Purpose
CHANGELOG.md Canonical per-commit history.
CONTRIBUTING.md Workflow conventions, branch protection rules, CI gates.
docs/ROADMAP.md Forward-looking candidates and technical-debt ledger.
monitoring/grafana-dashboard.json Pre-built Grafana dashboard (upload rate, parse duration, errors, queue, drift).
plans/README.md Senior-advisor audit trails and scoped cycle implementation plans.

Contributing

See CONTRIBUTING.md for branch protection, pre-commit, code style, and test requirements.

Principles

  1. gw2_core is the only contract between layers. Everything depends on it; it depends on nothing but Pydantic.
  2. The parser is replaceable behind the EvtcParser Protocol. Swap Python for Rust + PyO3 with zero churn elsewhere.
  3. The frontend never knows about EVTC, parser internals, or DB schema — only the OpenAPI surface.
  4. Each component evolves independently — enforced by pyproject.toml per lib.

License

Proprietary software — all rights reserved. Copyright (c) 2024-2026 Roddy. See LICENSE for the full legal text and NOTICE.md for a plain-language summary of what is and isn't permitted without explicit written permission from the copyright holder.

The project is independent third-party software — no affiliation with ArenaNet or any Guild Wars 2 trademark holder. All Guild Wars 2 game content references are nominative fair use under the GW2 content policy.

About

WvW Analytics — Guild Wars 2 World vs World combat log analysis platform

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages