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_0→PRO_Story_1→ ... →PRO_Story_6 - Same cascading rules as GH chains
Session Management
- Each upload creates a
ProspectEditSessionin 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_requesthook - 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).