lib/foundry/project/module.ex

defmodule Foundry.Project.Module do
  @moduledoc """
  Ash resource wrapping the output of `mix foundry.context <Module>`.

  Represents a single module's context: its type, domain, relationships,
  compliance links, test coverage, and agent step declarations.

  Delegates to `Foundry.Context.ProjectContext.build_one/2` for single-module
  lookups and `Foundry.Context.GraphBuilder.build/2` for full enumeration.
  """

  use Ash.Resource,
    domain: nil,
    data_layer: Ash.DataLayer.Simple

  attributes do
    attribute :id, :string do
      description("Fully qualified module name (e.g. 'MyApp.Finance.Wallet').")
      primary_key?(true)
      allow_nil?(false)
    end

    attribute :module, :string do
      description("Fully qualified module name, same as id.")
      allow_nil?(false)
    end

    attribute :type, :atom do
      description("Module type: :resource, :transfer, :rule, :blueprint, :adapter, :live_page, :oban_job.")
      allow_nil?(false)
    end

    attribute :domain, :string do
      description("Parent domain name.")
      allow_nil?(false)
    end

    attribute :app, :string do
      description("App name (for umbrella projects).")
      allow_nil?(true)
    end

    attribute :description, :string do
      description("First paragraph of @moduledoc.")
      allow_nil?(true)
    end

    attribute :sensitive, :boolean do
      description("Whether this module is declared as sensitive in the manifest.")
      default(false)
    end

    attribute :rules, {:array, :string} do
      description("Rule module names applied to this module.")
      default([])
    end

    attribute :compliance, {:array, :string} do
      description("RG-* requirement IDs linked in this module.")
      default([])
    end

    attribute :adrs, {:array, :string} do
      description("ADR IDs referenced in the @moduledoc.")
      default([])
    end

    attribute :runbook, :string do
      description("Path to the runbook file, if one exists.")
      allow_nil?(true)
    end

    attribute :data_layer, :string do
      description("Data layer string (e.g. 'ash_postgres', 'ash_ets').")
      allow_nil?(true)
    end

    attribute :pending_migrations, :boolean do
      description("Whether this module has pending migrations.")
      default(false)
    end

    attribute :paper_trail, :boolean do
      description("Whether AshPaperTrail is enabled.")
      default(false)
    end

    attribute :archival, :boolean do
      description("Whether AshArchival is enabled.")
      default(false)
    end

    attribute :test_coverage, :map do
      description("Test coverage map: %{property_tests, scenario_tests, e2e_tests}.")
      default(%{})
    end

    attribute :state_machine, :map do
      description("State machine metadata if present.")
      default(%{})
    end

    attribute :agent_steps, {:array, :map} do
      description("Agent step declarations for modules with AshAI integration.")
      default([])
    end

    attribute :telemetry_prefix, {:array, :string} do
      description("Telemetry prefix segments.")
      default([])
    end

    attribute :last_modified, :string do
      description("ISO 8601 date of last modification.")
      allow_nil?(true)
    end
  end

  actions do
    defaults [:read]
  end
end