# `Diffo.Provider.BasePlace`
[🔗](https://github.com/diffo-dev/diffo/blob/v0.9.0/lib/diffo/provider/components/base_place.ex#L5)

Ash Resource Fragment which is the foundation for TMF Place subtypes.

`BasePlace` is the foundation for the TMF Place cascade (TMF673–675) — Place is
an abstract TMF concept, and concrete subtype identity lives on the fragments
that compose with it:

  * `Diffo.Provider.BaseGeographicAddress` — TMF673 GeographicAddress fields
    (street_name, postcode, country, …)
  * `Diffo.Provider.BaseGeographicSite` — TMF674 GeographicSite fields
    (site_type, site_code, projected :address ref)
  * `Diffo.Provider.BaseGeographicLocation` — TMF675 GeographicLocation
    fields (accuracy) and tightened geometry validation

Each subtype fragment composes with `BasePlace` on a concrete leaf:

    defmodule MyApp.SydneyExchange do
      use Ash.Resource,
        fragments: [
          Diffo.Provider.BasePlace,
          Diffo.Provider.BaseGeographicSite
        ],
        domain: MyApp.Domain
      # consumer-specific attributes here
    end

Diffo ships the three corresponding concrete leaves out of the box:
`Diffo.Provider.GeographicAddress`, `Diffo.Provider.GeographicSite`,
`Diffo.Provider.GeographicLocation`. Use them directly or as templates
for your own domain leaves.

`Diffo.Provider.Place` is also kept in core but is plumbing (abstract
reader for projection + PlaceRef-typed placeholder support), not a
TMF subtype recommendation. See its moduledoc for details.

## Preferred consumer API

The `Diffo.Provider` domain exposes a type-atom dispatcher that handles
the subtype routing for you:

    Diffo.Provider.create_place!(:GeographicSite, %{...})
    Diffo.Provider.get_place_by_id!(id)    # returns concrete subtype struct via projection

## Attributes

- `id` — string primary key (required, no default — set by domain).
- `href` — optional URI for the place.
- `name` — the place name.
- `type` — TMF `@type`. Defaults to `:PlaceRef`. One of `:PlaceRef`, `:GeographicSite`,
  `:GeographicLocation`, `:GeographicAddress`. When `referred_type` is present, `type` must
  be `:PlaceRef`.
- `referred_type` — TMF `@referredType`. One of `:GeographicSite`, `:GeographicLocation`,
  `:GeographicAddress`. When present, indicates this is a reference to a place of that kind;
  `type` must be `:PlaceRef`.
- `location` — optional `AshGeo.GeoJson` (`:point`, WGS-84) for point-like Places.
  Values are `%Geo.Point{coordinates: {lon, lat}, srid: 4326}`.
- `bounds` — optional `AshGeo.GeoJson` (`:polygon`, WGS-84) for region Places.
  Values are `%Geo.Polygon{coordinates: [ring], srid: 4326}`. Polygon is the wire form;
  axis-aligned-bounding-box is the conventional use today but not type-enforced.
  At most one of `location`/`bounds` may be set on a record, and only when
  `type == :GeographicLocation` (per TMF675).

## Usage

    defmodule MyApp.GeographicSite do
      use Ash.Resource, fragments: [BasePlace], domain: MyApp.Domain

      resource do
        description "A Geographic Site"
        plural_name :geographic_sites
      end

      jason do
        pick [:id, :href, :name, :referred_type, :type]
        compact true
        rename referred_type: "@referredType", type: "@type"
      end

      outstanding do
        expect [:id, :name, :referred_type, :type]
      end

      actions do
        create :build do
          accept [:id, :href, :name]
          change set_attribute(:type, :GeographicSite)
        end
      end
    end

## Domain-specific attributes

Add Ash `attribute` declarations directly to your derived resource for any fields beyond the
base set. Those attributes can only be set via actions you declare on the derived resource —
the base `create` action provided by `BasePlace` only accepts the base fields (`id`, `href`,
`name`, `type`, `referred_type`). Use your domain API to call the derived resource's action:

    defmodule MyApp.DataCentre do
      use Ash.Resource, fragments: [BasePlace], domain: MyApp.Domain

      attributes do
        attribute :tier, :integer, public?: true
        attribute :power_capacity_kw, :integer, public?: true
      end

      actions do
        create :build do
          accept [:id, :href, :name, :tier, :power_capacity_kw]
          change set_attribute(:type, :GeographicSite)
        end
      end
    end

    # Use the domain API — Provider.create_place!/1 does not know about :tier
    MyApp.Domain.create_data_centre!(%{name: "M2", tier: 3, power_capacity_kw: 40_000})

## TMF type and referred_type

The `type` and `referred_type` attributes map to the TMF `@type` and `@referredType` JSON
fields via the jason layer. When `referred_type` is present, `type` must be `:PlaceRef`;
otherwise `type` must not be `:PlaceRef`.

# `extensions`

# `opts`

# `persisted`

# `spark_dsl_config`

# `validate_sections`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
