From c4023fc959cd99e8ea4c8a1ede6d40d259ea0fc4 Mon Sep 17 00:00:00 2001 From: adebayodeolu Date: Sat, 25 Apr 2026 20:04:52 +0000 Subject: [PATCH] docs: add comprehensive architecture decision records (#359) --- docs/adr/0001-soroban-rust-smart-contracts.md | 81 ++++++++++++++ docs/adr/0002-tokenized-learning-rewards.md | 73 ++++++++++++ docs/adr/0003-cross-chain-bridge-design.md | 78 +++++++++++++ docs/adr/0004-indexer-technology-selection.m | 73 ++++++++++++ docs/adr/0005-observability-stack.md | 79 +++++++++++++ docs/adr/README.md | 104 ++++++++++++++++++ docs/adr/template.md | 71 ++++++++++++ 7 files changed, 559 insertions(+) create mode 100644 docs/adr/0001-soroban-rust-smart-contracts.md create mode 100644 docs/adr/0002-tokenized-learning-rewards.md create mode 100644 docs/adr/0003-cross-chain-bridge-design.md create mode 100644 docs/adr/0004-indexer-technology-selection.m create mode 100644 docs/adr/0005-observability-stack.md create mode 100644 docs/adr/README.md create mode 100644 docs/adr/template.md diff --git a/docs/adr/0001-soroban-rust-smart-contracts.md b/docs/adr/0001-soroban-rust-smart-contracts.md new file mode 100644 index 00000000..95b95765 --- /dev/null +++ b/docs/adr/0001-soroban-rust-smart-contracts.md @@ -0,0 +1,81 @@ +# ADR-0001: Use Soroban (Rust) for Smart Contract Development + +**Status:** Accepted +**Date:** 2024-01-15 +**Authors:** [@rinafcode] +**Reviewers:** [@rinafcode] +**Tags:** contract, infrastructure + +--- + +## Context + +TeachLink requires a smart contract platform to manage tokenized learning rewards, proof-of-participation records, and educator incentive payouts. The contract must be auditable, deterministic, and deployable on a network with low transaction fees suitable for micro-reward use cases. + +Several smart contract platforms were available at the time of this decision. The choice of platform determines the programming language, toolchain, deployment target, and long-term maintenance burden. + +Key constraints: + +- Micro-transactions (reward payouts as small as fractions of a token) require negligible fees +- The team has existing experience with Rust systems programming +- The contract surface area is large (bridge, escrow, rewards, reputation, assessment modules), so type safety and compile-time correctness guarantees are important +- Long-term auditability matters; the contract code must be readable and verifiable by external reviewers + +## Decision + +We will write TeachLink's smart contracts in Rust targeting the Soroban platform on the Stellar network. All contract modules (bridge, escrow, tokenization, rewards, reputation, assessment, emergency, audit, analytics, reporting, backup) will be compiled to `wasm32-unknown-unknown` and deployed as a single Soroban contract. + +## Alternatives Considered + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Solidity on EVM (Ethereum / Polygon) | Gas fees unsuitable for micro-reward transactions; EVM bytecode harder to audit than Rust source; team preference for Rust type system | +| Move on Aptos / Sui | Ecosystem too early at decision time; limited tooling and auditor familiarity; cross-chain bridge support was less mature | +| CosmWasm (Rust on Cosmos) | Viable technically, but Stellar's Horizon API and SEP standards provide better fiat on/off-ramp integrations needed for educator payouts | +| Ink! on Substrate | Strong Rust support, but Polkadot parachain deployment complexity was disproportionate to the project's scale | + +## Consequences + +### Positive + +- Rust's type system eliminates entire classes of contract bugs at compile time +- `cargo test` and `cargo clippy` integrate naturally into CI, giving immediate feedback on contract correctness +- Soroban's WASM execution environment is deterministic and sandboxed +- Stellar's low fee model supports the micro-reward use cases central to TeachLink +- The `wasm32-unknown-unknown` target produces compact, verifiable artifacts + +### Negative / Trade-offs + +- Soroban is a relatively new platform; the ecosystem of third-party libraries and auditors is smaller than EVM +- Cross-chain bridge to EVM networks requires a custom bridge module, adding significant complexity +- Windows development requires additional setup (MSVC toolchain or Docker) due to WASM linker limitations on MinGW + +### Neutral + +- The `wasm32-unknown-unknown` compile target is separate from native test compilation; developers must be aware of the two-target workflow (`cargo build --target wasm32-unknown-unknown` vs `cargo test`) + +## Implementation Notes + +**Affected modules:** + +- `contracts/teachlink/` (entire contract workspace) + +**Build command:** + +```bash +cargo build --release --target wasm32-unknown-unknown -p teachlink-contract +``` + +**Related issues / PRs:** Initial project setup + +--- + +## Review Checklist + +- [x] Context accurately describes the problem without solution bias +- [x] Decision is stated clearly and unambiguously +- [x] At least two alternatives are documented with rejection rationale +- [x] Consequences cover both positive and negative outcomes +- [x] Status field is set correctly +- [x] Tags accurately reflect the domain +- [x] Linked to the relevant GitHub issue or PR \ No newline at end of file diff --git a/docs/adr/0002-tokenized-learning-rewards.md b/docs/adr/0002-tokenized-learning-rewards.md new file mode 100644 index 00000000..5c81e493 --- /dev/null +++ b/docs/adr/0002-tokenized-learning-rewards.md @@ -0,0 +1,73 @@ +# ADR-0002: Tokenized Learning Rewards Architecture + +**Status:** Accepted +**Date:** 2024-02-10 +**Authors:** [@rinafcode] +**Reviewers:** [@rinafcode] +**Tags:** contract, platform + +--- + +## Context + +TeachLink's core value proposition is rewarding learners and educators with on-chain tokens tied to verifiable learning activity. The contract must mint, distribute, and track reward tokens in a way that is transparent, resistant to manipulation, and useful as a credential signal (proof-of-participation). + +Design questions at the time of this decision: + +- Should rewards use a custom token standard or the Stellar Asset Contract (SAC)? +- Should participation proofs be stored on-chain or referenced via content-addressed hashes? +- How should educator incentives be structured relative to learner rewards to prevent gaming? + +## Decision + +We will implement the rewards module as a contract-native distribution system that issues reward tokens through the `rewards` module and records proof-of-participation as on-chain events (Soroban contract events) rather than storing full participation data in contract storage. Educator incentives will be handled through a separate escrow module that releases funds upon verified learner milestone completion, not upon content upload. + +## Alternatives Considered + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Store full participation records in contract storage | Contract storage on Soroban is metered and expensive for large payloads; event-based proofs are sufficient for auditability and cheaper to emit | +| Educator rewards on content upload | Creates perverse incentive to flood the platform with low-quality content; milestone-based release ties educator payout to actual learner success | +| Use only Stellar Classic assets (no SAC / contract layer) | Lacks programmable distribution logic; cannot encode conditional releases or reputation-weighted rewards | + +## Consequences + +### Positive + +- Proof-of-participation events are permanent, publicly verifiable, and indexable by the TypeScript indexer layer +- Escrow-based educator incentives align educator success with learner outcomes +- Keeping participation data off-chain storage (in events) keeps contract storage footprint small and predictable +- The separation of `rewards`, `escrow`, and `tokenization` modules allows each to be upgraded or audited independently + +### Negative / Trade-offs + +- Soroban events are not queryable from within the contract itself; external consumers (indexer) must subscribe and store event history for queries +- Escrow release logic requires reliable milestone verification; an oracle or off-chain verifier must signal completion, introducing a trust assumption + +### Neutral + +- The event-based participation record means the indexer is a required component for any UI that displays learning history; the contract alone is not sufficient for a full product experience + +## Implementation Notes + +**Affected modules:** + +- `contracts/teachlink/rewards` +- `contracts/teachlink/escrow` +- `contracts/teachlink/tokenization` +- `contracts/teachlink/reputation` +- `indexer/` (event subscription and storage) + +**Related issues / PRs:** # + +--- + +## Review Checklist + +- [x] Context accurately describes the problem without solution bias +- [x] Decision is stated clearly and unambiguously +- [x] At least two alternatives are documented with rejection rationale +- [x] Consequences cover both positive and negative outcomes +- [x] Status field is set correctly +- [x] Tags accurately reflect the domain +- [x] Linked to the relevant GitHub issue or PR \ No newline at end of file diff --git a/docs/adr/0003-cross-chain-bridge-design.md b/docs/adr/0003-cross-chain-bridge-design.md new file mode 100644 index 00000000..e235eebf --- /dev/null +++ b/docs/adr/0003-cross-chain-bridge-design.md @@ -0,0 +1,78 @@ +# ADR-0003: Cross-Chain Bridge Design + +**Status:** Accepted +**Date:** 2024-03-05 +**Authors:** [@rinafcode] +**Reviewers:** [@rinafcode] +**Tags:** contract, cross-chain, security + +--- + +## Context + +TeachLink operates on Stellar/Soroban, but learners and educators may hold assets or identities on other networks (EVM chains, in particular). To avoid locking users into a single chain, TeachLink needs a mechanism to bridge assets and credential signals between Stellar and external blockchains. + +A bridge introduces significant security surface area: bridge contracts are among the most frequently exploited components in the broader blockchain ecosystem. The design must balance interoperability with security and auditability. + +Key constraints: + +- The bridge must not require a trusted single operator (single point of failure / centralization risk) +- Slashing conditions must exist to punish malicious or faulty validators +- The design must be extensible to additional chains beyond the initial target + +## Decision + +We will implement the bridge as a BFT (Byzantine Fault Tolerant) multi-validator consensus module within the TeachLink contract. The `bridge` module handles asset lock/unlock on the Stellar side, the `bft_consensus` module manages validator set and quorum logic, and the `slashing` module enforces penalties for misbehavior. Liquidity management across chains is handled by the `liquidity` module. + +No single validator can unilaterally authorize a cross-chain transfer; a quorum signature is required. + +## Alternatives Considered + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Use an existing third-party bridge (e.g., Wormhole, Axelar) | Introduces external dependency and trust assumptions on a third-party protocol; limits control over slashing and dispute resolution logic | +| Trusted relayer (single operator) | Single point of failure; compromised relayer key results in total bridge loss; unacceptable for a platform managing educator and learner funds | +| Optimistic bridge with fraud proofs | Introduces a challenge window (latency) that degrades UX for micro-transactions; more complex to implement correctly in Soroban's execution model | + +## Consequences + +### Positive + +- BFT consensus eliminates single-point-of-failure risk at the bridge layer +- Slashing creates economic incentives for validators to behave correctly +- The modular design (`bridge`, `bft_consensus`, `slashing`, `multichain`, `liquidity`) allows each component to be tested and audited in isolation +- Extensible to additional chains by adding new chain adapters to the `multichain` module + +### Negative / Trade-offs + +- Building and maintaining a custom BFT consensus module is significantly more complex than delegating to a third-party bridge +- Validator set management (onboarding, rotation, slashing) requires ongoing operational overhead +- BFT consensus requires a minimum validator set size to be meaningful; a small or poorly distributed validator set reduces the security guarantees + +### Neutral + +- Cross-chain transfers have higher latency than native Stellar transactions due to the consensus round requirement; this is expected and documented for users + +## Implementation Notes + +**Affected modules:** + +- `contracts/teachlink/bridge` +- `contracts/teachlink/bft_consensus` +- `contracts/teachlink/slashing` +- `contracts/teachlink/multichain` +- `contracts/teachlink/liquidity` + +**Related issues / PRs:** # + +--- + +## Review Checklist + +- [x] Context accurately describes the problem without solution bias +- [x] Decision is stated clearly and unambiguously +- [x] At least two alternatives are documented with rejection rationale +- [x] Consequences cover both positive and negative outcomes +- [x] Status field is set correctly +- [x] Tags accurately reflect the domain +- [x] Linked to the relevant GitHub issue or PR \ No newline at end of file diff --git a/docs/adr/0004-indexer-technology-selection.m b/docs/adr/0004-indexer-technology-selection.m new file mode 100644 index 00000000..f68a0828 --- /dev/null +++ b/docs/adr/0004-indexer-technology-selection.m @@ -0,0 +1,73 @@ +# ADR-0004: Indexer Technology Selection (TypeScript / NestJS) + +**Status:** Accepted +**Date:** 2024-03-20 +**Authors:** [@rinafcode] +**Reviewers:** [@rinafcode] +**Tags:** indexer, infrastructure + +--- + +## Context + +The TeachLink smart contract emits Soroban events for all significant state changes (reward distributions, escrow releases, participation proofs, bridge transfers). These events are not directly queryable from within the contract or via simple RPC calls in a structured way. A separate indexer process is needed to subscribe to Soroban events, transform them, store them in a queryable database, and expose them to client applications via an API. + +The indexer is an optional but practically required component for any production UI. It also hosts the recommendation and analytics features that are not feasible to run on-chain. + +Key constraints: + +- Must integrate with Stellar Horizon and Soroban RPC event subscription endpoints +- Must support long-running background processes (event listeners, retry logic) +- The team has more TypeScript experience than Go or Python for service development + +## Decision + +We will implement the indexer as a TypeScript/NestJS service. NestJS provides a structured module and dependency injection system suitable for a long-running service with multiple subsystems (event ingestion, storage, API, monitoring). The service subscribes to Soroban events via the Stellar SDK and stores processed data in a PostgreSQL database. + +## Alternatives Considered + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Go service | Strong concurrency model, but team TypeScript familiarity is higher; NestJS module structure maps well to the multi-feature indexer design | +| Python (FastAPI / Celery) | Viable, but async event processing patterns in Python are less ergonomic than TypeScript; type safety weaker without strict mypy enforcement | +| The Graph protocol | Designed primarily for EVM chains; Soroban subgraph support was not mature at decision time | +| Rust (same language as contract) | Would maximize code sharing for type definitions, but NestJS ecosystem provides more out-of-the-box tooling for REST APIs, background jobs, and observability integration | + +## Consequences + +### Positive + +- NestJS's module system naturally maps to TeachLink's multi-feature architecture (one module per contract feature domain) +- TypeScript's type system allows sharing schema types between indexer and frontend clients +- Large ecosystem of Stellar JavaScript/TypeScript SDKs (`@stellar/stellar-sdk`) +- NestJS integrates well with Prometheus metrics exporters used in the observability stack (ADR-0005) + +### Negative / Trade-offs + +- TypeScript/Node.js has higher memory overhead than Go or Rust for long-running processes +- The indexer introduces a separate runtime dependency; operators must manage both the contract deployment and the indexer service +- Schema drift between on-chain event payloads and indexer DTOs must be managed carefully (see `NAMING_CONVENTIONS.md`) + +### Neutral + +- The indexer is architecturally optional; the contract functions correctly without it, but the full product experience (learning history, analytics, recommendations) requires it + +## Implementation Notes + +**Affected modules:** + +- `indexer/` (entire indexer workspace) + +**Related issues / PRs:** # + +--- + +## Review Checklist + +- [x] Context accurately describes the problem without solution bias +- [x] Decision is stated clearly and unambiguously +- [x] At least two alternatives are documented with rejection rationale +- [x] Consequences cover both positive and negative outcomes +- [x] Status field is set correctly +- [x] Tags accurately reflect the domain +- [x] Linked to the relevant GitHub issue or PR \ No newline at end of file diff --git a/docs/adr/0005-observability-stack.md b/docs/adr/0005-observability-stack.md new file mode 100644 index 00000000..bc96c6f3 --- /dev/null +++ b/docs/adr/0005-observability-stack.md @@ -0,0 +1,79 @@ +# ADR-0005: Observability Stack (Prometheus, Alertmanager, Grafana) + +**Status:** Accepted +**Date:** 2024-04-08 +**Authors:** [@rinafcode] +**Reviewers:** [@rinafcode] +**Tags:** infrastructure, indexer + +--- + +## Context + +The TeachLink indexer is a long-running service with several subsystems (event ingestion, API, background jobs). Production incidents on an event-driven system are hard to diagnose without visibility into throughput, lag, error rates, and resource usage. + +Additionally, the Soroban contract itself emits telemetry-relevant events (reward distributions, escrow state changes, bridge operations) that should be surfaced to operators for health monitoring. + +An observability stack must be chosen that: + +- Collects and stores time-series metrics from the indexer runtime +- Provides alerting for anomalies (ingestion lag, high error rates, validator slashing events) +- Offers dashboards accessible to non-developer operators +- Can be self-hosted alongside the indexer without external SaaS dependency + +## Decision + +We will use Prometheus for metrics collection, Alertmanager for alert routing, and Grafana for dashboards. The NestJS indexer will expose a `/metrics` endpoint compatible with Prometheus scraping. Contract-level telemetry will be surfaced by mapping Soroban events to Prometheus counters and gauges within the indexer. + +## Alternatives Considered + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Datadog / New Relic (SaaS APM) | Per-seat and per-metric pricing unsuitable for an open-source project; introduces external data dependency | +| OpenTelemetry collector → Jaeger | Better suited to distributed tracing than time-series metrics; the indexer's primary observability need is metrics and alerting, not trace correlation | +| InfluxDB + Chronograf | Viable time-series stack, but Prometheus + Grafana has broader community adoption, more pre-built dashboards, and stronger NestJS integration libraries | + +## Consequences + +### Positive + +- Prometheus + Grafana is the de-facto standard for self-hosted service monitoring; large library of pre-built dashboards and exporters +- Alertmanager integrates with common notification channels (PagerDuty, Slack, email) without custom webhook code +- NestJS has first-class Prometheus integration via `@willsoto/nestjs-prometheus` +- Entirely self-hosted; no external data egress required + +### Negative / Trade-offs + +- Requires operators to run three additional services (Prometheus, Alertmanager, Grafana) alongside the indexer +- Long-term metric storage requires configuring Prometheus remote write or a separate time-series store (e.g., Thanos, Mimir) for retention beyond the default 15-day window +- Grafana dashboard-as-code tooling (Grafonnet) adds a learning curve for contributors who want to modify dashboards + +### Neutral + +- The observability stack is documented separately in `OBSERVABILITY.md` and `indexer/MONITORING.md`; this ADR records only the technology selection rationale + +## Implementation Notes + +**Affected modules:** + +- `indexer/` (metrics endpoint and instrumentation) +- `docker-compose.yml` (Prometheus, Alertmanager, Grafana service definitions) + +**Reference docs:** + +- `OBSERVABILITY.md` +- `indexer/MONITORING.md` + +**Related issues / PRs:** # + +--- + +## Review Checklist + +- [x] Context accurately describes the problem without solution bias +- [x] Decision is stated clearly and unambiguously +- [x] At least two alternatives are documented with rejection rationale +- [x] Consequences cover both positive and negative outcomes +- [x] Status field is set correctly +- [x] Tags accurately reflect the domain +- [x] Linked to the relevant GitHub issue or PR \ No newline at end of file diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 00000000..4be027c2 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,104 @@ +# Architecture Decision Records + +This directory contains Architecture Decision Records (ADRs) for TeachLink. An ADR captures an important architectural choice made during the project's evolution, along with the context, alternatives considered, and consequences. + +## What is an ADR? + +An ADR is a short document that records a significant technical decision. It is **not** a design document or a specification — it is a snapshot of _why_ something is the way it is, written at the time the decision was made. + +ADRs are immutable once accepted. If a decision is reversed or superseded, the original ADR is marked accordingly and a new one is created. + +## Index + +| ID | Title | Status | Date | +|----------|---------------------------------------------------|----------|------------| +| ADR-0001 | Use Soroban (Rust) for Smart Contract Development | Accepted | 2024-01-15 | +| ADR-0002 | Tokenized Learning Rewards Architecture | Accepted | 2024-02-10 | +| ADR-0003 | Cross-Chain Bridge Design | Accepted | 2024-03-05 | +| ADR-0004 | Indexer Technology Selection (TypeScript/NestJS) | Accepted | 2024-03-20 | +| ADR-0005 | Observability Stack (Prometheus, Grafana) | Accepted | 2024-04-08 | + +> **New decision?** Copy [`template.md`](./template.md), assign the next sequential ID, fill it out, and open a PR. See the [Review Process](#review-process) section below. + +--- + +## Directory Structure + +``` +docs/adr/ +├── README.md ← this file (index + process) +├── template.md ← copy this when creating a new ADR +├── 0001-soroban-rust-smart-contracts.md +├── 0002-tokenized-learning-rewards.md +├── 0003-cross-chain-bridge-design.md +├── 0004-indexer-technology-selection.md +└── 0005-observability-stack.md +``` + +File names follow the pattern: `NNNN-kebab-case-title.md` + +--- + +## Lifecycle + +``` +Proposed → Accepted → (optionally) Deprecated + → (optionally) Superseded by ADR-XXXX +``` + +| Status | Meaning | +|-------------|-----------------------------------------------------------------------| +| Proposed | Under discussion; not yet adopted | +| Accepted | Decision is in effect | +| Deprecated | Decision is no longer relevant but the record is kept for history | +| Superseded | A newer ADR replaces this one; link to the replacement in the header | + +--- + +## Review Process + +### Creating an ADR + +1. Copy `template.md` to a new file: `NNNN-short-title.md` +2. Assign the next sequential ID (check the index table above) +3. Set status to `Proposed` +4. Fill out all required sections (Context, Decision, Alternatives, Consequences) +5. Open a PR and request review from at least one maintainer +6. Add the entry to the index table in this README in the same PR + +### Review Criteria + +Reviewers should verify that the ADR: + +- Clearly separates the **problem** (Context) from the **solution** (Decision) +- Lists **at least two** alternatives with concrete rejection rationale +- Documents **both positive and negative** consequences +- Does **not** contain implementation instructions (those belong in code comments or separate docs) +- References the GitHub issue or PR that triggered the decision + +### Merging + +- An ADR may be merged once it has at least **one approving review** from a maintainer +- The status must be changed from `Proposed` to `Accepted` before or at merge time +- The index table in this README must be updated in the same PR + +### Superseding an Existing ADR + +1. Create the new ADR as `Proposed` +2. In the old ADR, change status to `Superseded by ADR-XXXX` +3. In the new ADR header, add `Supersedes: ADR-XXXX` +4. Update the index table + +--- + +## Relationship to Other Documentation + +| Document | Purpose | +|----------------------------------|-------------------------------------------------------| +| `docs/ARCHITECTURE.md` | High-level system overview and component diagrams | +| `docs/NAMING_CONVENTIONS.md` | Cross-module naming standards and enforcement | +| `docs/adr/` | _Why_ the architecture looks the way it does | +| `OBSERVABILITY.md` | Monitoring and alerting runbook | +| `indexer/MONITORING.md` | Indexer-specific monitoring details | + +ADRs capture the **decision history** behind the architecture. For the current state of the system, refer to `docs/ARCHITECTURE.md`. \ No newline at end of file diff --git a/docs/adr/template.md b/docs/adr/template.md new file mode 100644 index 00000000..4e1af209 --- /dev/null +++ b/docs/adr/template.md @@ -0,0 +1,71 @@ +# ADR-XXXX: [Short Title — Noun Phrase, Present Tense] + +**Status:** [Proposed | Accepted | Deprecated | Superseded by ADR-XXXX] +**Date:** YYYY-MM-DD +**Authors:** [@github-handle] +**Reviewers:** [@github-handle] +**Tags:** [contract | indexer | infrastructure | security | cross-chain | tooling] + +--- + +## Context + + + +## Decision + + + +## Alternatives Considered + + + +| Alternative | Reason Rejected | +|-------------|-----------------| +| Option A | | +| Option B | | + +## Consequences + +### Positive + +- +- + +### Negative / Trade-offs + +- +- + +### Neutral + +- + +## Implementation Notes + + + +**Affected modules:** + +- `contracts/teachlink/` + +**Related issues / PRs:** # + +--- + +## Review Checklist + +- [ ] Context accurately describes the problem without solution bias +- [ ] Decision is stated clearly and unambiguously +- [ ] At least two alternatives are documented with rejection rationale +- [ ] Consequences cover both positive and negative outcomes +- [ ] Status field is set correctly +- [ ] Tags accurately reflect the domain +- [ ] Linked to the relevant GitHub issue or PR \ No newline at end of file