# State Flow

Shows every data contract, how it is created, mutated, and consumed across steps.

---

## Data Contract Lifecycle

```mermaid
flowchart LR
    subgraph "Step 01 Output"
        II["IngestedInputs\n{ user_prompt: str|None\n  images_dir: Path|None\n  image_paths: list[Path] }"]
    end

    subgraph "Step 02 Output"
        LPRD["LoadedPRD\n{ path: Path\n  text: str\n  images: list[PRDImage]\n  ddl_path: Path|None }"]
    end

    subgraph "Step 03 Output"
        MANIFEST["api_manifest: dict\n{ version, modules: [\n  { name, prefix, endpoints }\n], enums }"]
        BACKEND_FILES["backend/ on disk\n(FastAPI Python project)"]
    end

    subgraph "Step 04 Output"
        AP["AppPlan\n{ app_name: str\n  pages: list[PageNode]\n  shared_state: list[SharedStateField]\n  default_route: str\n  design_system: DesignSystem }"]
        IRB["IRBundle × N pages\n{ page_ir, data_ir,\n  data_fetch_ir, data_model_ir,\n  behaviour_ir, component_ir,\n  layout_ir, navigation_ir,\n  realtime_ir, metadata }"]
        AIR["AppIRBundle\n{ app_plan: AppPlan\n  ir_pages: list[IRPage]\n  run_id: str\n  encoded_images: list[EncodedImage] }"]
    end

    subgraph "Step 05 Output"
        PB["PageBundle × N\n{ page_node: PageNode\n  ir_bundle: IRBundle\n  react_code: str (TSX) }"]
        MPB["MultiPageBundle\n{ app_plan: AppPlan\n  pages: list[PageBundle]\n  router_code: str\n  context_code: str\n  run_id: str }"]
        FE_FILES["frontend/src/ on disk\nApp.tsx\nAppContext.tsx\npages/*.tsx"]
    end

    II -->|"user_prompt\nimages_dir\nimage_paths"| LPRD
    II -->|"user_prompt\nimage_paths"| BACKEND_FILES

    LPRD -->|"ddl_path\nprd_file"| BACKEND_FILES
    LPRD -->|"text (prd_text)\nimages (prd_images)"| AIR

    BACKEND_FILES -->|"api_manifest.json\nparsed as dict"| MANIFEST
    MANIFEST -->|"api_manifest: dict"| AIR
    MANIFEST -->|"api_manifest: dict"| MPB

    AP -->|"app_name, pages\nroutes, design_system"| AIR
    IRB -->|"12-section IR\nper page"| AIR

    AIR -->|"ir_pages: list[IRPage]\napp_plan: AppPlan"| MPB

    PB -->|"react_code: str (TSX)"| MPB
    MPB -->|"router_code\ncontext_code\npages"| FE_FILES
```

---

## RunLog State Transitions

```mermaid
stateDiagram-v2
    [*] --> Created : RunLog(run_id) in generate_project()

    Created --> Active : set_active(run_log)

    state Active {
        [*] --> Idle

        Idle --> StepRunning : with run_log.step("step-01-input-ingestion")
        StepRunning --> LLMRecording : record_llm_call() called by timed_llm_call
        LLMRecording --> StepRunning : LLMCall appended to StepEvent.llm_calls
        StepRunning --> Idle : step exits (status="ok")
        StepRunning --> StepFailed : exception raised
        StepFailed --> Idle : status="failed", error recorded, re-raised
    }

    Active --> Finalized : run_log.finalize(master_out)\n(always, in finally: block)
    Finalized --> [*] : set_active(None)\nrun_log.json + run_log.md written
```

---

## AppPlan State Transitions

```mermaid
stateDiagram-v2
    [*] --> LLMResponse : Bedrock returns JSON string

    LLMResponse --> RawJSON : extract_json_object(text)\nfinds first { and last }

    RawJSON --> Validated : AppPlan.model_validate(json.loads(json_str))\nPydantic validates all fields

    Validated --> Sanitized : for page in app_plan.pages:\n  page.page_id = sanitize_page_id(page.page_id)\n  (snake_case, max 30 chars)

    Sanitized --> InBundle : AppIRBundle(app_plan=app_plan, ...)

    InBundle --> [*] : passed to step-05 generate_react_pages()\nand scaffold_frontend()
```

