BUCKYVERSE

Date: 2025-03-10

Status

Proposed

Context

The Codexis system requires robust metadata management through YAML files (meta.yaml and config.yaml). The metadata system needs to handle:

  1. Book metadata (title, author, ISBN, etc.)
  2. Build configuration
  3. Format-specific settings
  4. Cover image specifications
  5. Asset management configuration

Decision

We will implement a comprehensive metadata management system with the following components:

1. YAML Schema Definition

defmodule Codexis.Metadata.Schema do
  @metadata_schema %{
    # Book Metadata
    title: [type: :string, required: true],
    subtitle: [type: :string],
    author: [type: :string, required: true],
    publisher: [type: :string, required: true],
    isbn: [type: :string, required: true, format: ~r/^\d{13}$/],
    language: [type: :string, required: true],
    publication_date: [type: :date, required: true],
    
    # Cover Image
    cover: %{
      path: [type: :string, required: true],
      formats: [
        type: {:list, :string},
        allowed_values: ["jpg", "png", "pdf"],
        required: true
      ]
    },
    
    # Format Settings
    formats: %{
      pdf: [type: :map, default: %{}],
      epub: [type: :map, default: %{}],
      mobi: [type: :map, default: %{}],
      kfx: [type: :map, default: %{}],
      wikijs: [type: :map, default: %{}]
    }
  }
  
  def schema, do: @metadata_schema
end

2. Metadata Loading and Validation

defmodule Codexis.Metadata.Loader do
  def load_metadata(meta_path, config_path) do
    with {:ok, meta_yaml} <- YamlElixir.read_from_file(meta_path),
         {:ok, config_yaml} <- YamlElixir.read_from_file(config_path),
         {:ok, merged} <- merge_metadata(meta_yaml, config_yaml),
         :ok <- validate_metadata(merged) do
      {:ok, merged}
    end
  end
  
  defp merge_metadata(meta, config) do
    # Deep merge strategy
    {:ok, DeepMerge.deep_merge(meta, config)}
  end
  
  defp validate_metadata(metadata) do
    case Vex.validate(metadata, Codexis.Metadata.Schema.schema()) do
      {:ok, _} -> :ok
      {:error, errors} -> {:error, format_errors(errors)}
    end
  end
end

3. Format-Specific Transformations

defmodule Codexis.Metadata.FormatTransformer do
  def transform_for_format(metadata, format) do
    base = get_base_metadata(metadata)
    format_specific = get_format_metadata(metadata, format)
    
    merge_and_transform(base, format_specific, format)
  end
  
  defp merge_and_transform(base, format_specific, :pdf) do
    # PDF-specific transformation
  end
  
  defp merge_and_transform(base, format_specific, :wikijs) do
    # WikiJS-specific transformation
  end
  
  # Other format transformations...
end

4. Cover Image Processing

defmodule Codexis.Metadata.CoverProcessor do
  def process_cover(metadata) do
    with {:ok, cover_path} <- get_cover_path(metadata),
         {:ok, formats} <- get_cover_formats(metadata) do
      generate_cover_variants(cover_path, formats)
    end
  end
  
  defp generate_cover_variants(path, formats) do
    formats
    |> Task.async_stream(fn format ->
      generate_cover_variant(path, format)
    end)
    |> Enum.reduce(%{}, fn {:ok, {format, path}}, acc ->
      Map.put(acc, format, path)
    end)
  end
end

5. Metadata Access API

defmodule Codexis.Metadata do
  def get(key, metadata) do
    get_in(metadata, List.wrap(key))
  end
  
  def get!(key, metadata) do
    case get(key, metadata) do
      nil -> raise KeyError, "key #{inspect(key)} not found in metadata"
      value -> value
    end
  end
  
  def update(key, value, metadata) do
    put_in(metadata, List.wrap(key), value)
  end
end

Consequences

Positive

  1. Validation: Strong schema validation ensures metadata integrity
  2. Flexibility: Easy to add new metadata fields and validations
  3. Transformation: Clean separation of format-specific transformations
  4. Cover Management: Integrated cover image processing
  5. API: Simple, consistent metadata access

Negative

  1. Complexity: More complex than simple YAML parsing
  2. Performance: Additional validation and transformation overhead
  3. Dependencies: Requires multiple dependencies (yaml_elixir, vex, etc.)

Risks

  1. Schema Evolution: Need strategy for handling schema changes
  2. Backward Compatibility: Must maintain compatibility with existing metadata
  3. Performance Impact: Monitor validation and transformation overhead

Compliance

Metadata handling must:

  1. Validate against defined schema
  2. Transform appropriately for each format
  3. Handle cover image processing
  4. Maintain backward compatibility
  5. Report validation errors clearly

Notes