first commit
This commit is contained in:
940
api/docs/PHASE4_IMPLEMENTATION.md
Normal file
940
api/docs/PHASE4_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,940 @@
|
||||
# Phase 4: AI Integration + Story Progression + Quest System
|
||||
## Implementation Plan
|
||||
|
||||
> **Note:** This document contains detailed implementation tasks for developers building the API backend.
|
||||
> For high-level project roadmap and progress tracking, see [/docs/ROADMAP.md](../../docs/ROADMAP.md).
|
||||
|
||||
**Document Version:** 1.2
|
||||
**Created:** November 16, 2025
|
||||
**Last Updated:** November 23, 2025
|
||||
**Status:** In Progress
|
||||
**Duration:** 3 weeks (21 days)
|
||||
**Total Tasks:** 45 tasks
|
||||
**Completed Tasks:** 22/45 (49%)
|
||||
|
||||
---
|
||||
|
||||
### Next Tasks
|
||||
- Task 8.29: Create story gameplay template with HTMX
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Phase 4 delivers the core single-player gameplay experience for Code of Conquest. This phase integrates AI narrative generation via Replicate (Llama-3 and Claude models), implements turn-based story progression with button-based actions, and creates a context-aware quest system.
|
||||
|
||||
> **Architecture Note:** All AI models (Llama-3, Claude Haiku/Sonnet/Opus) are accessed through the Replicate API for unified billing and management.
|
||||
|
||||
**Key Deliverables:**
|
||||
- AI narrative generation with tier-based model selection
|
||||
- Turn-based story progression system
|
||||
- YAML-driven quest system with context-aware offering
|
||||
- Cost tracking and usage limits
|
||||
- Complete solo gameplay loop
|
||||
|
||||
**Development Approach:**
|
||||
- Tasks are moderately granular (4 hours each)
|
||||
- Testing bundled into implementation tasks
|
||||
- Verification checkpoints after major features
|
||||
- YAML data created inline with features
|
||||
|
||||
---
|
||||
|
||||
## Week 8: Story Progression System (Days 8-14)
|
||||
|
||||
**Goal:** Implement turn-based story progression with button-based actions
|
||||
|
||||
### Task Group 8: Story UI & Integration (Tasks 29-31)
|
||||
|
||||
#### Task 8.29: Create story gameplay template with HTMX
|
||||
**Duration:** 5 hours
|
||||
**File:** `templates/game/story.html`
|
||||
|
||||
**Implementation:**
|
||||
- Create main story gameplay page layout:
|
||||
- Header: Character info, turn count, location
|
||||
- Left sidebar: Quest tracker (placeholder for Week 9)
|
||||
- Main area: Latest DM response
|
||||
- Action panel: Available action buttons
|
||||
- Footer: Custom input (if Premium/Elite)
|
||||
- Right sidebar: Conversation history (collapsible)
|
||||
- Add HTMX for dynamic updates:
|
||||
- Action buttons trigger `hx-post="/api/v1/sessions/{id}/action"`
|
||||
- Poll job status with `hx-trigger="every 2s"`
|
||||
- Update content when job completes
|
||||
- Add loading spinner during AI processing
|
||||
- Style with dark fantasy theme (match existing CSS)
|
||||
- Add responsive design (mobile-friendly)
|
||||
- Write Flask route to render template
|
||||
- Test UI rendering
|
||||
|
||||
**Dependencies:** Tasks 8.25-8.28 (API endpoints)
|
||||
**Deliverable:** Story gameplay UI template
|
||||
|
||||
**Key HTMX Patterns:**
|
||||
```html
|
||||
<!-- Action button -->
|
||||
<button
|
||||
hx-post="/api/v1/sessions/{{ session_id }}/action"
|
||||
hx-vals='{"action_type": "button", "prompt_id": "ask_locals"}'
|
||||
hx-target="#dm-response"
|
||||
hx-swap="innerHTML"
|
||||
hx-indicator="#loading">
|
||||
Ask locals for information
|
||||
</button>
|
||||
|
||||
<!-- Job status polling -->
|
||||
<div
|
||||
hx-get="/api/v1/jobs/{{ job_id }}/status"
|
||||
hx-trigger="every 2s"
|
||||
hx-swap="outerHTML">
|
||||
Processing...
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 8.30: Build action button UI with tier filtering
|
||||
**Duration:** 4 hours
|
||||
**File:** `templates/game/story.html` (extend), `app/routes/game.py`
|
||||
|
||||
**Implementation:**
|
||||
- Create Jinja2 macro for rendering action buttons
|
||||
- Filter actions based on user tier (passed from backend)
|
||||
- Show locked actions with upgrade prompt for higher tiers
|
||||
- Add tooltips with action descriptions
|
||||
- Implement custom text input area:
|
||||
- Only visible for Premium/Elite
|
||||
- Character counter (250 for Premium, 500 for Elite)
|
||||
- Submit button with validation
|
||||
- Add HTMX for seamless submission
|
||||
- Style buttons with RPG aesthetic (icons optional)
|
||||
- Disable buttons during AI processing
|
||||
- Write Flask route to provide available actions
|
||||
|
||||
**Dependencies:** Task 8.29 (Story template)
|
||||
**Deliverable:** Dynamic action button system
|
||||
|
||||
**Jinja2 Macro:**
|
||||
```jinja
|
||||
{% macro render_action(action, user_tier, locked=False) %}
|
||||
<button
|
||||
class="action-btn {% if locked %}locked{% endif %}"
|
||||
{% if not locked %}
|
||||
hx-post="/api/v1/sessions/{{ session_id }}/action"
|
||||
hx-vals='{"action_type": "button", "prompt_id": "{{ action.prompt_id }}"}'
|
||||
{% else %}
|
||||
disabled
|
||||
{% endif %}
|
||||
title="{{ action.description }}">
|
||||
{{ action.display_text }}
|
||||
{% if locked %}<span class="lock-icon">🔒</span>{% endif %}
|
||||
</button>
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 8.31: ✅ CHECKPOINT - Full story turn integration test
|
||||
**Duration:** 4 hours
|
||||
|
||||
**Verification Steps:**
|
||||
1. Create a new session via UI
|
||||
2. Click an action button
|
||||
3. Verify loading state appears
|
||||
4. Wait for AI response
|
||||
5. Verify DM response displayed
|
||||
6. Check conversation history updated
|
||||
7. Verify turn number incremented
|
||||
8. Test with different action buttons
|
||||
9. Test custom text input (Premium tier)
|
||||
10. Verify tier restrictions enforced (Free can't use Premium actions)
|
||||
11. Test rate limiting
|
||||
12. Verify Realtime updates work
|
||||
|
||||
**Success Criteria:**
|
||||
- Full story turn loop works end-to-end
|
||||
- UI updates smoothly with HTMX
|
||||
- AI responses are coherent and relevant
|
||||
- Tier filtering works correctly
|
||||
- Rate limits enforced
|
||||
- No errors in browser console or server logs
|
||||
|
||||
---
|
||||
|
||||
## Week 9: Quest System (Days 15-21)
|
||||
|
||||
**Goal:** Implement YAML-driven quest system with context-aware offering
|
||||
|
||||
### Task Group 9: Quest Data Models (Tasks 32-34)
|
||||
|
||||
#### Task 9.32: Create Quest dataclasses
|
||||
**Duration:** 5 hours
|
||||
**File:** `app/models/quest.py`
|
||||
|
||||
**Implementation:**
|
||||
- Create `QuestObjective` dataclass:
|
||||
- `objective_id`, `description`, `objective_type` (enum)
|
||||
- `required_progress`, `current_progress`, `completed`
|
||||
- Create `QuestReward` dataclass:
|
||||
- `gold`, `experience`, `items` (List[Item])
|
||||
- `reputation` (optional, for future use)
|
||||
- Create `Quest` dataclass:
|
||||
- `quest_id`, `name`, `description`, `quest_giver`
|
||||
- `difficulty` (enum: EASY, MEDIUM, HARD, EPIC)
|
||||
- `objectives` (List[QuestObjective])
|
||||
- `rewards` (QuestReward)
|
||||
- `offering_triggers` (QuestTriggers)
|
||||
- `narrative_hooks` (List[str])
|
||||
- `status` (enum: AVAILABLE, ACTIVE, COMPLETED, FAILED)
|
||||
- Implement methods:
|
||||
- `is_complete()` - Check if all objectives done
|
||||
- `get_next_objective()` - Get first incomplete objective
|
||||
- `update_progress(objective_id, amount)` - Increment progress
|
||||
- Add to_dict() / from_dict() serialization
|
||||
- Write unit tests for all methods
|
||||
|
||||
**Dependencies:** None
|
||||
**Deliverable:** Quest data models
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
quest = Quest(
|
||||
quest_id="quest_goblin_cave",
|
||||
name="Clear the Goblin Cave",
|
||||
description="A nearby cave is infested with goblins...",
|
||||
quest_giver="Village Elder",
|
||||
difficulty=QuestDifficulty.EASY,
|
||||
objectives=[
|
||||
QuestObjective(
|
||||
objective_id="kill_goblins",
|
||||
description="Defeat 5 goblins",
|
||||
objective_type=ObjectiveType.KILL,
|
||||
required_progress=5,
|
||||
current_progress=0
|
||||
)
|
||||
],
|
||||
rewards=QuestReward(gold=50, experience=100, items=[])
|
||||
)
|
||||
|
||||
quest.update_progress("kill_goblins", 1)
|
||||
quest.is_complete() # False (4 more goblins needed)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.33: Create QuestTriggers with offering logic
|
||||
**Duration:** 4 hours
|
||||
**File:** `app/models/quest.py` (extend)
|
||||
|
||||
**Implementation:**
|
||||
- Create `QuestTriggers` dataclass:
|
||||
- `location_types` (List[LocationType]) - Where quest can be offered
|
||||
- `specific_locations` (List[str]) - Optional specific location names
|
||||
- `min_character_level`, `max_character_level` (int)
|
||||
- `required_quests_completed` (List[str]) - Quest prerequisites
|
||||
- `probability_weights` (Dict[LocationType, float]) - Offer chance by location
|
||||
- Implement methods:
|
||||
- `can_offer(character_level, completed_quests)` - Check eligibility
|
||||
- `get_offer_probability(location_type)` - Get chance for location
|
||||
- Add validation (probabilities 0.0-1.0)
|
||||
- Write unit tests for offering logic
|
||||
- Document trigger system in docstrings
|
||||
|
||||
**Dependencies:** Task 9.32 (Quest model)
|
||||
**Deliverable:** Quest offering trigger system
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
triggers = QuestTriggers(
|
||||
location_types=[LocationType.TOWN, LocationType.TAVERN],
|
||||
min_character_level=1,
|
||||
max_character_level=5,
|
||||
probability_weights={
|
||||
LocationType.TOWN: 0.30,
|
||||
LocationType.TAVERN: 0.35
|
||||
}
|
||||
)
|
||||
|
||||
triggers.can_offer(character_level=3, completed_quests=[]) # True
|
||||
triggers.get_offer_probability(LocationType.TAVERN) # 0.35 (35% chance)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.34: ✅ CHECKPOINT - Verify quest model serialization
|
||||
**Duration:** 2 hours
|
||||
|
||||
**Verification Steps:**
|
||||
1. Create sample quest with all fields
|
||||
2. Convert to dict with to_dict()
|
||||
3. Serialize to JSON
|
||||
4. Deserialize from JSON
|
||||
5. Recreate quest with from_dict()
|
||||
6. Verify all fields match original
|
||||
7. Test quest methods (is_complete, update_progress)
|
||||
8. Test trigger methods (can_offer, get_offer_probability)
|
||||
9. Test edge cases (invalid progress, level requirements)
|
||||
|
||||
**Success Criteria:**
|
||||
- Quest serialization round-trips correctly
|
||||
- All methods work as expected
|
||||
- Offering logic accurate
|
||||
- No data loss during serialization
|
||||
|
||||
---
|
||||
|
||||
### Task Group 10: Quest Content & Loading (Tasks 35-38)
|
||||
|
||||
#### Task 9.35: Create quest YAML schema
|
||||
**Duration:** 3 hours
|
||||
**File:** `app/data/quests/schema.yaml` (documentation), update `docs/QUEST_SYSTEM.md`
|
||||
|
||||
**Implementation:**
|
||||
- Document YAML structure for quests
|
||||
- Define all required and optional fields
|
||||
- Provide examples for each objective type
|
||||
- Document narrative_hooks usage
|
||||
- Create template quest file
|
||||
- Add validation rules
|
||||
- Update QUEST_SYSTEM.md with schema details
|
||||
|
||||
**Dependencies:** Task 9.32 (Quest models)
|
||||
**Deliverable:** Quest YAML schema documentation
|
||||
|
||||
**Schema Example:**
|
||||
```yaml
|
||||
quest_id: quest_goblin_cave
|
||||
name: Clear the Goblin Cave
|
||||
description: |
|
||||
A nearby cave has been overrun by goblins who are raiding nearby farms.
|
||||
The village elder asks you to clear them out.
|
||||
quest_giver: Village Elder
|
||||
difficulty: EASY
|
||||
|
||||
objectives:
|
||||
- objective_id: kill_goblins
|
||||
description: Defeat 5 goblins
|
||||
objective_type: KILL
|
||||
required_progress: 5
|
||||
|
||||
rewards:
|
||||
gold: 50
|
||||
experience: 100
|
||||
items: []
|
||||
|
||||
offering_triggers:
|
||||
location_types: [TOWN, TAVERN]
|
||||
min_character_level: 1
|
||||
max_character_level: 5
|
||||
probability_weights:
|
||||
TOWN: 0.30
|
||||
TAVERN: 0.35
|
||||
|
||||
narrative_hooks:
|
||||
- "The village elder looks worried about recent goblin attacks"
|
||||
- "You hear farmers complaining about lost livestock"
|
||||
- "A town guard mentions a cave to the north"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.36: Write 10 example quests
|
||||
**Duration:** 5 hours
|
||||
**Files:** `app/data/quests/easy/*.yaml`, `app/data/quests/medium/*.yaml`, etc.
|
||||
|
||||
**Implementation:**
|
||||
- Create quest files organized by difficulty:
|
||||
- **Easy (4 quests):** Levels 1-3, simple objectives
|
||||
1. Clear Goblin Cave (kill 5 goblins)
|
||||
2. Gather Healing Herbs (collect 10 herbs)
|
||||
3. Deliver Message to Town (travel to location)
|
||||
4. Find Lost Cat (discover location)
|
||||
- **Medium (3 quests):** Levels 3-7, multi-objective
|
||||
5. Investigate Bandit Camp (kill + collect + discover)
|
||||
6. Rescue Kidnapped Villager (travel + interact)
|
||||
7. Ancient Artifact Recovery (discover + collect)
|
||||
- **Hard (2 quests):** Levels 7-10, complex chains
|
||||
8. Stop the Necromancer (multi-step with prerequisites)
|
||||
9. Dragon's Hoard (discover + kill boss + collect)
|
||||
- **Epic (1 quest):** Level 10+, multi-chapter
|
||||
10. The Demon Lord's Return (epic multi-objective chain)
|
||||
- Include rich narrative_hooks for each quest
|
||||
- Vary reward amounts by difficulty
|
||||
- Add location variety
|
||||
- Ensure proper level gating
|
||||
|
||||
**Dependencies:** Task 9.35 (YAML schema)
|
||||
**Deliverable:** 10 complete quest YAML files
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.37: Implement QuestService with YAML loader
|
||||
**Duration:** 5 hours
|
||||
**File:** `app/services/quest_service.py`
|
||||
|
||||
**Implementation:**
|
||||
- Create `QuestService` class
|
||||
- Implement `load_quests_from_yaml(directory)` method
|
||||
- Parse all YAML files in quest directory
|
||||
- Convert to Quest objects
|
||||
- Validate quest structure and fields
|
||||
- Cache loaded quests in memory
|
||||
- Implement methods:
|
||||
- `get_quest_by_id(quest_id)`
|
||||
- `get_eligible_quests(character_level, location_type, completed_quests)`
|
||||
- `filter_by_difficulty(difficulty)`
|
||||
- `get_all_quests()`
|
||||
- Add error handling for malformed YAML
|
||||
- Write unit tests with sample quests
|
||||
- Add logging for quest loading
|
||||
|
||||
**Dependencies:** Task 9.36 (Quest YAML files)
|
||||
**Deliverable:** Quest loading and filtering service
|
||||
|
||||
**Usage:**
|
||||
```python
|
||||
service = QuestService()
|
||||
service.load_quests_from_yaml("app/data/quests/")
|
||||
|
||||
# Get eligible quests
|
||||
eligible = service.get_eligible_quests(
|
||||
character_level=3,
|
||||
location_type=LocationType.TAVERN,
|
||||
completed_quests=[]
|
||||
)
|
||||
# Returns: [Quest(...), Quest(...)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.38: ✅ CHECKPOINT - Verify quest loading and validation
|
||||
**Duration:** 2 hours
|
||||
|
||||
**Verification Steps:**
|
||||
1. Load all 10 quests from YAML files
|
||||
2. Verify all quests parsed correctly
|
||||
3. Check quest filtering by level works
|
||||
4. Test filtering by location type
|
||||
5. Verify offering probability calculations
|
||||
6. Test get_eligible_quests() with various inputs
|
||||
7. Verify error handling for invalid YAML
|
||||
8. Check quest caching works
|
||||
|
||||
**Success Criteria:**
|
||||
- All 10 quests load without errors
|
||||
- Filtering logic accurate
|
||||
- Offering probabilities correct
|
||||
- No performance issues loading quests
|
||||
- Error handling graceful
|
||||
|
||||
---
|
||||
|
||||
### Task Group 11: Quest Offering & Management (Tasks 39-42)
|
||||
|
||||
#### Task 9.39: Implement context-aware quest offering logic
|
||||
**Duration:** 5 hours
|
||||
**File:** `app/services/quest_offering_service.py`
|
||||
|
||||
**Implementation:**
|
||||
- Create `QuestOfferingService` class
|
||||
- Implement two-stage offering:
|
||||
1. **Location probability roll:**
|
||||
- Get location type probability from triggers
|
||||
- Roll random 0.0-1.0, check if < probability
|
||||
- If fail, no quest offered
|
||||
2. **Context-aware AI selection:**
|
||||
- Get eligible quests from QuestService
|
||||
- Build AI prompt with narrative_hooks
|
||||
- Ask AI to select most contextually relevant quest
|
||||
- Parse AI response to get selected quest_id
|
||||
- Implement `should_offer_quest(location_type)` method (probability roll)
|
||||
- Implement `select_quest_for_context(eligible_quests, game_context)` method (AI selection)
|
||||
- Implement main `offer_quest(session_id)` method (full flow)
|
||||
- Add validation (max 2 active quests)
|
||||
- Write integration tests with mocked AI
|
||||
- Add logging for quest offerings
|
||||
|
||||
**Dependencies:** Tasks 7.10 (NarrativeGenerator), 9.37 (QuestService)
|
||||
**Deliverable:** Context-aware quest offering system
|
||||
|
||||
**Flow:**
|
||||
```python
|
||||
offering_service = QuestOfferingService()
|
||||
|
||||
# Called after each story turn
|
||||
if offering_service.should_offer_quest(LocationType.TAVERN):
|
||||
eligible = quest_service.get_eligible_quests(...)
|
||||
selected_quest = offering_service.select_quest_for_context(
|
||||
eligible_quests=eligible,
|
||||
game_context={
|
||||
"location": "The Rusty Anchor",
|
||||
"recent_actions": ["talked to locals", "rested"],
|
||||
"active_quests": []
|
||||
}
|
||||
)
|
||||
# Returns: Quest object or None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.40: Integrate quest offering into story turns
|
||||
**Duration:** 4 hours
|
||||
**File:** `app/tasks/ai_tasks.py` (extend generate_dm_response job)
|
||||
|
||||
**Implementation:**
|
||||
- Update `generate_dm_response()` RQ job
|
||||
- After AI narrative generated and before saving:
|
||||
1. Check if quest should be offered (probability roll)
|
||||
2. If yes, get eligible quests
|
||||
3. Call AI to select contextually relevant quest
|
||||
4. Add quest offering to response data
|
||||
5. Store offered quest in session state (pending acceptance)
|
||||
- Add quest offering to conversation entry:
|
||||
```python
|
||||
{
|
||||
"turn": 5,
|
||||
"action": "...",
|
||||
"dm_response": "...",
|
||||
"quest_offered": {
|
||||
"quest_id": "quest_goblin_cave",
|
||||
"quest_name": "Clear the Goblin Cave"
|
||||
}
|
||||
}
|
||||
```
|
||||
- Update API response format to include quest offering
|
||||
- Write integration tests for offering flow
|
||||
- Add logging for quest offerings
|
||||
|
||||
**Dependencies:** Task 9.39 (Quest offering logic)
|
||||
**Deliverable:** Integrated quest offering in story turns
|
||||
|
||||
**Updated Response:**
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"result": {
|
||||
"dm_response": "As you chat with the locals...",
|
||||
"quest_offered": {
|
||||
"quest_id": "quest_goblin_cave",
|
||||
"name": "Clear the Goblin Cave",
|
||||
"description": "...",
|
||||
"rewards": {"gold": 50, "experience": 100}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.41: Implement quest accept endpoint
|
||||
**Duration:** 4 hours
|
||||
**File:** `app/routes/quests.py` (new file)
|
||||
|
||||
**Implementation:**
|
||||
- Create `POST /api/v1/quests/accept` endpoint
|
||||
- Validate request body:
|
||||
```json
|
||||
{
|
||||
"session_id": "sess_789",
|
||||
"quest_id": "quest_goblin_cave"
|
||||
}
|
||||
```
|
||||
- Validate quest is currently offered to session
|
||||
- Check max 2 active quests limit
|
||||
- Add quest to session's active_quests
|
||||
- Initialize quest with status ACTIVE
|
||||
- Store quest state in character (or session)
|
||||
- Return accepted quest details
|
||||
- Add @require_auth decorator
|
||||
- Write integration tests
|
||||
- Document in API_REFERENCE.md
|
||||
|
||||
**Dependencies:** Task 9.39 (Quest offering)
|
||||
**Deliverable:** Quest acceptance endpoint
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"result": {
|
||||
"quest_id": "quest_goblin_cave",
|
||||
"status": "ACTIVE",
|
||||
"objectives": [
|
||||
{
|
||||
"objective_id": "kill_goblins",
|
||||
"description": "Defeat 5 goblins",
|
||||
"progress": "0/5"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.42: Implement quest complete endpoint with rewards
|
||||
**Duration:** 5 hours
|
||||
**File:** `app/routes/quests.py` (extend)
|
||||
|
||||
**Implementation:**
|
||||
- Create `POST /api/v1/quests/complete` endpoint
|
||||
- Validate request body:
|
||||
```json
|
||||
{
|
||||
"session_id": "sess_789",
|
||||
"quest_id": "quest_goblin_cave"
|
||||
}
|
||||
```
|
||||
- Verify quest is active for session
|
||||
- Check all objectives completed
|
||||
- Grant rewards:
|
||||
- Add gold to character
|
||||
- Add experience to character
|
||||
- Add items to inventory
|
||||
- Check for level up
|
||||
- Update quest status to COMPLETED
|
||||
- Remove from active_quests
|
||||
- Add to completed_quests list
|
||||
- Return completion details with level up info
|
||||
- Add @require_auth decorator
|
||||
- Write integration tests
|
||||
- Document in API_REFERENCE.md
|
||||
|
||||
**Dependencies:** Task 9.41 (Quest accept)
|
||||
**Deliverable:** Quest completion and reward system
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"result": {
|
||||
"quest_id": "quest_goblin_cave",
|
||||
"status": "COMPLETED",
|
||||
"rewards_granted": {
|
||||
"gold": 50,
|
||||
"experience": 100,
|
||||
"items": []
|
||||
},
|
||||
"level_up": {
|
||||
"leveled_up": true,
|
||||
"new_level": 4,
|
||||
"skill_points_gained": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task Group 12: Quest UI & Final Testing (Tasks 43-45)
|
||||
|
||||
#### Task 9.43: Create quest tracker sidebar UI
|
||||
**Duration:** 4 hours
|
||||
**File:** `templates/game/story.html` (extend left sidebar)
|
||||
|
||||
**Implementation:**
|
||||
- Add quest tracker to left sidebar
|
||||
- Display active quests (max 2)
|
||||
- Show quest name and description
|
||||
- Display objective progress (X/Y format)
|
||||
- Add "View Details" button for each quest
|
||||
- Style with RPG theme
|
||||
- Add HTMX for dynamic updates when objectives progress
|
||||
- Show "No active quests" message when empty
|
||||
- Add quest complete notification (toast/modal)
|
||||
- Test UI rendering
|
||||
|
||||
**Dependencies:** Tasks 9.41-9.42 (Quest endpoints)
|
||||
**Deliverable:** Quest tracker sidebar UI
|
||||
|
||||
**UI Structure:**
|
||||
```html
|
||||
<div class="quest-tracker">
|
||||
<h3>Active Quests ({{ active_quests|length }}/2)</h3>
|
||||
{% for quest in active_quests %}
|
||||
<div class="quest-card">
|
||||
<h4>{{ quest.name }}</h4>
|
||||
<div class="objectives">
|
||||
{% for obj in quest.objectives %}
|
||||
<div class="objective {% if obj.completed %}completed{% endif %}">
|
||||
{{ obj.description }}: {{ obj.current_progress }}/{{ obj.required_progress }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button hx-get="/quests/{{ quest.quest_id }}/details">View Details</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.44: Create quest offering modal UI
|
||||
**Duration:** 4 hours
|
||||
**File:** `templates/game/partials/quest_offer_modal.html`
|
||||
|
||||
**Implementation:**
|
||||
- Create modal component for quest offering
|
||||
- Display when quest offered in DM response
|
||||
- Show quest name, description, quest giver
|
||||
- Display objectives and rewards clearly
|
||||
- Add "Accept Quest" button (HTMX post to /api/v1/quests/accept)
|
||||
- Add "Decline" button (closes modal)
|
||||
- Style modal with RPG theme (parchment background)
|
||||
- Add HTMX to update quest tracker when accepted
|
||||
- Show error if max quests reached (2/2)
|
||||
- Test modal behavior
|
||||
|
||||
**Dependencies:** Task 9.41 (Quest accept endpoint)
|
||||
**Deliverable:** Quest offering modal UI
|
||||
|
||||
**Modal Structure:**
|
||||
```html
|
||||
<div class="modal quest-offer-modal">
|
||||
<div class="modal-content parchment">
|
||||
<h2>{{ quest.quest_giver }} offers you a quest!</h2>
|
||||
<h3>{{ quest.name }}</h3>
|
||||
<p>{{ quest.description }}</p>
|
||||
|
||||
<div class="objectives">
|
||||
<h4>Objectives:</h4>
|
||||
<ul>
|
||||
{% for obj in quest.objectives %}
|
||||
<li>{{ obj.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="rewards">
|
||||
<h4>Rewards:</h4>
|
||||
<p>Gold: {{ quest.rewards.gold }} | XP: {{ quest.rewards.experience }}</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button
|
||||
hx-post="/api/v1/quests/accept"
|
||||
hx-vals='{"session_id": "{{ session_id }}", "quest_id": "{{ quest.quest_id }}"}'
|
||||
hx-target="#quest-tracker"
|
||||
class="btn-accept">Accept Quest</button>
|
||||
<button class="btn-decline" onclick="closeModal()">Decline</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Task 9.45: ✅ FINAL CHECKPOINT - Full quest integration test
|
||||
**Duration:** 4 hours
|
||||
|
||||
**Comprehensive Test Flow:**
|
||||
|
||||
**Setup:**
|
||||
1. Create new character (level 1)
|
||||
2. Create solo session
|
||||
3. Verify starting state
|
||||
|
||||
**Quest Offering:**
|
||||
4. Take multiple story actions in a town/tavern
|
||||
5. Wait for quest offering (may take several turns)
|
||||
6. Verify quest modal appears
|
||||
7. Check quest details display correctly
|
||||
8. Accept quest
|
||||
9. Verify quest appears in tracker (1/2 active)
|
||||
|
||||
**Quest Progress:**
|
||||
10. Simulate quest progress (update objective manually via API or through combat)
|
||||
11. Verify tracker updates in real-time
|
||||
12. Complete all objectives
|
||||
13. Verify completion indicator
|
||||
|
||||
**Quest Completion:**
|
||||
14. Call complete quest endpoint
|
||||
15. Verify rewards granted (gold, XP)
|
||||
16. Check for level up if applicable
|
||||
17. Verify quest removed from active list
|
||||
18. Verify quest in completed list
|
||||
|
||||
**Edge Cases:**
|
||||
19. Try accepting 3rd quest (should fail with max 2 message)
|
||||
20. Try completing incomplete quest (should fail)
|
||||
21. Test with ineligible quest (wrong level)
|
||||
22. Verify offering probabilities work (multiple sessions)
|
||||
|
||||
**Success Criteria:**
|
||||
- Full quest lifecycle works end-to-end
|
||||
- Quest offering feels natural in story flow
|
||||
- UI updates smoothly with HTMX
|
||||
- Rewards granted correctly
|
||||
- Level up system works
|
||||
- Max 2 quest limit enforced
|
||||
- Error handling graceful
|
||||
- No bugs in browser console or server logs
|
||||
|
||||
---
|
||||
|
||||
## Deferred Tasks
|
||||
|
||||
### Task 7.15: Set up cost monitoring and alerts
|
||||
**Duration:** 3 hours
|
||||
**Files:** `app/tasks/monitoring_tasks.py`, `app/services/alert_service.py`
|
||||
|
||||
**Implementation:**
|
||||
- Create `calculate_daily_cost()` RQ job (runs daily at midnight)
|
||||
- Aggregate all AI usage from previous day
|
||||
- Calculate total cost by summing estimated costs
|
||||
- Store daily cost in Redis timeseries
|
||||
- Create `AlertService` class
|
||||
- Implement alert triggers:
|
||||
- Daily cost > $50 → Warning email
|
||||
- Daily cost > $100 → Critical email
|
||||
- Monthly projection > $1500 → Warning email
|
||||
- Add email sending via SMTP or service (e.g., SendGrid)
|
||||
- Create admin dashboard endpoint: `GET /admin/costs`
|
||||
- Write tests for cost calculation
|
||||
|
||||
**Dependencies:** Task 7.13 (Usage tracking)
|
||||
**Deliverable:** Automated cost monitoring with alerts
|
||||
|
||||
**Daily Job:**
|
||||
```python
|
||||
# Runs at midnight UTC
|
||||
@job('monitoring_tasks')
|
||||
def calculate_daily_cost():
|
||||
yesterday = date.today() - timedelta(days=1)
|
||||
total_cost = sum_all_user_costs(yesterday)
|
||||
|
||||
if total_cost > 100:
|
||||
send_alert(f"CRITICAL: Daily AI cost ${total_cost}")
|
||||
elif total_cost > 50:
|
||||
send_alert(f"WARNING: Daily AI cost ${total_cost}")
|
||||
|
||||
store_cost_metric(yesterday, total_cost)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 Complete!
|
||||
|
||||
**Deliverables Summary:**
|
||||
|
||||
### Week 7: AI Engine Foundation ✅
|
||||
- Redis/RQ infrastructure working
|
||||
- AI clients for Replicate + Anthropic (Haiku/Sonnet/Opus)
|
||||
- Model selection with tier-based routing
|
||||
- Jinja2 prompt templates (4 types)
|
||||
- Narrative generator wrapper
|
||||
- Async AI task jobs with Appwrite integration
|
||||
- Usage tracking and cost monitoring
|
||||
- Daily limits per tier enforced
|
||||
|
||||
### Week 8: Story Progression System ✅
|
||||
- 10 action prompts defined in YAML
|
||||
- ActionPrompt loader with tier/context filtering
|
||||
- Solo GameSession model with state tracking
|
||||
- SessionService for CRUD operations
|
||||
- Conversation history management
|
||||
- 4 API endpoints (create, state, action, history)
|
||||
- Story gameplay UI with HTMX
|
||||
- Dynamic action buttons with tier filtering
|
||||
- Full story turn loop working
|
||||
|
||||
### Week 9: Quest System ✅
|
||||
- Quest data models (Quest, Objective, Reward, Triggers)
|
||||
- 10 example quests in YAML (4 easy, 3 medium, 2 hard, 1 epic)
|
||||
- QuestService with YAML loader
|
||||
- Context-aware quest offering logic
|
||||
- Quest offering integrated into story turns
|
||||
- Quest accept/complete API endpoints
|
||||
- Quest tracker sidebar UI
|
||||
- Quest offering modal UI
|
||||
- Full quest lifecycle tested
|
||||
|
||||
**Next Phase:** Phase 5 - Combat System + Skill Tree UI (Week 10-11)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies Graph
|
||||
|
||||
```
|
||||
Week 7 (AI Engine):
|
||||
Task 7.1 (Redis) → 7.2 (RQ) → 7.3 (AI jobs) → 7.4 (✅ Verify)
|
||||
Task 7.5 (Replicate+Claude) → 7.7 (Model selector) → 7.8 (✅ Verify)
|
||||
│
|
||||
Task 7.9 (Templates) ───────────────────┘→ 7.10 (Narrative gen) → 7.11 (AI jobs) → 7.12 (✅ Verify)
|
||||
│
|
||||
Task 7.13 (Usage track) → 7.14 (Rate limits) ────────────────────────┘
|
||||
└→ 7.15 (Cost monitoring)
|
||||
|
||||
Note: Task 7.6 merged into 7.5 (all models via Replicate API)
|
||||
|
||||
Week 8 (Story Progression):
|
||||
Task 8.16 (ActionPrompt) → 8.17 (YAML) → 8.18 (Loader) → 8.19 (✅ Verify)
|
||||
│
|
||||
Task 8.20 (GameSession) → 8.21 (SessionService) ──────────┤
|
||||
└→ 8.22 (History) ──────────────────┤
|
||||
└→ 8.23 (State tracking) → 8.24 (✅ Verify)
|
||||
│
|
||||
Task 8.25 (Create API) ───────────────────────────┤
|
||||
Task 8.26 (Action API) ───────────────────────────┤
|
||||
Task 8.27 (State API) ────────────────────────────┤
|
||||
Task 8.28 (History API) ──────────────────────────┤
|
||||
│
|
||||
Task 8.29 (Story UI) → 8.30 (Action buttons) → 8.31 (✅ Integration test)
|
||||
|
||||
Week 9 (Quest System):
|
||||
Task 9.32 (Quest models) → 9.33 (Triggers) → 9.34 (✅ Verify)
|
||||
│
|
||||
Task 9.35 (YAML schema) → 9.36 (10 quests) → 9.37 (QuestService) → 9.38 (✅ Verify)
|
||||
│
|
||||
Task 9.39 (Offering logic) ──────────────────────────────────────────┤
|
||||
Task 9.40 (Story integration) → 9.41 (Accept API) → 9.42 (Complete API)
|
||||
│
|
||||
Task 9.43 (Tracker UI) ──────────────────────────────┤
|
||||
Task 9.44 (Offer modal) ─────────────────────────────┤
|
||||
│
|
||||
Task 9.45 (✅ Final integration test)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
**Testing Strategy:**
|
||||
- Unit tests bundled into each implementation task
|
||||
- Integration tests at verification checkpoints
|
||||
- Manual testing for UI/UX flows
|
||||
- Use docs/API_TESTING.md for endpoint testing
|
||||
|
||||
**Cost Management:**
|
||||
- Target: < $500/month total AI costs
|
||||
- Free tier users cost $0 (Replicate)
|
||||
- Monitor daily costs via Task 7.15
|
||||
- Adjust tier limits if costs spike
|
||||
|
||||
**Development Tips:**
|
||||
- Start each week by reviewing previous week's work
|
||||
- Commit frequently with conventional commit messages
|
||||
- Update API_REFERENCE.md as you build endpoints
|
||||
- Test with real AI calls periodically (not just mocks)
|
||||
- Keep YAML files well-documented and validated
|
||||
|
||||
**Estimated Timeline:**
|
||||
- Week 7: ~40 hours (5 days at 8 hours/day)
|
||||
- Week 8: ~44 hours (5.5 days at 8 hours/day)
|
||||
- Week 9: ~42 hours (5.25 days at 8 hours/day)
|
||||
- **Total: ~126 hours (~16 days of focused work)**
|
||||
|
||||
**Success Metrics:**
|
||||
- All 45 tasks completed
|
||||
- All verification checkpoints passed
|
||||
- No critical bugs in core gameplay loop
|
||||
- AI costs within budget (<$50/day during development)
|
||||
- Story progression feels engaging and responsive
|
||||
- Quest system feels natural and rewarding
|
||||
|
||||
---
|
||||
|
||||
**Document History:**
|
||||
- v1.0 (2025-11-16): Initial Phase 4 implementation plan created
|
||||
Reference in New Issue
Block a user