---

## IRBundle State Transitions (per page)

```mermaid
stateDiagram-v2
    [*] --> Prompted : PageNode + images + api_manifest\nbuilt into Bedrock prompt

    Prompted --> LLMCall : ChatBedrockConverse.invoke()\nOpus 4.6 model

    LLMCall --> TextResponse : AIMessage.content\n(may be str or list[dict])

    TextResponse --> CoercedText : coerce_message_content_to_text()\nconcatenates all text blocks

    CoercedText --> ExtractedJSON : extract_json_object(text)\nfinds { ... } substring

    ExtractedJSON --> ParsedDict : json.loads(json_str)

    ParsedDict --> ValidatedIR : IRBundle.model_validate(parsed_dict)\nPydantic validates 12 sections\nextra="forbid" → strict

    ValidatedIR --> IRPage : IRPage(page_node, ir_bundle)\nappended to ir_pages list

    IRPage --> AppIRBundle : returned to orchestrator
    AppIRBundle --> WrittenJSON : ir_bundle.model_dump_json(indent=2)\nwritten to s04_out/ir/<page_id>_ir.json

    ValidatedIR --> [*] : passed to step-05 as ir_bundle
```

---

## Shared State Fields (AppPlan.shared_state)

```mermaid
flowchart LR
    AP["AppPlan.shared_state\nlist[SharedStateField]"]

    AP -->|"key, type, initial_value"| CTX["generate_context_code(app_plan)\ndeterministic\n→ AppContext.tsx"]

    CTX -->|"React Context + Provider\nuseState per field"| FE["frontend/src/AppContext.tsx\nexports: AppContextProvider\nuseAppContext() hook"]

    FE -->|"consumed by"| PAGES["All page TSX files\nimport { useAppContext } from '../AppContext'"]
```

---

## Design System State

```mermaid
flowchart LR
    DS["AppPlan.design_system\nDesignSystem {\n  theme_mode: 'light'|'dark'\n  color_primary: '#1677ff'\n  font_family: str\n  font_size_base: int\n  border_radius: int\n  component_overrides: dict\n}"]

    DS -->|"Ant Design ConfigProvider\ntheme tokens"| SCAFFOLD["scaffold_frontend()\n→ frontend/src/main.tsx\n(or App.tsx wrapper)"]

    SCAFFOLD -->|"<ConfigProvider theme={...}>"| RUNTIME["Runtime: Ant Design\napplies theme globally"]
```

---

## EncodedImage State

```mermaid
flowchart LR
    RAW["Raw image files\n.png / .jpg / .jpeg / .gif / .webp"]

    RAW -->|"path.read_bytes()"| DETECT["_detect_media_type(data)\nfile header → media_type"]

    DETECT -->|"base64.b64encode(raw)"| ENCODED["EncodedImage {\n  path: Path\n  media_type: str\n  base64_data: str\n}"]

    ENCODED -->|"encoded_image_to_bedrock_block()"| BLOCK["Bedrock content block {\n  type: 'image'\n  source: {\n    type: 'base64'\n    media_type: str\n    data: str\n  }\n}"]

    BLOCK -->|"included in messages"| LLM["Bedrock Opus LLM call\nfor page detection or IR generation"]
```

---

## Related source files

- [shared/schemas/app_plan.py](../../shared/schemas/app_plan.py)
- [shared/schemas/ir_bundle.py](../../shared/schemas/ir_bundle.py)
- [shared/schemas/app_ir.py](../../shared/schemas/app_ir.py)
- [shared/schemas/multi_page_bundle.py](../../shared/schemas/multi_page_bundle.py)
- [shared/run_log.py](../../shared/run_log.py)
- [shared/media/images.py](../../shared/media/images.py)
