defmodule Bloccs.Web.Resolver do @moduledoc """ The integration seam between the dashboard and the host application: who is looking, what they may see, and which features are enabled. A host provides a module implementing this behaviour and passes it to `bloccs_dashboard/2` via `:resolver`. Every callback has a default (see `Bloccs.Web.Access`), so the simplest mount needs no resolver at all. ## The Pro seam `c:resolve_features/1` is how the open-core / Pro split is expressed without any LiveView change: the free build returns every feature, a future licensed build returns a subset, and panels gate themselves with `Bloccs.Web.Access.enabled?/2`. The dashboard ships **only the seam** — no license logic. """ @typedoc "An opaque user term resolved from the connection (whatever the host uses)." @type user :: term() @typedoc """ A coarse access level for the session. The dashboard is observe-only, so the meaningful distinction is full access vs. forbidden. """ @type access :: :all | {:forbidden, reason :: term()} @typedoc "A feature flag the dashboard consults before rendering gated UI." @type feature :: atom() @doc "Resolve the current user from the Plug session map. Defaults to `nil`." @callback resolve_user(session :: map()) :: user() @doc "Resolve the access level for a user. Defaults to `:all`." @callback resolve_access(user()) :: access() @doc """ Resolve the set of enabled features for a user. Defaults to `:all` (every feature on — the free baseline). A licensed build returns an explicit list. """ @callback resolve_features(user()) :: :all | [feature()] @optional_callbacks resolve_user: 1, resolve_access: 1, resolve_features: 1 end