Skip to content

Latest commit

 

History

History
326 lines (236 loc) · 15 KB

File metadata and controls

326 lines (236 loc) · 15 KB

Contributing to Stellar Intel

Thank you for your interest in contributing. This document covers everything you need to get started.


Before You Begin

  • Read the Code of Conduct. All contributors are expected to follow it.
  • For significant changes, open an issue first to discuss the approach before writing code.
  • For bug fixes and small improvements, a pull request is sufficient.

Development Setup

git clone https://github.com/Ezedike-Evan/stellar-intel.git
cd stellar-intel
npm install
cp .env.example .env.local
npm run dev

See README.md for full setup instructions and environment variable reference.


Workflow

  1. Fork the repository and create a branch from main.

  2. Name branches descriptively: feat/sep24-fee-fetching, fix/anchor-rate-display, docs/readme-update.

  3. Make your changes. Keep commits focused — one logical change per commit.

  4. Run checks before pushing. The one-liner is:

    npm run test:release   # format:check + lint + typecheck + test + build

    That covers the whole check CI job except the two generated-file drift gates, which are separate and catch people out:

    npm run emit-openapi && git diff --exit-code -- public/openapi.json

    public/openapi.json is committed, and CI regenerates it and fails on any diff. If you changed an API route or a schema, regenerate and commit the spec in the same commit.

    The same applies to the docs corpus served at /llms-full.txt:

    npm run emit-llms-full && git diff --exit-code -- lib/seo/llms-full.generated.txt

    It is generated from docs/, so editing any doc in the corpus means committing the regenerated file too. npm run build regenerates it for you (it runs in prebuild), so after npm run test:release the file is already updated in your working tree — just commit it.

    If your change touches Rust, Python or a workspace package, see Per-surface checks below — the root commands do not cover them.

  5. Open a pull request against main. Fill in the PR description template.


Code Standards

TypeScript

  • Strict mode is enabled. All code must pass npm run typecheck with zero errors.
  • Prefer explicit types over any. Use unknown when the type is genuinely unknown.
  • Export types from types/ — do not inline complex types in component files.

Components

  • One component per file.
  • Components live in components/. UI primitives live in components/ui/.
  • Keep components focused. If a component exceeds ~150 lines, consider splitting it.

Data Fetching

  • Use SWR hooks from hooks/ for client-side data fetching.
  • Network calls belong in lib/ — not inside components or hooks.
  • No mock data in production code. If real data is unavailable, surface an error state.

Styling

  • Tailwind CSS v4 only. No inline style props unless absolutely necessary.
  • Follow the existing class ordering convention (layout → spacing → typography → colour).

Commits

Follow the Conventional Commits format:

feat: add SEP-24 fee fetching for Cowrie anchor
fix: correct exchange rate computation for NGN corridor
docs: update environment variable reference
refactor: extract anchor TOML resolution into lib/sep1.ts

Types: feat, fix, docs, refactor, test, chore, ci.

Documentation

  • All documentation files in docs/ must carry a **Last reviewed:** YYYY-MM-DD line near the top of the file (immediately after the main heading or header block).
  • Maintainers and contributors should update this date whenever making non-trivial documentation updates or re-verifying accuracy.

Adding a New Anchor

Anchors are defined in constants/anchors.ts (re-exported via constants/index.ts). To add a new anchor:

  1. Add an entry to KNOWN_ANCHORS with the anchor's id, name, domain, supportedCountries, supportedCurrencies, and depositMethods.
  2. The anchor must have a publicly resolvable stellar.toml at https://{domain}/.well-known/stellar.toml.
  3. The stellar.toml must expose a transfer server — TRANSFER_SERVER_SEP0024 (SEP-24) or TRANSFER_SERVER (SEP-6). SEP-6-only anchors are supported; see docs/ANCHOR_ONBOARDING.md.
  4. Verify the anchor's /fee endpoint returns live data before submitting the PR.

Per-surface checks

This repository is no longer a single Next.js app. It spans a TypeScript app, a Soroban contract, a no_std Rust consumer crate, a Python SDK, and three npm workspaces — and the root npm scripts cover only the first. Run the block for whatever you touched.

Root — the Next.js app, lib/, components/, app/

npm run format:check   # prettier, and it covers **/*.md too
npm run lint           # eslint --max-warnings 0
npm run typecheck      # tsc --noEmit
npm run test           # vitest
npm run build
npm run check:registry # anchor registry ⊆ transfer-capable set
npm run emit-openapi && git diff --exit-code -- public/openapi.json
npm run emit-llms-full && git diff --exit-code -- lib/seo/llms-full.generated.txt

contracts/reputation — the Soroban contract

Mirrors the soroban contract (reputation) CI job exactly:

cargo fmt   --manifest-path contracts/reputation/Cargo.toml --check
cargo clippy --manifest-path contracts/reputation/Cargo.toml --all-targets -- -D warnings
cargo test  --manifest-path contracts/reputation/Cargo.toml --locked
cargo build --manifest-path contracts/reputation/Cargo.toml \
  --target wasm32-unknown-unknown --release

clippy runs with -D warnings, so a warning is a build failure.

crates/stellar-intel-reputation — the read-only consumer crate

cargo test --manifest-path crates/stellar-intel-reputation/Cargo.toml --locked
cargo doc  --manifest-path crates/stellar-intel-reputation/Cargo.toml --no-deps
cargo publish --manifest-path crates/stellar-intel-reputation/Cargo.toml --dry-run --locked

The --dry-run publish is in CI, so bumping the crate version means committing the regenerated Cargo.lock alongside it.

This crate is #![no_std] and is linked into wasm32 contracts. Do not add a dependency that needs stdreqwest, tokio and friends will not compile here, and feature-gating them poisons the dependency graph for the contract authors this crate exists for.

