{
  "components": {
    "schemas": {
      "bff.errorBody": {
        "description": "errorBody is every error as a JSON client gets it: a stable code to\nswitch on, what to tell the customer, and the screen to show with it\nwhen there is one (the login screen with its notice).",
        "properties": {
          "error": {
            "description": "bad_request, unauthenticated, bad_credentials, rate_limited, not_found or internal",
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "screen": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/screen.Screen"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "error",
          "message"
        ],
        "type": "object"
      },
      "bff.loginRequest": {
        "properties": {
          "customer_id": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "customer_id",
          "password"
        ],
        "type": "object"
      },
      "bff.loginResponse": {
        "description": "loginResponse is what a JSON client gets for a login: the session token\nto send back as a bearer, when the session ends whatever happens (it\nalso ends after fifteen idle minutes), and the home screen, so the\nclient has nothing more to fetch.",
        "properties": {
          "expires_at": {
            "description": "RFC 3339, UTC",
            "type": "string"
          },
          "screen": {
            "$ref": "#/components/schemas/screen.Screen"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "token",
          "expires_at",
          "screen"
        ],
        "type": "object"
      },
      "bff.screenBody": {
        "description": "screenBody is a screen on its own, as the logout answers a JSON client.",
        "properties": {
          "screen": {
            "$ref": "#/components/schemas/screen.Screen"
          }
        },
        "required": [
          "screen"
        ],
        "type": "object"
      },
      "core.EventRecord": {
        "description": "EventRecord is one event on the bank's record (ADR-0011): something\nthat happened at an instant, raised by someone, whose cascade is\npending or done.",
        "properties": {
          "At": {
            "$ref": "#/components/schemas/time.Time"
          },
          "By": {
            "description": "who raised it: a user, a customer, a market's name, \"clock\"",
            "type": "string"
          },
          "DoneAt": {
            "$ref": "#/components/schemas/time.Time"
          },
          "ID": {
            "type": "string"
          },
          "Kind": {
            "description": "\"start of day\", \"publication\", \"payment\", \"setting\", \"opening\"",
            "type": "string"
          },
          "RaisedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/time.Time"
              }
            ],
            "description": "RaisedAt and DoneAt are wall time: in a simulation the bank's time\n(At) runs apart from the wall's, and the gap between them is how\nfast the bank works through its events."
          },
          "Status": {
            "description": "\"pending\", \"done\"",
            "type": "string"
          }
        },
        "required": [
          "ID",
          "Kind",
          "At",
          "Status",
          "By",
          "RaisedAt",
          "DoneAt"
        ],
        "type": "object"
      },
      "core.Leg": {
        "description": "Leg is one side of a movement: the account and the balance it was left\nwith, signed as the ledger holds it.",
        "properties": {
          "AccountID": {
            "type": "string"
          },
          "Balance": {
            "$ref": "#/components/schemas/luca.Amount"
          },
          "Path": {
            "description": "\"Liability:Savings:cust-001:easy-access\"",
            "type": "string"
          },
          "Type": {
            "description": "the path's first segment: Asset, Liability, Equity, Income, Expense",
            "type": "string"
          }
        },
        "required": [
          "AccountID",
          "Path",
          "Type",
          "Balance"
        ],
        "type": "object"
      },
      "core.Movement": {
        "description": "Movement is one ledger movement as written (ADR-0008): a signed amount\nfrom one account to another, the to account's balance rising by it and\nthe from account's falling, with the balance each is left with, in the\nbank's view.",
        "properties": {
          "Amount": {
            "$ref": "#/components/schemas/luca.Amount"
          },
          "Cause": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/core.EventRecord"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cause is the root event a rule's posting was made under (ADR-0011)\nand Step the posting's name within it; nil and empty for a movement\nthat is not a rule's, or from before the record."
          },
          "Code": {
            "type": "string"
          },
          "Currency": {
            "type": "string"
          },
          "Description": {
            "type": "string"
          },
          "From": {
            "$ref": "#/components/schemas/core.Leg"
          },
          "ID": {
            "type": "string"
          },
          "KnowledgeTime": {
            "$ref": "#/components/schemas/time.Time"
          },
          "Step": {
            "type": "string"
          },
          "To": {
            "$ref": "#/components/schemas/core.Leg"
          },
          "ValueTime": {
            "$ref": "#/components/schemas/time.Time"
          }
        },
        "required": [
          "ID",
          "From",
          "To",
          "Amount",
          "Currency",
          "Code",
          "ValueTime",
          "KnowledgeTime",
          "Description",
          "Cause",
          "Step"
        ],
        "type": "object"
      },
      "luca.Amount": {
        "type": "integer"
      },
      "screen.Action": {
        "description": "Action is what happens when the user taps a component. Exactly one of the\nfields is set.",
        "properties": {
          "logout": {
            "description": "end the session",
            "type": "boolean"
          },
          "screen": {
            "description": "GET this path and show the result",
            "type": "string"
          },
          "submit": {
            "description": "POST form values to this path",
            "type": "string"
          }
        },
        "type": "object"
      },
      "screen.Component": {
        "description": "Component is one element of a screen body. Type selects the component and\nwhich of the other fields are meaningful; unused fields are omitted from\nJSON.",
        "properties": {
          "action": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/screen.Action"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "description": "ISO 4217 code of the money a row or tx shows; the renderer picks the glyph by it",
            "type": "string"
          },
          "fields": {
            "items": {
              "$ref": "#/components/schemas/screen.Field"
            },
            "type": "array"
          },
          "icon": {
            "$ref": "#/components/schemas/screen.Icon"
          },
          "note": {
            "type": "string"
          },
          "pairs": {
            "items": {
              "$ref": "#/components/schemas/screen.Pair"
            },
            "type": "array"
          },
          "subtitle": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "tone": {
            "$ref": "#/components/schemas/screen.Tone"
          },
          "type": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "screen.Field": {
        "description": "Field is one input in a form.",
        "properties": {
          "kind": {
            "description": "\"text\", \"password\", \"number\"",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "placeholder": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          }
        },
        "required": [
          "name",
          "label",
          "kind"
        ],
        "type": "object"
      },
      "screen.Icon": {
        "description": "Icon names a glyph. Clients map icons to their icon set.",
        "enum": [
          "accounts",
          "activity",
          "bank",
          "home",
          "in",
          "interest",
          "lending",
          "loan",
          "",
          "out",
          "savings"
        ],
        "type": "string"
      },
      "screen.Nav": {
        "description": "Nav is the bottom tab bar.",
        "properties": {
          "active": {
            "type": "string"
          },
          "tabs": {
            "items": {
              "$ref": "#/components/schemas/screen.Tab"
            },
            "type": "array"
          }
        },
        "required": [
          "active",
          "tabs"
        ],
        "type": "object"
      },
      "screen.Pair": {
        "description": "Pair is a label/value line inside a hero or details component.",
        "properties": {
          "label": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "label",
          "value"
        ],
        "type": "object"
      },
      "screen.Screen": {
        "description": "Screen is one app view.",
        "properties": {
          "back": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/screen.Action"
              },
              {
                "type": "null"
              }
            ]
          },
          "body": {
            "items": {
              "$ref": "#/components/schemas/screen.Component"
            },
            "type": "array"
          },
          "id": {
            "type": "string"
          },
          "nav": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/screen.Nav"
              },
              {
                "type": "null"
              }
            ]
          },
          "path": {
            "description": "GET path that returns this screen",
            "type": "string"
          },
          "schema": {
            "type": "integer"
          },
          "subtitle": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "schema",
          "id",
          "path",
          "title",
          "body"
        ],
        "type": "object"
      },
      "screen.Tab": {
        "description": "Tab is one entry in the bottom tab bar.",
        "properties": {
          "icon": {
            "$ref": "#/components/schemas/screen.Icon"
          },
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "screen": {
            "type": "string"
          }
        },
        "required": [
          "key",
          "label",
          "icon",
          "screen"
        ],
        "type": "object"
      },
      "screen.Tone": {
        "description": "Tone selects a colour treatment. Clients map tones to their theme.",
        "enum": [
          "danger",
          "lending",
          "muted",
          "negative",
          "",
          "positive",
          "savings"
        ],
        "type": "string"
      },
      "staff.AboutOwed": {
        "description": "AboutOwed is core.Owed as another program reads it.",
        "properties": {
          "at_rest": {
            "type": "boolean"
          },
          "days": {
            "type": "integer"
          },
          "events": {
            "description": "root events due and not done: cascades in progress (ADR-0011)",
            "type": "integer"
          },
          "unprojected": {
            "type": "integer"
          }
        },
        "required": [
          "at_rest",
          "days",
          "unprojected",
          "events"
        ],
        "type": "object"
      },
      "staff.AboutPosition": {
        "description": "AboutPosition is the bank's position: what the dashboard leads with.",
        "properties": {
          "customers": {
            "type": "integer"
          },
          "day": {
            "description": "YYYY-MM-DD",
            "type": "string"
          },
          "day_count": {
            "type": "integer"
          },
          "lending": {
            "type": "string"
          },
          "savings": {
            "description": "formatted, as the dashboard shows it",
            "type": "string"
          }
        },
        "required": [
          "day",
          "day_count",
          "customers",
          "savings",
          "lending"
        ],
        "type": "object"
      },
      "staff.AboutRestart": {
        "description": "AboutRestart is one row of the restart record, newest first, read with\nthe row before it (see Restart).",
        "properties": {
          "customers": {
            "type": "integer"
          },
          "day_count": {
            "type": "integer"
          },
          "downtime": {
            "description": "Go duration; \"\" when unknown",
            "type": "string"
          },
          "intact": {
            "description": "day and customers equal across the stop; null when the previous row cannot say",
            "type": [
              "boolean",
              "null"
            ]
          },
          "previous_stopped_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/time.Time"
              },
              {
                "type": "null"
              }
            ]
          },
          "previous_version": {
            "description": "\"\" for unrecorded or none",
            "type": "string"
          },
          "started_at": {
            "$ref": "#/components/schemas/time.Time"
          },
          "stop_customers": {
            "type": "integer"
          },
          "stop_day_count": {
            "type": "integer"
          },
          "stopped_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/time.Time"
              },
              {
                "type": "null"
              }
            ]
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "version",
          "started_at",
          "day_count",
          "customers",
          "previous_version",
          "previous_stopped_at",
          "downtime",
          "intact",
          "stopped_at",
          "stop_day_count",
          "stop_customers"
        ],
        "type": "object"
      },
      "staff.AboutRoute": {
        "description": "AboutRoute is one route's figures since the process started, as\ninternal/routestats keeps them: the count, the latency (last, p50 and\np95 of the latest requests, the maximum ever), the most in flight at\nonce and the rate over the last minute.",
        "properties": {
          "count": {
            "type": "integer"
          },
          "in_flight": {
            "type": "integer"
          },
          "last": {
            "description": "Go durations",
            "type": "string"
          },
          "max": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "p50": {
            "type": "string"
          },
          "p95": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "pattern": {
            "description": "as registered: \"GET /v1/health\"",
            "type": "string"
          },
          "peak_in_flight": {
            "type": "integer"
          },
          "per_second": {
            "description": "completed in the last minute, a second",
            "type": "number"
          }
        },
        "required": [
          "pattern",
          "path",
          "count",
          "in_flight",
          "peak_in_flight",
          "last",
          "p50",
          "p95",
          "max",
          "per_second"
        ],
        "type": "object"
      },
      "staff.AboutSettings": {
        "description": "AboutSettings are the console settings.",
        "properties": {
          "day_length": {
            "description": "Go duration; \"0s\" is flat out",
            "type": "string"
          },
          "max_customers": {
            "type": "integer"
          }
        },
        "required": [
          "day_length",
          "max_customers"
        ],
        "type": "object"
      },
      "staff.AboutSim": {
        "description": "AboutSim is the run as it is now, with the two rates a performance run\nreads: customers added per second (the live rate while a batch add runs,\nelse the last batch's) and account days per 12h at the pass's measured\nwhole-day rate, with the last day it is made of.",
        "properties": {
          "account_days_per_12h": {
            "type": "integer"
          },
          "adding_customers": {
            "type": "boolean"
          },
          "clock": {
            "description": "the bank's clock now (simulated time), RFC 3339 UTC",
            "type": "string"
          },
          "customers_per_sec": {
            "type": "number"
          },
          "day_ends_in": {
            "description": "Go duration; \"0s\" when flat out or stopped",
            "type": "string"
          },
          "day_refused": {
            "description": "why the bank would not follow the clock when last asked",
            "type": "string"
          },
          "last_day_accounts": {
            "type": "integer"
          },
          "last_day_duration": {
            "description": "Go duration; \"\" before the first day",
            "type": "string"
          },
          "next_event": {
            "description": "the event the run loop waits for: \"payment at 2020-03-04T10:32:00Z\"",
            "type": "string"
          },
          "owed": {
            "allOf": [
              {
                "$ref": "#/components/schemas/staff.AboutOwed"
              }
            ],
            "description": "what the bank owed when last asked (ADR-0010); a drill waits for at_rest"
          },
          "running": {
            "type": "boolean"
          },
          "wall": {
            "description": "the wall clock now, RFC 3339 UTC",
            "type": "string"
          },
          "warp": {
            "description": "simulated seconds per wall second; 0 when flat out",
            "type": "number"
          }
        },
        "required": [
          "running",
          "wall",
          "clock",
          "warp",
          "day_ends_in",
          "adding_customers",
          "customers_per_sec",
          "account_days_per_12h",
          "last_day_duration",
          "last_day_accounts",
          "owed"
        ],
        "type": "object"
      },
      "staff.AboutStatus": {
        "description": "AboutStatus is the demo's state as another program reads it, at\n/about.json: the version and schema this process runs, the console\nsettings, the run's position and the restart record. gobank-deploy's\nupgrade drill reads it before and after each redeploy to compare the\nposition and read the downtime off the newest restart row.",
        "properties": {
          "database_bytes": {
            "type": "integer"
          },
          "position": {
            "$ref": "#/components/schemas/staff.AboutPosition"
          },
          "restarts": {
            "items": {
              "$ref": "#/components/schemas/staff.AboutRestart"
            },
            "type": "array"
          },
          "routes": {
            "description": "what the process has measured of each route it served",
            "items": {
              "$ref": "#/components/schemas/staff.AboutRoute"
            },
            "type": "array"
          },
          "schema": {
            "items": {
              "$ref": "#/components/schemas/staff.SchemaVersion"
            },
            "type": "array"
          },
          "settings": {
            "$ref": "#/components/schemas/staff.AboutSettings"
          },
          "sim": {
            "$ref": "#/components/schemas/staff.AboutSim"
          },
          "tables": {
            "description": "The data's size on PostgreSQL: every table biggest first, and the\nwhole database. None on pglike.",
            "items": {
              "$ref": "#/components/schemas/staff.AboutTable"
            },
            "type": "array"
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "version",
          "schema",
          "settings",
          "sim",
          "position",
          "restarts"
        ],
        "type": "object"
      },
      "staff.AboutTable": {
        "description": "AboutTable is one table's share of the database: its size on disk with\nindexes and TOAST, and its rows as PostgreSQL estimates them (as of the\nlast ANALYZE; a count would scan the biggest tables).",
        "properties": {
          "bytes": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "rows": {
            "type": "integer"
          }
        },
        "required": [
          "name",
          "rows",
          "bytes"
        ],
        "type": "object"
      },
      "staff.SchemaVersion": {
        "description": "SchemaVersion is the version a component's tables are at.",
        "properties": {
          "component": {
            "type": "string"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "component",
          "version"
        ],
        "type": "object"
      },
      "time.Time": {
        "description": "RFC 3339",
        "format": "date-time",
        "type": "string"
      }
    },
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "type": "http"
      },
      "mb_session": {
        "in": "cookie",
        "name": "mb_session",
        "type": "apiKey"
      },
      "staff_session": {
        "in": "cookie",
        "name": "staff_session",
        "type": "apiKey"
      }
    }
  },
  "info": {
    "description": "Read off the code by api/walk: every route the servers register, with what each handler can answer. Branches are not followed, so a response listed is one the handler can write on some path through it; a route whose handler the walk could not see into says so under x-unknowns.",
    "title": "Model Bank API",
    "version": "1"
  },
  "openapi": "3.1.0",
  "paths": {
    "/": {
      "get": {
        "description": "The dashboard: the bank's position, the run's state and its controls;\nit polls its own sections.",
        "operationId": "get",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The dashboard: the bank's position, the run's state and its controls; it polls its own sections",
        "tags": [
          "Simulation"
        ],
        "x-package": "staff",
        "x-prefix": "serves every path no other route does",
        "x-source": "bff/staff/console_routes.go:21"
      }
    },
    "/about": {
      "get": {
        "description": "The project: what the Model Bank is, its aims and its non-goals.",
        "operationId": "get-about",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The project: what the Model Bank is, its aims and its non-goals",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:542"
      }
    },
    "/about.json": {
      "get": {
        "description": "The demo's state for another program (GET, no session): version,\nschema, settings, the run and its rates, the position and the restart\nrecord. gobank-deploy's upgrade drill reads it before and after each\nredeploy; a performance run reads the rates.",
        "operationId": "get-about-json",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/staff.AboutStatus"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [],
        "summary": "The demo's state for another program (GET, no session): version, schema, settings, the run and its rates, the position and the restart record",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:617"
      }
    },
    "/about/adr": {
      "get": {
        "description": "The architecture decision records compiled into this build.",
        "operationId": "get-about-adr",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The architecture decision records compiled into this build",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:587"
      }
    },
    "/about/api": {
      "get": {
        "description": "The API: every route the BFF and the staff web serve, read off the\ncode at build time (package api), in clusters by subject (the\nfunction each is registered in), each linking to its own page; the\ntypes the bodies\nare made of follow. The OpenAPI document is at v1/openapi.json.\nA static page: the surface does not change while the run goes.",
        "operationId": "get-about-api",
        "responses": {
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The API: every route the BFF and the staff web serve, read off the code at build time (package api), in clusters by subject (the function each is registered in), each linking to its own page; the types the bodies are made of follow",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:564"
      }
    },
    "/about/api/{method}/{path...}": {
      "get": {
        "description": "One route of the API: what its handler needs, reads and answers,\nwith a link to the registration in the source at this build's tag.\nThe method is the pattern's or \"any\", the path the pattern's.",
        "operationId": "get-about-api-method-path",
        "parameters": [
          {
            "in": "path",
            "name": "method",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "One route of the API: what its handler needs, reads and answers, with a link to the registration in the source at this build's tag",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:574"
      }
    },
    "/about/docs": {
      "get": {
        "description": "The system documentation: the component registry, who may read what,\nthe pre-rule debt and the ADR list.",
        "operationId": "get-about-docs",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The system documentation: the component registry, who may read what, the pre-rule debt and the ADR list",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:555"
      }
    },
    "/about/docs/adr/": {
      "get": {
        "description": "An ADR whole: its page, or one of the diagrams and sources its\nmarkdown names beside it.",
        "operationId": "get-about-docs-adr",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "An ADR whole: its page, or one of the diagrams and sources its markdown names beside it",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-prefix": "serves every path under it",
        "x-source": "bff/staff/site.go:592"
      }
    },
    "/about/models": {
      "get": {
        "description": "The architecture models: the C4 system context and container diagrams.",
        "operationId": "get-about-models",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The architecture models: the C4 system context and container diagrams",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:550"
      }
    },
    "/about/runtime": {
      "get": {
        "description": "Runtime: the process, its memory against the limit, the schema\nversions and the restart record.",
        "operationId": "get-about-runtime",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Runtime: the process, its memory against the limit, the schema versions and the restart record",
        "tags": [
          "About"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:610"
      }
    },
    "/accounting/balance-sheet": {
      "get": {
        "description": "The balance sheet on the current business day, with the CET1 position.",
        "operationId": "get-accounting-balance-sheet",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The balance sheet on the current business day, with the CET1 position",
        "tags": [
          "Accounting"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:287"
      }
    },
    "/accounting/pnl": {
      "get": {
        "description": "The profit and loss statement since the bank opened, on an accrual\nbasis.",
        "operationId": "get-accounting-pnl",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The profit and loss statement since the bank opened, on an accrual basis",
        "tags": [
          "Accounting"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:283"
      }
    },
    "/add-customers": {
      "post": {
        "description": "Opens n customers in the background (POST n=), with the product mix\nthe simulation uses; /about.json shows the batch's rate.",
        "operationId": "post-add-customers",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "n": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Opens n customers in the background (POST n=), with the product mix the simulation uses; /about.json shows the batch's rate",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "control"
        },
        "x-package": "staff",
        "x-role-action": "sim_controls",
        "x-source": "bff/staff/console_routes.go:78"
      }
    },
    "/advance": {
      "post": {
        "description": "Runs one business day while the run is stopped (POST).",
        "operationId": "post-advance",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Runs one business day while the run is stopped (POST)",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "control"
        },
        "x-package": "staff",
        "x-role-action": "sim_controls",
        "x-source": "bff/staff/console_routes.go:72"
      }
    },
    "/auth/authorize": {
      "post": {
        "description": "PII (POST): an admin authorises themselves to see personal data for a\nwhile, then returns to redirect=.",
        "operationId": "post-auth-authorize",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "redirect": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "PII (POST): an admin authorises themselves to see personal data for a while, then returns to redirect=",
        "tags": [
          "Session"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/login.go:57"
      }
    },
    "/auth/revoke": {
      "post": {
        "description": "PII (POST): the admin gives the authorisation up and returns to\nredirect=.",
        "operationId": "post-auth-revoke",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "redirect": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "PII (POST): the admin gives the authorisation up and returns to redirect=",
        "tags": [
          "Session"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/login.go:69"
      }
    },
    "/customers": {
      "get": {
        "description": "The customers, one page (?page=) at a time; personal data only for an\nauthorised admin.",
        "operationId": "get-customers",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The customers, one page (?page=) at a time; personal data only for an authorised admin",
        "tags": [
          "Customers"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:382"
      }
    },
    "/customers/": {
      "get": {
        "description": "Under /customers/: a customer's detail at /customers/{id}, or one of\ntheir accounts at /customers/{id}/account/{index}, each with its\ntransactions one page (?txpage=) at a time.",
        "operationId": "get-customers",
        "parameters": [
          {
            "in": "query",
            "name": "txpage",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Under /customers/: a customer's detail at /customers/{id}, or one of their accounts at /customers/{id}/account/{index}, each with its transactions one page (?txpage=) at a time",
        "tags": [
          "Customers"
        ],
        "x-package": "staff",
        "x-prefix": "serves every path under it",
        "x-source": "bff/staff/site.go:408"
      }
    },
    "/customers/search": {
      "post": {
        "description": "Customer search by name (POST name=): the customers whose name\ncontains it, oldest first and at most core.CustomerSearchLimit, as the\nregister's table — the matches alone for htmx, the Customers page\nwith them for a browser. The name is personal data: it travels in the\nbody and never in a URL, and only an authorised admin may search.",
        "operationId": "post-customers-search",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "name": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Customer search by name (POST name=): the customers whose name contains it, oldest first and at most core.CustomerSearchLimit, as the register's table — the matches alone for htmx, the Customers page with them for a browser",
        "tags": [
          "Customers"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:390"
      }
    },
    "/dashboard/update": {
      "get": {
        "description": "The dashboard's polled sections, as an HTML fragment.",
        "operationId": "get-dashboard-update",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The dashboard's polled sections, as an HTML fragment",
        "tags": [
          "Simulation"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/console_routes.go:41"
      }
    },
    "/events": {
      "get": {
        "description": "Events: the record of what happened and what it caused (ADR-0011)",
        "operationId": "get-events",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Events: the record of what happened and what it caused (ADR-0011)",
        "tags": [
          "Internal"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:637"
      }
    },
    "/export.goluca": {
      "get": {
        "description": "The whole book as a .goluca file (GET): admin only.",
        "operationId": "get-export-goluca",
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          },
          "500": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Internal error"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The whole book as a .goluca file (GET): admin only",
        "tags": [
          "Internal"
        ],
        "x-package": "staff",
        "x-role-action": "export",
        "x-source": "bff/staff/site.go:668"
      }
    },
    "/favicon.ico": {
      "get": {
        "description": "The tab icon as .ico, from lofigui.",
        "operationId": "get-favicon-ico",
        "responses": {},
        "security": [],
        "summary": "The tab icon as .ico, from lofigui",
        "tags": [
          "Assets"
        ],
        "x-handler": {
          "function": "lofigui.ServeFavicon"
        },
        "x-methods": "any",
        "x-package": "staff",
        "x-source": "bff/staff/site.go:720",
        "x-unknowns": [
          "handler lofigui.ServeFavicon: body outside the walk",
          "no response found"
        ]
      }
    },
    "/favicon.svg": {
      "get": {
        "description": "The tab icon as SVG.",
        "operationId": "get-favicon-svg",
        "responses": {
          "200": {
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          }
        },
        "security": [],
        "summary": "The tab icon as SVG",
        "tags": [
          "Assets"
        ],
        "x-methods": "any",
        "x-package": "staff",
        "x-source": "bff/staff/site.go:722"
      }
    },
    "/import": {
      "post": {
        "description": "Replaces the book with an uploaded .goluca file (POST, multipart\nfile=): admin only.",
        "operationId": "post-import",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "properties": {
                  "file": {
                    "format": "binary",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "No file uploaded; Read error"
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          },
          "500": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Internal error"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Replaces the book with an uploaded .goluca file (POST, multipart file=): admin only",
        "tags": [
          "Internal"
        ],
        "x-package": "staff",
        "x-role-action": "export",
        "x-source": "bff/staff/site.go:687"
      }
    },
    "/internal/explorer": {
      "get": {
        "description": "The DB explorer: every component's tables, read-only; a role sees only\nthe components it may (customers needs view_pii).",
        "operationId": "get-internal-explorer",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The DB explorer: every component's tables, read-only; a role sees only the components it may (customers needs view_pii)",
        "tags": [
          "Internal"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:663"
      }
    },
    "/internal/explorer/": {
      "get": {
        "description": "The DB explorer's tables and rows, under its prefix.",
        "operationId": "get-internal-explorer",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The DB explorer's tables and rows, under its prefix",
        "tags": [
          "Internal"
        ],
        "x-package": "staff",
        "x-prefix": "serves every path under it",
        "x-source": "bff/staff/site.go:665"
      }
    },
    "/login": {
      "get": {
        "description": "The staff login: the form (GET) and its check (POST login, password)\nagainst the users component. Five failures for one login or from one\naddress lock it for fifteen minutes; 503 on a deployment with no users.",
        "operationId": "get-post-login",
        "parameters": [
          {
            "in": "query",
            "name": "redirect",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "login": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  },
                  "redirect": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Malformed login form; Enter your login and password."
          },
          "401": {
            "description": "Unknown login or wrong password."
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          },
          "429": {
            "description": "Too many requests"
          },
          "503": {
            "description": "Staff login is not set up on this deployment."
          }
        },
        "security": [],
        "summary": "The staff login: the form (GET) and its check (POST login, password) against the users component",
        "tags": [
          "Session"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/login.go:26"
      },
      "post": {
        "description": "The staff login: the form (GET) and its check (POST login, password)\nagainst the users component. Five failures for one login or from one\naddress lock it for fifteen minutes; 503 on a deployment with no users.",
        "operationId": "get-post-login",
        "parameters": [
          {
            "in": "query",
            "name": "redirect",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "login": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  },
                  "redirect": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Malformed login form; Enter your login and password."
          },
          "401": {
            "description": "Unknown login or wrong password."
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          },
          "429": {
            "description": "Too many requests"
          },
          "503": {
            "description": "Staff login is not set up on this deployment."
          }
        },
        "security": [],
        "summary": "The staff login: the form (GET) and its check (POST login, password) against the users component",
        "tags": [
          "Session"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/login.go:26"
      }
    },
    "/logout": {
      "post": {
        "description": "Ends the staff session (POST): the cookie is cleared and the browser\nsent to the login page.",
        "operationId": "post-logout",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Ends the staff session (POST): the cookie is cleared and the browser sent to the login page",
        "tags": [
          "Session"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/login.go:42"
      }
    },
    "/movements/{id}": {
      "get": {
        "description": "Serves one movement of the ledger (ADR-0008): its page; with\nthe suffix .goluca its plain-text-accounting text, with .json the\nmovement itself.",
        "operationId": "get-movements-id",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/core.Movement"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          },
          "500": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Internal error"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Serves one movement of the ledger (ADR-0008): its page; with the suffix .goluca its plain-text-accounting text, with .json the movement itself",
        "tags": [
          "Accounting"
        ],
        "x-handler": {
          "function": "(*Site).movement"
        },
        "x-package": "staff",
        "x-source": "bff/staff/site.go:291"
      }
    },
    "/payments": {
      "get": {
        "description": "Payments: the list, newest first, one page (?page=) at a time, with\nthe generator's controls.",
        "operationId": "get-payments",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Payments: the list, newest first, one page (?page=) at a time, with the generator's controls",
        "tags": [
          "Payments"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:454"
      }
    },
    "/payments/run": {
      "post": {
        "description": "Starts the payment generator (POST): the settings' payments a day.",
        "operationId": "post-payments-run",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Starts the payment generator (POST): the settings' payments a day",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "payments"
        },
        "x-package": "staff",
        "x-role-action": "send_payment",
        "x-source": "bff/staff/console_routes.go:104"
      }
    },
    "/payments/send": {
      "post": {
        "description": "Sends one generated payment now (POST).",
        "operationId": "post-payments-send",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Sends one generated payment now (POST)",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "payments"
        },
        "x-package": "staff",
        "x-role-action": "send_payment",
        "x-source": "bff/staff/console_routes.go:102"
      }
    },
    "/payments/stop": {
      "post": {
        "description": "Stops the payment generator (POST).",
        "operationId": "post-payments-stop",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Stops the payment generator (POST)",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "payments"
        },
        "x-package": "staff",
        "x-role-action": "send_payment",
        "x-source": "bff/staff/console_routes.go:106"
      }
    },
    "/payments/{id}": {
      "get": {
        "description": "One payment: its detail and the movements it made.",
        "operationId": "get-payments-id",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "One payment: its detail and the movements it made",
        "tags": [
          "Payments"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:442"
      }
    },
    "/products/bank": {
      "get": {
        "description": "The bank's own parameters (Bank Rate, the reserve ratio and the rest),\nas the Bank tab shows them.",
        "operationId": "get-products-bank",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The bank's own parameters (Bank Rate, the reserve ratio and the rest), as the Bank tab shows them",
        "tags": [
          "Products"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:313"
      }
    },
    "/products/lending": {
      "get": {
        "description": "The lending products: the family's catalogue, each product with its\nbook.",
        "operationId": "get-products-lending",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The lending products: the family's catalogue, each product with its book",
        "tags": [
          "Products"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:308"
      }
    },
    "/products/savings": {
      "get": {
        "description": "The savings products: the family's catalogue, each product with its\nbook.",
        "operationId": "get-products-savings",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The savings products: the family's catalogue, each product with its book",
        "tags": [
          "Products"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:303"
      }
    },
    "/products/{owner}/parameters/{key}": {
      "get": {
        "description": "One parameter of a product or of the bank: its history and, for a\nsigned-in user who may, the form that sets it (POST value, effective);\n?refused= carries a refusal back to the page.",
        "operationId": "get-post-products-owner-parameters-key",
        "parameters": [
          {
            "in": "path",
            "name": "owner",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "key",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "refused",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "effective": {
                    "type": "string"
                  },
                  "value": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "One parameter of a product or of the bank: its history and, for a signed-in user who may, the form that sets it (POST value, effective); ?refused= carries a refusal back to the page",
        "tags": [
          "Products"
        ],
        "x-package": "staff",
        "x-role-action": "settings",
        "x-source": "bff/staff/site.go:319"
      },
      "post": {
        "description": "One parameter of a product or of the bank: its history and, for a\nsigned-in user who may, the form that sets it (POST value, effective);\n?refused= carries a refusal back to the page.",
        "operationId": "get-post-products-owner-parameters-key",
        "parameters": [
          {
            "in": "path",
            "name": "owner",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "key",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "refused",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "effective": {
                    "type": "string"
                  },
                  "value": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Not found"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "One parameter of a product or of the bank: its history and, for a signed-in user who may, the form that sets it (POST value, effective); ?refused= carries a refusal back to the page",
        "tags": [
          "Products"
        ],
        "x-package": "staff",
        "x-role-action": "settings",
        "x-source": "bff/staff/site.go:319"
      }
    },
    "/reports/bbsi": {
      "get": {
        "description": "The BBSI return (Bank and Building Society Interest): each customer's\ninterest for the year; personal data only for an authorised admin.",
        "operationId": "get-reports-bbsi",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The BBSI return (Bank and Building Society Interest): each customer's interest for the year; personal data only for an authorised admin",
        "tags": [
          "Reports"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:519"
      }
    },
    "/reports/charts": {
      "get": {
        "description": "The charts: the book, the customer count and the rates over the run.",
        "operationId": "get-reports-charts",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The charts: the book, the customer count and the rates over the run",
        "tags": [
          "Reports"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:514"
      }
    },
    "/reports/customer-view": {
      "get": {
        "description": "A customer as the app shows them (?id=); without an id, the customer\nlist.",
        "operationId": "get-reports-customer-view",
        "parameters": [
          {
            "in": "query",
            "name": "id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "A customer as the app shows them (?id=); without an id, the customer list",
        "tags": [
          "Reports"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:524"
      }
    },
    "/reset": {
      "post": {
        "description": "Empties the bank and starts again on its opening day (POST); the\nsettings are kept.",
        "operationId": "post-reset",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Empties the bank and starts again on its opening day (POST); the settings are kept",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "control"
        },
        "x-package": "staff",
        "x-role-action": "sim_controls",
        "x-source": "bff/staff/console_routes.go:75"
      }
    },
    "/settings": {
      "get": {
        "description": "The console settings: the page (GET), and the change (POST\nmax_customers, payments_per_day, day_length; 0s runs flat out, a day\nlength that does not parse leaves the current one). The day length set\nhere is the run's and outlives the process.",
        "operationId": "get-post-settings",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "day_length": {
                    "type": "string"
                  },
                  "max_customers": {
                    "type": "string"
                  },
                  "payments_per_day": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The console settings: the page (GET), and the change (POST max_customers, payments_per_day, day_length; 0s runs flat out, a day length that does not parse leaves the current one)",
        "tags": [
          "Simulation"
        ],
        "x-package": "staff",
        "x-role-action": "settings",
        "x-source": "bff/staff/console_routes.go:114"
      },
      "post": {
        "description": "The console settings: the page (GET), and the change (POST\nmax_customers, payments_per_day, day_length; 0s runs flat out, a day\nlength that does not parse leaves the current one). The day length set\nhere is the run's and outlives the process.",
        "operationId": "get-post-settings",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "day_length": {
                    "type": "string"
                  },
                  "max_customers": {
                    "type": "string"
                  },
                  "payments_per_day": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The console settings: the page (GET), and the change (POST max_customers, payments_per_day, day_length; 0s runs flat out, a day length that does not parse leaves the current one)",
        "tags": [
          "Simulation"
        ],
        "x-package": "staff",
        "x-role-action": "settings",
        "x-source": "bff/staff/console_routes.go:114"
      }
    },
    "/settings/status": {
      "get": {
        "description": "The settings page's status line, polled on its own so the form is\nnever re-rendered under the operator.",
        "operationId": "get-settings-status",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The settings page's status line, polled on its own so the form is never re-rendered under the operator",
        "tags": [
          "Simulation"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/console_routes.go:142"
      }
    },
    "/start": {
      "post": {
        "description": "Starts the run (POST): the simulation moves day after day at the\nsettings' day length until stopped.",
        "operationId": "post-start",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Starts the run (POST): the simulation moves day after day at the settings' day length until stopped",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "control"
        },
        "x-package": "staff",
        "x-role-action": "sim_controls",
        "x-source": "bff/staff/console_routes.go:68"
      }
    },
    "/stop": {
      "post": {
        "description": "Stops the run after the day in progress (POST).",
        "operationId": "post-stop",
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Stops the run after the day in progress (POST)",
        "tags": [
          "Simulation"
        ],
        "x-handler": {
          "via": "control"
        },
        "x-package": "staff",
        "x-role-action": "sim_controls",
        "x-source": "bff/staff/console_routes.go:70"
      }
    },
    "/treasury/capital": {
      "get": {
        "description": "The reserve ratio against its requirement, and the lending headroom.",
        "operationId": "get-treasury-capital",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The reserve ratio against its requirement, and the lending headroom",
        "tags": [
          "Treasury"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:474"
      }
    },
    "/treasury/cash": {
      "get": {
        "description": "The cash position: deposits, loans, cash at the BoE against the\nrequired reserves, and the Bank Rate.",
        "operationId": "get-treasury-cash",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The cash position: deposits, loans, cash at the BoE against the required reserves, and the Bank Rate",
        "tags": [
          "Treasury"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:470"
      }
    },
    "/treasury/gilts": {
      "get": {
        "description": "The gilt holdings and the purchase form.",
        "operationId": "get-treasury-gilts",
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "405": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Method not allowed"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The gilt holdings and the purchase form",
        "tags": [
          "Treasury"
        ],
        "x-package": "staff",
        "x-source": "bff/staff/site.go:478"
      }
    },
    "/treasury/gilts/buy": {
      "post": {
        "description": "Buys a gilt (POST tenor, face_value in pounds): admin only; returns to\nthe gilts page.",
        "operationId": "post-treasury-gilts-buy",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "face_value": {
                    "type": "string"
                  },
                  "tenor": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Buys a gilt (POST tenor, face_value in pounds): admin only; returns to the gilts page",
        "tags": [
          "Treasury"
        ],
        "x-package": "staff",
        "x-role-action": "buy_gilt",
        "x-source": "bff/staff/site.go:483"
      }
    },
    "/v1/health": {
      "get": {
        "description": "Answers as soon as the process serves HTTP. No session.",
        "operationId": "get-v1-health",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          }
        },
        "security": [],
        "summary": "Answers as soon as the process serves HTTP",
        "tags": [
          "Health"
        ],
        "x-handler": {
          "function": "(*Server).health"
        },
        "x-package": "bff",
        "x-source": "bff/server.go:133"
      }
    },
    "/v1/login": {
      "post": {
        "description": "Checks the customer ID and password, from a JSON body or a form,\nand opens a session: a JSON client gets the token and the home screen; a\nform post or a browser gets the mb_session cookie and is sent to the\nhome screen. Five failures for one customer ID or from one address in\nfifteen minutes lock that key for the rest of the window (429 with\nRetry-After).",
        "operationId": "post-v1-login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/bff.loginRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "customer_id": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/bff.loginResponse"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect to /v1/screen/accounts.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "bad_request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "bad_credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "rate_limited"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "internal"
          }
        },
        "security": [],
        "summary": "Checks the customer ID and password, from a JSON body or a form, and opens a session: a JSON client gets the token and the home screen; a form post or a browser gets the mb_session cookie and is sent to the home screen",
        "tags": [
          "Customer session"
        ],
        "x-handler": {
          "function": "(*Server).login"
        },
        "x-package": "bff",
        "x-source": "bff/server.go:143"
      }
    },
    "/v1/logout": {
      "post": {
        "description": "Ends the session: a browser's cookie is cleared and it is sent\nto the login screen; a JSON client gets the login screen.",
        "operationId": "post-v1-logout",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/bff.screenBody"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect to /v1/screen/login.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "unauthenticated"
          }
        },
        "security": [
          {
            "mb_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Ends the session: a browser's cookie is cleared and it is sent to the login screen; a JSON client gets the login screen",
        "tags": [
          "Customer session"
        ],
        "x-handler": {
          "function": "(*Server).logout",
          "wrappers": [
            "(*Server).authed"
          ]
        },
        "x-package": "bff",
        "x-source": "bff/server.go:144"
      }
    },
    "/v1/openapi.json": {
      "get": {
        "description": "Serves the API document (package api): the surface this server\nand the staff web present, as built.",
        "operationId": "get-v1-openapi-json",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          }
        },
        "security": [],
        "summary": "Serves the API document (package api): the surface this server and the staff web present, as built",
        "tags": [
          "Health"
        ],
        "x-handler": {
          "function": "(*Server).openapi"
        },
        "x-package": "bff",
        "x-source": "bff/server.go:134"
      }
    },
    "/v1/screen/accounts": {
      "get": {
        "description": "The home screen: the customer's net position and a row per\naccount, each opening its product screen.",
        "operationId": "get-v1-screen-accounts",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/screen.Screen"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect to /v1/screen/login.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "unauthenticated"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "not_found"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "internal"
          }
        },
        "security": [
          {
            "mb_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The home screen: the customer's net position and a row per account, each opening its product screen",
        "tags": [
          "Screens"
        ],
        "x-handler": {
          "function": "(*Server).accounts",
          "wrappers": [
            "(*Server).authed"
          ]
        },
        "x-package": "bff",
        "x-source": "bff/server.go:151"
      }
    },
    "/v1/screen/activity": {
      "get": {
        "description": "The customer's transactions across every account, newest\nfirst, one page (?page=) at a time.",
        "operationId": "get-v1-screen-activity",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/screen.Screen"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect to /v1/screen/login.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "unauthenticated"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "not_found"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "internal"
          }
        },
        "security": [
          {
            "mb_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "The customer's transactions across every account, newest first, one page (?page=) at a time",
        "tags": [
          "Screens"
        ],
        "x-handler": {
          "function": "(*Server).activity",
          "wrappers": [
            "(*Server).authed"
          ]
        },
        "x-package": "bff",
        "x-source": "bff/server.go:152"
      }
    },
    "/v1/screen/login": {
      "get": {
        "description": "The front door: the login form, whose submit is POST\n/v1/login, with the deployment's note. No session.",
        "operationId": "get-v1-screen-login",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/screen.Screen"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          }
        },
        "security": [],
        "summary": "The front door: the login form, whose submit is POST /v1/login, with the deployment's note",
        "tags": [
          "Screens"
        ],
        "x-handler": {
          "function": "(*Server).loginScreen"
        },
        "x-package": "bff",
        "x-source": "bff/server.go:150"
      }
    },
    "/v1/screen/product/{index}": {
      "get": {
        "description": "One account, by its index in the customer's list: its\ndetails and its own transactions, one page (?page=) at a time; 404 for\nan index the customer has no account at.",
        "operationId": "get-v1-screen-product-index",
        "parameters": [
          {
            "in": "path",
            "name": "index",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/screen.Screen"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "303": {
            "description": "Redirect to /v1/screen/login.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "unauthenticated"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "not_found"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/bff.errorBody"
                    },
                    {
                      "$ref": "#/components/schemas/screen.Screen"
                    }
                  ]
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "internal"
          }
        },
        "security": [
          {
            "mb_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "One account, by its index in the customer's list: its details and its own transactions, one page (?page=) at a time; 404 for an index the customer has no account at",
        "tags": [
          "Screens"
        ],
        "x-handler": {
          "function": "(*Server).product",
          "wrappers": [
            "(*Server).authed"
          ]
        },
        "x-package": "bff",
        "x-source": "bff/server.go:153"
      }
    },
    "/view/{name}": {
      "get": {
        "description": "Switches this browser between the bank's view and the\ncustomer's: GET view/{name}?back=\u003cpath\u003e sets the staff_view cookie for a\nyear and returns to the page that offered it.",
        "operationId": "get-view-name",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "back",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "Switches this browser between the bank's view and the customer's: GET view/{name}?back=\u003cpath\u003e sets the staff_view cookie for a year and returns to the page that offered it",
        "tags": [
          "Session"
        ],
        "x-handler": {
          "function": "(*Site).viewSwitch"
        },
        "x-methods": "any",
        "x-package": "staff",
        "x-source": "bff/staff/login.go:80"
      }
    },
    "/wasm/": {
      "get": {
        "description": "pta2svg's browser renderer and its loader, embedded (ADR-0008), so\nthe movement page draws in the tab.",
        "operationId": "get-wasm",
        "responses": {
          "200": {
            "description": "static files"
          }
        },
        "security": [
          {
            "staff_session": []
          },
          {
            "bearer": []
          }
        ],
        "summary": "pta2svg's browser renderer and its loader, embedded (ADR-0008), so the movement page draws in the tab",
        "tags": [
          "Assets"
        ],
        "x-handler": {
          "wrappers": [
            "http.StripPrefix"
          ]
        },
        "x-methods": "any",
        "x-package": "staff",
        "x-prefix": "serves every path under it",
        "x-source": "bff/staff/site.go:729"
      }
    }
  },
  "tags": [
    {
      "description": "whether the server is up, the API document, and not_found for every path no other route serves.",
      "name": "Health",
      "x-package": "bff"
    },
    {
      "description": "the login and the logout.",
      "name": "Customer session",
      "x-package": "bff"
    },
    {
      "description": "the trees the app renders, the login screen open and the rest for a signed-in customer.",
      "name": "Screens",
      "x-package": "bff"
    },
    {
      "description": "the dashboard and its controls, the payments generator and the settings, what gobank-deploy drives.",
      "name": "Simulation",
      "x-package": "staff"
    },
    {
      "description": "the login and the logout, the PII authorisation and the view switch.",
      "name": "Session",
      "x-package": "staff"
    },
    {
      "description": "the profit and loss, the balance sheet and a movement of the ledger.",
      "name": "Accounting",
      "x-package": "staff"
    },
    {
      "description": "the masters (a family's products, the bank's own) and the detail, a parameter's own page, which is also where a staff setting is made (ADR-0010), decided by the signed-in user.",
      "name": "Products",
      "x-package": "staff"
    },
    {
      "description": "the register, the search by name and a customer's detail and accounts.",
      "name": "Customers",
      "x-package": "staff"
    },
    {
      "description": "the list and a payment's detail; the generator that makes them is Simulation's.",
      "name": "Payments",
      "x-package": "staff"
    },
    {
      "description": "the cash position, the capital and the gilts.",
      "name": "Treasury",
      "x-package": "staff"
    },
    {
      "description": "the charts, the BBSI return and a customer as the app shows them.",
      "name": "Reports",
      "x-package": "staff"
    },
    {
      "description": "the project, the models, the documentation, the API and the ADRs; with a console, the runtime and the state another program reads.",
      "name": "About",
      "x-package": "staff"
    },
    {
      "description": "the events, and with a console the explorer, export and import.",
      "name": "Internal",
      "x-package": "staff"
    },
    {
      "description": "the tab icons and pta2svg's browser renderer.",
      "name": "Assets",
      "x-package": "staff"
    }
  ]
}
