icarus prospects

Icarus Prospects

A web-based save editor for Icarus prospect files. Served at /prospects on the portal.


Project Details

Field Value
GitLab Project ID 4
GitLab Project icarus/prospects
Slug prospects
Repository https://git.eurekaendeavors.com/icarus/prospects
Visibility private
License GPL v3
Portal route /prospects
Source app Flask Blueprint
Depends on icarus/core
Portal milestone v0.03 - Prospects Blueprint
Portal issues #12–#17, #68–#69

What It Does

Users can upload a prospect save file (.json), reset missions, and download the modified file — all in the browser, with no installation required.

Supported features: - Reset Great Hunts mission chains (with full dependency cascading) - Reset Open World missions (with expedition → biome cascading) - Reset PRO and ELY story chains (sequential dependencies) - All missions shown with display names, descriptions, and difficulty - Session-based: no user accounts, no persistent storage of save data - WCAG 2.1 Level A accessibility (skip links, ARIA live regions, keyboard focus)


Blueprint Structure

The prospects editor is integrated into icarus/portal as a self-contained Flask Blueprint at portal/blueprints/prospects/:

portal/blueprints/prospects/
├── __init__.py              Blueprint factory, registers routes
├── models.py                SQLAlchemy models:
│                              - ProspectEditSession (session tracking)
│                              - ProspectSiteVisit (page view analytics)
│                              - ProspectUsageEvent (action logging)
├── routes.py                All HTTP routes:
│                              GET  /              Upload page
│                              POST /upload         File upload + parse
│                              GET  /editor         Mission editor UI
│                              POST /api/toggle     AJAX mission toggle
│                              POST /api/apply      Generate modified save
│                              GET  /api/download   Download modified save
│                              GET  /api/state      Current session state
├── services/
│   └── mission_service.py   Core logic:
│                              - parse_save_json()
│                              - extract_missions()
│                              - apply_dependency_cascade()
│                              - apply_resets()
│                              - get_pending_resets()
│                              - reconstruct_save_json()
├── data/
│   ├── gh_chains.json       GH mission chain definitions (from icarus/prospects)
│   ├── mission_metadata.json  Display names + descriptions (from icarus/data-catalog)
│   └── data_version.json    Data version tracking
├── templates/prospects/
│   ├── base.html            Dark Bootstrap 5 base layout
│   ├── upload.html          File upload form
│   ├── editor.html          Interactive mission editor
│   └── error.html           Error display page
└── static/
    ├── css/app.css          Custom styles (status badges, mission rows, focus styles)
    └── js/editor.js         AJAX toggle/apply/download, ARIA announcements

Dependency Cascading

Mission dependencies are enforced automatically when toggling missions:

Great Hunts (GH) Chains

  • Uncheck: Cascades downstream — all later missions in the chain are also unchecked
  • Check: Cascades upstream — all prerequisite missions in the chain are also checked
  • Chain data loaded from gh_chains.json (9 chains across Olympus/Styx/Prometheus maps)

Expedition → Biome

  • Uncheck expedition: All missions in that biome are unchecked
  • Check biome mission: The expedition unlock is auto-checked

Story Chains (PRO/ELY)

  • Sequential dependency: PRO_Story_0PRO_Story_1 → ... → PRO_Story_6
  • Same cascading rules as GH chains

Session Management

  • Each upload creates a ProspectEditSession in SQLite
  • Session ID stored in Flask session cookie
  • Sessions expire after PROSPECTS_SESSION_TTL_SECONDS (default 1 hour)
  • Expired sessions cleaned up periodically via before_request hook
  • All mission state held server-side (compressed blob + parsed state)
  • No save data persists after session expiry

API Endpoints

All API routes require an active session (return 404 otherwise).

POST /prospects/api/toggle

Toggle a mission's completed state with dependency cascading.

Request:

{"mission_name": "GH_RG_B", "completed": false, "mission_index": null}

Response:

{
  "affected": [
    {"name": "GH_RG_B", "index": 5, "completed": false},
    {"name": "GH_RG_C", "index": 6, "completed": false}
  ],
  "pending_count": 2,
  "pending_missions": ["GH_RG_B", "GH_RG_C"]
}

POST /prospects/api/apply

Apply all pending resets to the save file.

Response:

{
  "removed_missions": ["GH_RG_B", "GH_RG_C"],
  "verification": {"passed": true, "errors": []},
  "duration_ms": 42
}

GET /prospects/api/download

Download the modified save file as JSON.

GET /prospects/api/state

Get current session state (missions, pending count, stats).


Accessibility (WCAG 2.1 Level A)

Feature Issue
Skip-to-content link #65
Proper form labels and aria-describedby #68
aria-live="polite" announcements for AJAX updates #69
:focus-visible outlines on checkboxes #68
role="status" on change count badge #69
Upload error alert links to input via aria-describedby #68
Error alert contains Fix this issue link anchored to #savefile #68

Tests

38 tests in tests/test_prospects.py: - Upload page rendering, form structure, accessibility attributes - Upload validation (no file, empty, invalid JSON, missing ProspectBlob) - Upload flow: full upload → session creation, blob storage, event logging (mocked extract_missions) - Editor/API session gating (404 without active session) - Session API: toggle updates mission state + pending count, apply generates modified blob, download returns JSON - Dependency cascade logic (GH chains, expeditions, PRO story, pending resets) - Mission service: parse_save_json with valid and invalid inputs


Git Clone

Source is hosted privately on GitLab. Not exposed for public clone through the portal (development/internal project only).

Back to Docs