defmodule Localiser.Web.Router do use Phoenix.Router, helpers: false alias Localiser.Web.Plugs.{AuthRequired, AdminRequired, BootstrapGuard} pipeline :api do plug :accepts, ["json"] end pipeline :authenticated do plug :accepts, ["json"] plug AuthRequired end pipeline :admin do plug :accepts, ["json"] plug AuthRequired plug AdminRequired end pipeline :bootstrap do plug :accepts, ["json"] plug BootstrapGuard end # OpenAPI spec (unauthenticated) scope "/api" do pipe_through :api get "/openapi", OpenApiSpex.Plug.RenderSpec, [] end # First-boot setup - forbidden once any user exists scope "/api", Localiser.Web.Controllers do pipe_through :bootstrap post "/setup", SetupController, :create end # Auth - public scope "/api", Localiser.Web.Controllers do pipe_through :api post "/session", SessionController, :create delete "/session", SessionController, :delete end # Onboarding status - public scope "/api", Localiser.Web.Controllers do pipe_through :api get "/onboarding", OnboardingController, :status end # Firmware download - public (ESP32 devices fetch without auth) scope "/api", Localiser.Web.Controllers do pipe_through :api get "/firmware/:version", FirmwareController, :download end # User self-service (show own profile) scope "/api", Localiser.Web.Controllers do pipe_through :authenticated get "/users/me", UserController, :me end # Firmware management - admin only scope "/api", Localiser.Web.Controllers do pipe_through :admin get "/firmware", FirmwareController, :index post "/firmware", FirmwareController, :upload post "/firmware/:version/ota", FirmwareController, :ota_fleet post "/firmware/:version/ota/instant", FirmwareController, :ota_fleet_instant post "/sensors/:id/ota", SensorController, :ota end # User admin CRUD scope "/api", Localiser.Web.Controllers do pipe_through :admin get "/users", UserController, :index get "/users/:id", UserController, :show post "/users", UserController, :create put "/users/:id", UserController, :update delete "/users/:id", UserController, :delete put "/users/:id/admin", UserController, :promote end # Floors / Rooms / Tags - auth required scope "/api", Localiser.Web.Controllers do pipe_through :authenticated resources "/floors", FloorController, except: [:new, :edit] resources "/floors/:floor_id/rooms", RoomController, except: [:new, :edit] get "/tags/occupancy", TagController, :occupancy resources "/tags", TagController, except: [:new, :edit] # Sensors post "/sensors", SensorController, :enroll get "/sensors", SensorController, :index get "/sensors/unplaced", SensorController, :unplaced get "/sensors/:id", SensorController, :show put "/sensors/:id", SensorController, :update delete "/sensors/:id", SensorController, :delete put "/sensors/:id/place", SensorController, :place delete "/sensors/:id/place", SensorController, :unplace post "/sensors/:id/factory_reset", SensorController, :factory_reset post "/sensors/:id/reconfigure", SensorController, :reconfigure post "/sensors/:id/calibration/begin", SensorController, :calibration_begin post "/sensors/:id/calibration/stage", SensorController, :calibration_stage_start post "/sensors/:id/calibration/finish", SensorController, :calibration_finish delete "/sensors/:id/calibration", SensorController, :calibration_cancel get "/sensors/:id/version", SensorController, :get_version end end