{
  "openapi": "3.1.0",
  "info": {
    "title": "FinGuide Mock API — Java 21 stubs",
    "version": "0.1.0-mock",
    "description": "Backend/frontend contract for the financial planning product reconstructed from the Figma Make mockup. Base path: /api/v1.\n\nThis Swagger is backed by live Java 21 stub endpoints. Use Try it out to receive deterministic mock responses. Excel model analytics are documented in docs/model-analytics.md."
  },
  "servers": [
    {
      "url": "/finguide-mock/api/v1",
      "description": "Java 21 mock stubs on 66.42.121.18"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Auth"
    },
    {
      "name": "Profile"
    },
    {
      "name": "Plan"
    },
    {
      "name": "Income"
    },
    {
      "name": "Expenses"
    },
    {
      "name": "Goals"
    },
    {
      "name": "Contributions"
    },
    {
      "name": "Pension"
    },
    {
      "name": "Budget"
    },
    {
      "name": "Analytics"
    },
    {
      "name": "Scenarios"
    },
    {
      "name": "Notifications"
    },
    {
      "name": "ImportExport"
    }
  ],
  "paths": {
    "/auth/register": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Create account",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuthTokens"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Login by email or phone",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuthTokens"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/auth/refresh": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Refresh access token",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "refreshToken"
                ],
                "properties": {
                  "refreshToken": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuthTokens"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Revoke current refresh token",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/auth/password/forgot": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Send password reset link",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted"
          }
        }
      }
    },
    "/auth/password/reset": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Reset password by token",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "newPassword"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "newPassword": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/me": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Current user profile",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Profile"
        ],
        "summary": "Update profile fields",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserProfile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/me/avatar": {
      "put": {
        "tags": [
          "Profile"
        ],
        "summary": "Upload avatar image",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Profile"
        ],
        "summary": "Remove avatar",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/me/password": {
      "put": {
        "tags": [
          "Profile"
        ],
        "summary": "Change password",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "currentPassword",
                  "newPassword"
                ],
                "properties": {
                  "currentPassword": {
                    "type": "string",
                    "format": "password"
                  },
                  "newPassword": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/plans/current": {
      "get": {
        "tags": [
          "Plan"
        ],
        "summary": "Get full normalized current plan state",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PlanState"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "put": {
        "tags": [
          "Plan"
        ],
        "summary": "Replace current plan state, used for migration/import",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PlanState"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/incomes": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Income"
        ],
        "summary": "List incomes",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/IncomeSource"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Income"
        ],
        "summary": "Create income",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IncomeSource"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/IncomeSource"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/incomes/{id}": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Income"
        ],
        "summary": "Get income",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/IncomeSource"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Income"
        ],
        "summary": "Patch income",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IncomeSource"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/IncomeSource"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Income"
        ],
        "summary": "Delete income",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/plans/{planId}/expenses": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Expenses"
        ],
        "summary": "List expenses",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExpenseItem"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Expenses"
        ],
        "summary": "Create expense",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpenseItem"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExpenseItem"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/expenses/{id}": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Expenses"
        ],
        "summary": "Get expense",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExpenseItem"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Expenses"
        ],
        "summary": "Patch expense",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpenseItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExpenseItem"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Expenses"
        ],
        "summary": "Delete expense",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/plans/{planId}/goals": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Goals"
        ],
        "summary": "List goals",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Goal"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Goals"
        ],
        "summary": "Create goal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Goal"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Goal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/goals/{id}": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Goals"
        ],
        "summary": "Get goal",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Goal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Goals"
        ],
        "summary": "Patch goal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Goal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Goal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Goals"
        ],
        "summary": "Delete goal",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/plans/{planId}/contributions": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Contributions"
        ],
        "summary": "List contributions",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contribution"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Contributions"
        ],
        "summary": "Create contribution",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Contribution"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Contribution"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/contributions/{id}": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Contributions"
        ],
        "summary": "Get contribution",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Contribution"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Contributions"
        ],
        "summary": "Patch contribution",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Contribution"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Contribution"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Contributions"
        ],
        "summary": "Delete contribution",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/plans/{planId}/goals/reorder": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Goals"
        ],
        "summary": "Persist goal order / waterfall priority",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "goalIds"
                ],
                "properties": {
                  "goalIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Goal"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/pension": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Pension"
        ],
        "summary": "Get pension settings",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PensionSettings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Pension"
        ],
        "summary": "Update pension settings",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PensionSettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PensionSettings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/budget": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Budget"
        ],
        "summary": "Get budget method, envelopes and computed spending",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BudgetSettings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Budget"
        ],
        "summary": "Update budget method/classifications/envelopes",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BudgetSettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BudgetSettings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/budget/envelopes/autogenerate": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Budget"
        ],
        "summary": "Generate envelopes from current expenses with buffer",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BudgetSettings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/dashboard": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Dashboard metrics matching mockup cards",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DashboardMetrics"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/analytics/health": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Financial health score and recommendations",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/HealthScore"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/analytics/projection": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "years",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 60,
            "default": 30
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Long-term financial projection",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/YearlyProjectionPoint"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/plans/{planId}/calendar/monthly-tracker": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "year",
          "in": "query",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Monthly tracker: done/partial/missed savings months",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "post": {
        "tags": [
          "Analytics"
        ],
        "summary": "Mark month status",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "month",
                  "status"
                ],
                "properties": {
                  "month": {
                    "type": "string",
                    "pattern": "^[0-9]{4}-[0-9]{2}$"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "completed",
                      "partial",
                      "missed"
                    ]
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/scenarios": {
      "get": {
        "tags": [
          "Scenarios"
        ],
        "summary": "List user scenarios",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Scenario"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Scenarios"
        ],
        "summary": "Create scenario from blank plan, clone or adjustments",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Scenario"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Scenario"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/scenarios/{scenarioId}": {
      "parameters": [
        {
          "name": "scenarioId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Scenarios"
        ],
        "summary": "Get scenario",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Scenario"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Scenarios"
        ],
        "summary": "Rename/update scenario",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Scenario"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Scenario"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Scenarios"
        ],
        "summary": "Delete scenario",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/scenarios/compare": {
      "post": {
        "tags": [
          "Scenarios"
        ],
        "summary": "Compare two scenarios on balance/income/expenses/savings",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "scenarioAId",
                  "scenarioBId"
                ],
                "properties": {
                  "scenarioAId": {
                    "type": "string"
                  },
                  "scenarioBId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/notifications": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "summary": "Derived alert/milestone/tip notifications",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "unread"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/notifications/read": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "summary": "Mark notifications as read",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "all": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/import": {
      "post": {
        "tags": [
          "ImportExport"
        ],
        "summary": "Import JSON/CSV parsed client-side or server-side",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "type": {
                    "type": "string"
                  },
                  "mode": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PlanState"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/export": {
      "post": {
        "tags": [
          "ImportExport"
        ],
        "summary": "Start export job",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "format"
                ],
                "properties": {
                  "format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "csv",
                      "xlsx",
                      "pdf"
                    ]
                  },
                  "scope": {
                    "type": "string",
                    "enum": [
                      "full_plan",
                      "incomes",
                      "expenses",
                      "goals",
                      "summary"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExportJob"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/export/{jobId}": {
      "parameters": [
        {
          "name": "jobId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "ImportExport"
        ],
        "summary": "Get export job/download URL",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExportJob"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/analytics/assumptions": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get projection assumptions imported from UI or Excel model",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ModelAssumptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Analytics"
        ],
        "summary": "Update projection assumptions",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModelAssumptions"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ModelAssumptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/analytics/balance/current": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Current-year workbook-style balance snapshot",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BalanceSnapshot"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/analytics/cashflow": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "startYear",
          "in": "query",
          "schema": {
            "type": "integer"
          }
        },
        {
          "name": "endYear",
          "in": "query",
          "schema": {
            "type": "integer"
          }
        },
        {
          "name": "years",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 80
          }
        }
      ],
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Rich yearly cashflow projection based on the Excel model",
        "description": "Returns income, expense, goal-spending, annual savings and accumulated capital per year. API outflows are positive; netSavings = income - expenses - goalExpenses.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CashFlowProjectionPoint"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/plans/{planId}/pension/projection": {
      "parameters": [
        {
          "name": "planId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Pension",
          "Analytics"
        ],
        "summary": "Pension projection with preserve-capital and spend-down variants",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PensionProjection"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "requestId"
            ],
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "VALIDATION_ERROR"
                ]
              },
              "message": {
                "type": "string"
              },
              "requestId": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        }
      },
      "CurrencyCode": {
        "type": "string",
        "minLength": 3,
        "maxLength": 3,
        "examples": [
          "RUB",
          "USD",
          "EUR"
        ]
      },
      "Frequency": {
        "type": "string",
        "enum": [
          "monthly",
          "yearly",
          "one_time"
        ]
      },
      "GrowthType": {
        "type": "string",
        "enum": [
          "manual",
          "inflation",
          "none",
          "schedule"
        ]
      },
      "Gender": {
        "type": "string",
        "enum": [
          "male",
          "female",
          "other"
        ]
      },
      "UserProfile": {
        "type": "object",
        "required": [
          "id",
          "name",
          "email",
          "initialBalance",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "examples": [
              "Александр Петров"
            ]
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "age": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 16,
            "maximum": 100
          },
          "gender": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Gender"
              },
              {
                "type": "null"
              }
            ]
          },
          "initialBalance": {
            "type": "number",
            "minimum": 0
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuthTokens": {
        "type": "object",
        "required": [
          "accessToken",
          "refreshToken",
          "expiresIn",
          "user"
        ],
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "refreshToken": {
            "type": "string"
          },
          "expiresIn": {
            "type": "integer",
            "examples": [
              3600
            ]
          },
          "user": {
            "$ref": "#/components/schemas/UserProfile"
          }
        }
      },
      "LoginRequest": {
        "type": "object",
        "required": [
          "login",
          "password"
        ],
        "properties": {
          "login": {
            "type": "string",
            "description": "email or normalized phone"
          },
          "password": {
            "type": "string",
            "format": "password"
          }
        }
      },
      "RegisterRequest": {
        "type": "object",
        "required": [
          "name",
          "email",
          "password"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "password": {
            "type": "string",
            "minLength": 8
          }
        }
      },
      "PensionSettings": {
        "type": "object",
        "required": [
          "currentAge",
          "retirementAge",
          "monthlyExpenses",
          "currency",
          "expectedReturnPct",
          "inflationPct",
          "withdrawalStrategy",
          "statePensionEnabled",
          "statePensionMonthly"
        ],
        "properties": {
          "currentAge": {
            "type": "integer",
            "minimum": 16,
            "maximum": 100,
            "examples": [
              32
            ]
          },
          "retirementAge": {
            "type": "integer",
            "minimum": 40,
            "maximum": 80,
            "examples": [
              60
            ]
          },
          "monthlyExpenses": {
            "type": "number",
            "minimum": 0,
            "examples": [
              120000
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "expectedReturnPct": {
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "examples": [
              9
            ]
          },
          "inflationPct": {
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "examples": [
              7
            ]
          },
          "withdrawalStrategy": {
            "type": "string",
            "enum": [
              "preserve_capital",
              "spend_down_30y"
            ],
            "description": "UI scenarios: preserve / spend"
          },
          "statePensionEnabled": {
            "type": "boolean"
          },
          "statePensionMonthly": {
            "type": "number",
            "minimum": 0,
            "examples": [
              22000
            ]
          },
          "desiredMonthlyExpensesCurrentPrices": {
            "type": [
              "number",
              "null"
            ],
            "description": "Excel model row: desired retirement spending in current prices."
          },
          "projection": {
            "$ref": "#/components/schemas/PensionProjection"
          }
        }
      },
      "IncomeSource": {
        "type": "object",
        "required": [
          "id",
          "name",
          "amount",
          "currency",
          "frequency",
          "growthType",
          "growthPct",
          "startDate"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "examples": [
              "Зарплата"
            ]
          },
          "amount": {
            "type": "number",
            "minimum": 0
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "frequency": {
            "$ref": "#/components/schemas/Frequency"
          },
          "growthType": {
            "$ref": "#/components/schemas/GrowthType"
          },
          "growthPct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "startYear": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Derived/imported active start year; startDate remains canonical for day precision."
          },
          "endYear": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Derived/imported active end year; endDate remains canonical for day precision."
          },
          "growthSchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/YearRatePoint"
            },
            "description": "Optional per-year growth rates from the Excel model. Overrides growthPct for listed years."
          }
        }
      },
      "ExpenseItem": {
        "type": "object",
        "required": [
          "id",
          "name",
          "amount",
          "currency",
          "frequency",
          "growthType",
          "growthPct",
          "startDate"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "examples": [
              "Ипотека"
            ]
          },
          "amount": {
            "type": "number",
            "minimum": 0
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "frequency": {
            "$ref": "#/components/schemas/Frequency"
          },
          "growthType": {
            "$ref": "#/components/schemas/GrowthType"
          },
          "growthPct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "growthLabel": {
            "type": "string"
          },
          "budgetClass": {
            "type": "string",
            "enum": [
              "needs",
              "wants",
              "savings"
            ]
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "startYear": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Derived/imported active start year; startDate remains canonical for day precision."
          },
          "endYear": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Derived/imported active end year; endDate remains canonical for day precision."
          },
          "growthSchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/YearRatePoint"
            },
            "description": "Optional per-year growth rates from the Excel model. Overrides growthPct for listed years."
          }
        }
      },
      "Goal": {
        "type": "object",
        "required": [
          "id",
          "name",
          "currentCost",
          "savedAmount",
          "currency",
          "targetYear",
          "type",
          "growthType",
          "growthPct",
          "priority"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "examples": [
              "Финансовая подушка"
            ]
          },
          "icon": {
            "type": "string",
            "examples": [
              "shield"
            ]
          },
          "currentCost": {
            "type": "number",
            "minimum": 0
          },
          "savedAmount": {
            "type": "number",
            "minimum": 0,
            "description": "denormalized current saved amount; server can also derive it from contributions"
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "targetYear": {
            "type": "integer",
            "minimum": 2024
          },
          "type": {
            "type": "string",
            "enum": [
              "one_time",
              "recurring"
            ]
          },
          "growthType": {
            "$ref": "#/components/schemas/GrowthType"
          },
          "growthPct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "indexLabel": {
            "type": "string"
          },
          "priority": {
            "type": "integer",
            "minimum": 1
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "plannedAmount": {
            "type": [
              "number",
              "null"
            ],
            "description": "For recurring goal-spending lines from the Excel model."
          },
          "frequency": {
            "$ref": "#/components/schemas/Frequency"
          },
          "startDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "startYear": {
            "type": [
              "integer",
              "null"
            ]
          },
          "endYear": {
            "type": [
              "integer",
              "null"
            ]
          },
          "growthSchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/YearRatePoint"
            }
          }
        }
      },
      "Contribution": {
        "type": "object",
        "required": [
          "id",
          "goalId",
          "amount",
          "date"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "goalId": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "minimum": 0
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "note": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BudgetEnvelope": {
        "type": "object",
        "required": [
          "id",
          "name",
          "limit",
          "icon",
          "color"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "limit": {
            "type": "number",
            "minimum": 0
          },
          "icon": {
            "type": "string"
          },
          "color": {
            "type": "string"
          },
          "spent": {
            "type": "number",
            "readOnly": true
          },
          "remaining": {
            "type": "number",
            "readOnly": true
          },
          "pct": {
            "type": "number",
            "readOnly": true
          },
          "isOver": {
            "type": "boolean",
            "readOnly": true
          }
        }
      },
      "BudgetSettings": {
        "type": "object",
        "required": [
          "method",
          "envelopes",
          "classifications"
        ],
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "503020",
              "envelope"
            ]
          },
          "envelopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BudgetEnvelope"
            }
          },
          "classifications": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "enum": [
                "needs",
                "wants",
                "savings"
              ]
            }
          }
        }
      },
      "PlanState": {
        "type": "object",
        "required": [
          "id",
          "profile",
          "pension",
          "incomes",
          "expenses",
          "goals",
          "contributions",
          "budget"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "profile": {
            "$ref": "#/components/schemas/UserProfile"
          },
          "pension": {
            "$ref": "#/components/schemas/PensionSettings"
          },
          "incomes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IncomeSource"
            }
          },
          "expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExpenseItem"
            }
          },
          "goals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Goal"
            }
          },
          "contributions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contribution"
            }
          },
          "budget": {
            "$ref": "#/components/schemas/BudgetSettings"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "modelAssumptions": {
            "$ref": "#/components/schemas/ModelAssumptions"
          }
        }
      },
      "YearlyProjectionPoint": {
        "type": "object",
        "required": [
          "year",
          "income",
          "expenses",
          "goalsCost",
          "netSavings"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "income": {
            "type": "number"
          },
          "expenses": {
            "type": "number"
          },
          "goalsCost": {
            "type": "number"
          },
          "netSavings": {
            "type": "number"
          }
        }
      },
      "DashboardMetrics": {
        "type": "object",
        "required": [
          "totalMonthlyIncome",
          "totalYearlyIncome",
          "totalMonthlyExpenses",
          "totalYearlyExpenses",
          "netMonthlyBalance",
          "netYearlyBalance",
          "savingsRatePct",
          "totalGoalsCost",
          "totalGoalsSaved",
          "totalGoalsRemaining",
          "monthlyGoalContribution",
          "availableForPension",
          "projectedPensionCapital",
          "yearsToRetirement",
          "emergencyFundTarget",
          "emergencyFundCurrent",
          "emergencyFundPct",
          "yearlyProjection"
        ],
        "properties": {
          "totalMonthlyIncome": {
            "type": "number"
          },
          "totalYearlyIncome": {
            "type": "number"
          },
          "totalMonthlyExpenses": {
            "type": "number"
          },
          "totalYearlyExpenses": {
            "type": "number"
          },
          "netMonthlyBalance": {
            "type": "number"
          },
          "netYearlyBalance": {
            "type": "number"
          },
          "savingsRatePct": {
            "type": "number"
          },
          "totalGoalsCost": {
            "type": "number"
          },
          "totalGoalsSaved": {
            "type": "number"
          },
          "totalGoalsRemaining": {
            "type": "number"
          },
          "monthlyGoalContribution": {
            "type": "number"
          },
          "availableForPension": {
            "type": "number"
          },
          "projectedPensionCapital": {
            "type": "number"
          },
          "yearsToRetirement": {
            "type": "integer"
          },
          "emergencyFundTarget": {
            "type": "number"
          },
          "emergencyFundCurrent": {
            "type": "number"
          },
          "emergencyFundPct": {
            "type": "number"
          },
          "yearlyProjection": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/YearlyProjectionPoint"
            }
          }
        }
      },
      "HealthScore": {
        "type": "object",
        "required": [
          "score",
          "items"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "number"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "good",
                    "warning",
                    "bad"
                  ]
                },
                "hint": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Scenario": {
        "type": "object",
        "required": [
          "id",
          "name",
          "emoji",
          "description",
          "createdAt",
          "updatedAt",
          "isBase"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "emoji": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "isBase": {
            "type": "boolean"
          },
          "basePlanId": {
            "type": "string"
          },
          "snapshot": {
            "$ref": "#/components/schemas/PlanState"
          },
          "adjustments": {
            "type": "object",
            "properties": {
              "incomeAdjPct": {
                "type": "number"
              },
              "expenseAdjPct": {
                "type": "number"
              },
              "returnAdjPct": {
                "type": "number"
              },
              "inflationAdjPct": {
                "type": "number"
              },
              "retirementAgeShift": {
                "type": "integer"
              },
              "goalsCostAdjPct": {
                "type": "number"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ImportRequest": {
        "type": "object",
        "required": [
          "type",
          "data"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "incomes",
              "expenses",
              "goals",
              "full_plan",
              "excel_model"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "append",
              "replace"
            ],
            "default": "append"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "ExportJob": {
        "type": "object",
        "required": [
          "id",
          "status",
          "format"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "done",
              "failed"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "csv",
              "xlsx",
              "pdf"
            ]
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "YearRatePoint": {
        "type": "object",
        "required": [
          "year",
          "ratePct"
        ],
        "properties": {
          "year": {
            "type": "integer",
            "minimum": 1900,
            "maximum": 2200
          },
          "ratePct": {
            "type": "number",
            "description": "Percent points. Example: 6 means 6% and is converted to 0.06 by calculation code."
          }
        }
      },
      "ModelAssumptions": {
        "type": "object",
        "required": [
          "startYear",
          "monthsPerYear",
          "currency",
          "investmentReturnPct",
          "inflationSchedule"
        ],
        "properties": {
          "startYear": {
            "type": "integer",
            "examples": [
              2024
            ]
          },
          "projectionEndYear": {
            "type": [
              "integer",
              "null"
            ],
            "examples": [
              2076
            ]
          },
          "horizonYears": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 80,
            "examples": [
              53
            ]
          },
          "birthYear": {
            "type": [
              "integer",
              "null"
            ],
            "examples": [
              1993
            ]
          },
          "monthsPerYear": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 12
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "initialCapital": {
            "type": "number",
            "default": 0
          },
          "investmentReturnPct": {
            "type": "number",
            "description": "Nominal annual return in percent points. Excel sample: 6."
          },
          "inflationSchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/YearRatePoint"
            }
          },
          "sourceModel": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional import/source marker, e.g. uploaded Excel model checksum."
          }
        }
      },
      "BalanceSnapshot": {
        "type": "object",
        "required": [
          "year",
          "monthlyIncome",
          "yearlyIncome",
          "totalIncome",
          "monthlyExpenses",
          "yearlyExpenses",
          "goalExpenses",
          "totalOutflow",
          "netSavings"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "monthlyIncome": {
            "type": "number"
          },
          "yearlyIncome": {
            "type": "number"
          },
          "totalIncome": {
            "type": "number"
          },
          "monthlyExpenses": {
            "type": "number"
          },
          "yearlyExpenses": {
            "type": "number"
          },
          "monthlyGoalExpenses": {
            "type": "number"
          },
          "yearlyGoalExpenses": {
            "type": "number"
          },
          "goalExpenses": {
            "type": "number"
          },
          "totalOutflow": {
            "type": "number"
          },
          "netSavings": {
            "type": "number"
          }
        }
      },
      "CashFlowProjectionPoint": {
        "type": "object",
        "required": [
          "year",
          "age",
          "periodNo",
          "totalIncome",
          "totalExpenses",
          "totalGoalExpenses",
          "netSavings",
          "capitalEndOfYear"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "age": {
            "type": [
              "integer",
              "null"
            ]
          },
          "periodNo": {
            "type": "integer"
          },
          "monthlyIncome": {
            "type": "number"
          },
          "yearlyIncome": {
            "type": "number"
          },
          "totalIncome": {
            "type": "number"
          },
          "monthlyExpenses": {
            "type": "number"
          },
          "yearlyExpenses": {
            "type": "number"
          },
          "totalExpenses": {
            "type": "number"
          },
          "monthlyGoalExpenses": {
            "type": "number"
          },
          "yearlyGoalExpenses": {
            "type": "number"
          },
          "totalGoalExpenses": {
            "type": "number"
          },
          "netSavings": {
            "type": "number"
          },
          "investmentReturnPct": {
            "type": "number"
          },
          "capitalStartOfYear": {
            "type": "number"
          },
          "capitalEndOfYear": {
            "type": "number"
          }
        }
      },
      "PensionSpendDownPoint": {
        "type": "object",
        "required": [
          "year",
          "age",
          "beginningCapital",
          "plannedExpense",
          "endingCapital"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "age": {
            "type": "integer"
          },
          "beginningCapital": {
            "type": "number"
          },
          "plannedExpense": {
            "type": "number",
            "description": "Positive outflow amount."
          },
          "nominalReturnPct": {
            "type": "number"
          },
          "endingCapital": {
            "type": "number"
          }
        }
      },
      "PensionProjection": {
        "type": "object",
        "required": [
          "currentAge",
          "retirementAge",
          "retirementYear",
          "capitalAtRetirement",
          "nominalReturnPct",
          "averageInflationPct",
          "realReturnPct",
          "preserveCapital",
          "spendDown"
        ],
        "properties": {
          "currentAge": {
            "type": "integer"
          },
          "retirementAge": {
            "type": "integer"
          },
          "retirementYear": {
            "type": "integer"
          },
          "capitalAtRetirement": {
            "type": "number"
          },
          "nominalReturnPct": {
            "type": "number"
          },
          "averageInflationPct": {
            "type": "number"
          },
          "realReturnPct": {
            "type": "number"
          },
          "preserveCapital": {
            "type": "object",
            "required": [
              "annualSpendableAtRetirement",
              "annualSpendableCurrentPrices",
              "monthlySpendableCurrentPrices"
            ],
            "properties": {
              "annualSpendableAtRetirement": {
                "type": "number"
              },
              "annualSpendableCurrentPrices": {
                "type": "number"
              },
              "monthlySpendableCurrentPrices": {
                "type": "number"
              }
            }
          },
          "spendDown": {
            "type": "object",
            "required": [
              "desiredMonthlyExpensesCurrentPrices",
              "desiredAnnualExpensesAtRetirement",
              "retirementYears",
              "depletionAge",
              "series"
            ],
            "properties": {
              "desiredMonthlyExpensesCurrentPrices": {
                "type": "number"
              },
              "desiredAnnualExpensesAtRetirement": {
                "type": "number"
              },
              "retirementYears": {
                "type": "integer"
              },
              "depletionAge": {
                "type": "integer"
              },
              "series": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PensionSpendDownPoint"
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Validation or domain error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid access token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  }
}
