Search documentation of macula

# Development Guide

View Source

This guide covers setting up a development environment for contributing to Macula.

## Prerequisites

- Erlang/OTP 26+ - Installation Guide
- Rebar3 - Erlang build tool (Installation)
- Git - Version control
- Docker (optional) - For multi-node testing

## Quick Setup

    # Clone the repository
    git clone https://codeberg.org/macula-io/macula.git
    cd macula

    # Fetch dependencies
    rebar3 get-deps

    # Compile
    rebar3 compile

    # Run tests
    rebar3 eunit

    # Start a shell with Macula loaded
    rebar3 shell

## Project Structure

Macula SDK is organized as a single Erlang/OTP library with 48 modules:

    macula/
    ├── src/                          # Source code (48 .erl files)
    │   ├── macula.erl               # Public facade (connect, subscribe, publish, call, advertise)
    │   ├── macula_relay_client.erl  # QUIC relay connection
    │   ├── macula_multi_relay.erl   # Multi-homed connections
    │   ├── macula_quic.erl          # QUIC transport abstraction
    │   ├── macula_protocol_*.erl    # Wire protocol encoding/decoding
    │   ├── macula_crypto_nif.erl    # Ed25519, BLAKE3, SHA-256 (Rust NIF + Erlang fallback)
    │   ├── macula_ucan_nif.erl      # UCAN token operations (Rust NIF + Erlang fallback)
    │   ├── macula_did_nif.erl       # DID document operations (Rust NIF + Erlang fallback)
    │   ├── macula_mri.erl           # Resource identifiers (parse, format, hierarchy, trie index)
    │   ├── macula_cert_system/      # Ed25519 keypairs, cert generation, trust store
    │   ├── macula_dist_system/      # Erlang distribution over relay mesh
    │   └── macula_*.erl             # Utilities (id, names, node, realm, time, uri, cache)
    ├── native/                       # Rust NIF source (Quinn QUIC + crypto/UCAN/DID/MRI)
    ├── test/                         # EUnit tests
    ├── include/                      # Header files (.hrl)
    ├── docs/                         # SDK guides
    ├── priv/                         # Build scripts, precompiled NIFs
    └── rebar.config                  # Build configuration

Server modules (gateway, DHT routing, RPC/PubSub routing, SWIM, peering, etc.) live in macula-station.

## Running Tests

### All Tests

    rebar3 eunit

### Specific Module Tests

    rebar3 eunit --module=macula_mri_tests
    rebar3 eunit --module=macula_crypto_nif_tests

### Test Coverage

    rebar3 do eunit, cover

### Multi-Node Integration Tests

    cd docker
    docker compose -f docker-compose.multi-node-test.yml build --no-cache
    docker compose -f docker-compose.multi-node-test.yml up

## Code Quality Standards

Macula follows Idiomatic Erlang principles:

### Core Principles

- ✅ Pattern matching on function heads - Avoid `if` and `cond`
- ✅ Guards instead of case - Use guards for simple conditions
- ✅ Shallow nesting - Keep nesting to 1-2 levels maximum
- ✅ Let it crash - Don't catch errors unless you can handle them meaningfully
- ✅ OTP behaviors - Use gen_server, gen_statem, supervisor where appropriate

### Example: Good vs. Bad

❌ Bad:

    process_message(Msg, State) ->
        if
            is_binary(Msg) ->
                case decode_message(Msg) of
                    {ok, Data} ->
                        if
                            Data#data.type == request ->
                                handle_request(Data, State);
                            Data#data.type == response ->
                                handle_response(Data, State)
                        end
                end
        end.

✅ Good:

    %% Guard ensures binary input
    process_message(Msg, State) when is_binary(Msg) ->
        case decode_message(Msg) of
            {ok, Data} -> handle_decoded_message(Data, State);
            {error, Reason} -> {error, Reason}
        end;
    process_message(_Msg, _State) ->
        {error, invalid_message}.

    %% Pattern match on data type
    handle_decoded_message(#data{type = request} = Data, State) ->
        handle_request(Data, State);
    handle_decoded_message(#data{type = response} = Data, State) ->
        handle_response(Data, State).

See CLAUDE.md (at repository root) for complete coding guidelines.

## Building Documentation

Macula uses ex_doc for documentation generation:

    rebar3 ex_doc

Generated docs appear in `doc/` directory. Open `doc/index.html` in a browser.

## Rust NIFs

The SDK includes Rust NIFs for performance-critical operations. They build automatically via `priv/build-nifs.sh` during `rebar3 compile`. Requires a Rust toolchain (`cargo`). If Rust is not available, pure Erlang fallbacks are used.

NIF Crate | Provides
--- | ---
`native/macula_quic/` | Quinn QUIC transport (precompiled download available)
`native/macula_crypto_nif/` | Ed25519, BLAKE3, SHA-256
`native/macula_ucan_nif/` | UCAN token create/verify
`native/macula_did_nif/` | DID document operations
`native/macula_mri_nif/` | MRI parsing, trie index

## Contributing Workflow

1. Read the documentation

   - README.md (at repository root) - Project overview
   - CLAUDE.md (at repository root) - Coding guidelines

2. Create a feature branch

       git checkout -b feature/your-feature-name

3. Write tests first (TDD approach preferred)

       # Create test file
       touch test/macula_your_module_tests.erl

       # Write failing tests
       # Implement functionality
       # Verify tests pass
       rebar3 eunit --module=macula_your_module_tests

4. Follow code quality standards

   - Pattern matching over conditionals
   - Guards instead of case where possible
   - Maximum 1-2 levels of nesting
   - Comprehensive tests for new functionality

5. Commit and push

       git add .
       git commit -m "Add feature: your feature description"
       git push origin feature/your-feature-name

6. Create pull request

   - Describe what the PR does
   - Reference any related issues
   - Ensure all tests pass
   - Follow PR template guidelines

## Getting Help

- Issues: GitHub Issues
- Documentation: See `architecture/` directory for detailed architecture docs

← Back to Documentation

← Previous Page MRI (Resource Identifiers)
Next Page → Migration: V1 → V2 Pub/Sub