packages/python-sdk

cd packages/python-sdk
pip install -e ".[dev]"
pytest
mypy src

Most of this package is generated. src/stellarintel/api/, models/, client.py and types.py come from openapi-python-client generate against public/openapi.json. Only wrapper.py is hand-written. Editing a generated file means your change disappears on the next regeneration — change the spec, or change the wrapper.

packages/publisher, packages/mcp

npm workspaces. Root npm run test picks up packages/*/tests/** automatically (vitest.config.mts excludes only tests/e2e/**), so their unit tests run with the root suite. Building the publisher is a prerequisite of the root typecheck and is wired into pretypecheck/prebuild, so you rarely invoke it directly:

npm run build --workspace=@stellarintel/publisher

Which surface does my change touch?

You changed… Run
app/, components/, lib/, hooks/ Root block
An API route or a zod schema Root block including the OpenAPI gate
constants/anchors.ts Root block including check:registry
contracts/reputation/ Root block + contract block
crates/stellar-intel-reputation/ Consumer crate block
packages/publisher/, packages/mcp/ Root block (their tests run with it)
packages/python-sdk/ Python block
Any *.md npm run format:check — prettier covers docs

Pull Request Checklist

  • npm run test:release passes (format, lint, typecheck, test, build)
  • npm run emit-openapi produces no diff, or the regenerated spec is committed
  • npm run emit-llms-full produces no diff, or the regenerated corpus is committed
  • Rust: cargo fmt --check, cargo clippy -- -D warnings, cargo test pass for every crate touched
  • Python: pytest and mypy pass, and no generated file was hand-edited
  • Documentation files in docs/ carry an updated **Last reviewed:** YYYY-MM-DD date
  • No isMock, // MOCK, or hardcoded rate values added
  • New anchor entries include a verified stellar.toml domain
  • Exactly one Closes #N keyword — reference other issues without one
  • PR description explains what changed and why

Issue Numbering & Label Conventions

This repo uses several namespaces to organise work across waves, modules, and documentation debt. Understanding them helps you navigate the issue tracker and write PRs that auto-link correctly.

Issue numbering

Prefix Range Purpose
#001–#250 Main tracker Wave-scoped engineering tickets (see docs/ROADMAP.md).
#B001–#B100 Batch 2 Supplementary issues from issues-batch-2.md.
#W1.1–W7.x Wave issues Per-workstream milestone issues from WAVE_ISSUES.md.
#D001–D999 Doc/infra debt Documentation gaps, infra improvements, and technical-debt tickets that don't fit a wave. Sometimes referenced as #D047 inline in code comments.
#N/A Meta Issues opened against the issue tracker itself (template improvements, workflow changes).

A PR title like fix: correct exchange rate computation for NGN corridor will auto-close an issue when the body contains Closes #NNN.

Label taxonomy

Labels are the single source of truth for issue triage. They are defined in .github/labels.yml and synced to GitHub by .github/workflows/label-sync.yml. The taxonomy follows these rules:

  • Lower-case, hyphenated, namespaced with / — e.g. module/oracle, epic/reputation.
  • One concern per namespace. A label belongs to exactly one category (type, state, difficulty, wave, epic, module).
  • State labels are flatblocked, help-wanted, design-review.
Category Examples Purpose
Type bug, feature, docs, chore, refactor, test What kind of change the issue represents. Every issue has exactly one type label.
State blocked, help-wanted, good-first-issue, design-review, needs-triage Workflow status. Applied and removed as the issue progresses.
Difficulty difficulty/good-first-issue, difficulty/intermediate, difficulty/hard Estimated effort. Set by a maintainer during triage.
Wave wave/1.0, wave/2.0, wave/2.1 Which milestone the issue belongs to. Maps to docs/ROADMAP.md.
Epic epic/execution-layer, epic/reputation, epic/agents, epic/anchor-integration, epic/ui, epic/docs-community High-level theme the issue contributes to.
Module module/oracle, module/router, module/reputation, module/mcp, module/api, module/ui, module/sep10, module/sep24, module/sep38 Which subsystem the change lands in. Helps route PRs to the right reviewer.
Meta release, dependencies, size/xssize/xl Release tracking, dependency updates, and PR size estimation.

D-numbering (documentation & infra debt)

D-prefixed issues (#D001, #D002, …) track documentation gaps and infrastructure improvements that are not visible to end users but affect contributor experience, maintainability, or operator workflows. They follow the same triage process as numbered issues but live in a separate namespace so they can be planned independently of feature work.

Examples from the codebase:

  • #D002 — Uptime probe ledger
  • #D005 — Quote-latency probe
  • #D006 — Quote-drift probe
  • #D014 — Sentry / dead-letter alert sink
  • #D035 — SEP-24 live execution flow e2e test
  • #D047 — Rate-limit audit follow-up
  • #D060 / #746 — Plausible analytics integration

When referencing a D-issue in code, use the pattern:

// ─── Uptime / quote-latency probe ledger (Issue #D002 / #D005) ────────────────

Branch naming

Branches should be named descriptively:

  • feat/<short-description> — new capabilities
  • fix/<short-description> — bug fixes
  • docs/<short-description> — documentation changes
  • chore/<short-description> — build, tooling, deps
  • refactor/<short-description> — code structure changes with no behaviour change

"One issue per PR" rule

Every PR must link exactly one issue with a closing keyword (Closes, Fixes, Resolves). This ensures:

  1. Issues auto-close on merge.
  2. The changelog generator picks up a clean mapping.
  3. Reviews stay scoped.

If a change genuinely spans multiple issues (rare), close the primary issue and reference the others in the PR body. Never leave a Closes # line unfilled or filled with an example number.


Questions

Open an issue with the question label.