# Узел Ostalari в локальной сети заведения: один порт, без домена и без HTTPS.
# Публичных функций у локальной копии нет, поэтому наружу узел не выставляется.
:80 {
  encode zstd gzip

  # Консоль Keycloak владельцу заведения не нужна: сотрудников заводят в самой кассе.
  @keycloakBlocked path /auth/admin* /auth/realms/master*
  respond @keycloakBlocked 403

  # Корень на узле — рабочее место, а не сайт для гостей.
  @root path /
  redir @root /login 302

  @keycloak path /auth /auth/*
  reverse_proxy @keycloak keycloak:8080
  reverse_proxy app:3000

  # Касса перезапускается при обновлении (15.10.2026): запросам программы — JSON {updating:true}, по нему открытая страница
  # показывает плашку с таймером (public/update-screen.js); остальным — короткая страница, она обновляется сама.
  handle_errors {
    @apiDown {
      expression `{err.status_code} >= 502 && {err.status_code} <= 504`
      path /api/* /health
    }
    handle @apiDown {
      header Content-Type "application/json; charset=utf-8"
      header Cache-Control no-store
      respond `{"error":"Идёт обновление — это займёт около минуты. Повторите чуть позже.","updating":true}` 503
    }
    @pageDown expression `{err.status_code} >= 502 && {err.status_code} <= 504`
    handle @pageDown {
      header Content-Type "text/html; charset=utf-8"
      header Cache-Control no-store
      respond `<!doctype html><html lang="ru"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="refresh" content="5"><title>Идёт обновление</title><body style="margin:0;display:grid;place-items:center;min-height:100vh;padding:16px;box-sizing:border-box;font:16px/1.45 system-ui,sans-serif;text-align:center"><div><h1 style="margin:0 0 6px;font-size:22px">Идёт обновление</h1><p style="margin:0;color:#475569">Обычно это меньше минуты. Страница откроется сама.</p></div></body></html>` 503
    }
  }
}
