Skip to content

Commit c4023fc

Browse files
committed
docs: add comprehensive architecture decision records (#359)
1 parent 26aef70 commit c4023fc

7 files changed

Lines changed: 559 additions & 0 deletions
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# ADR-0001: Use Soroban (Rust) for Smart Contract Development
2+
3+
**Status:** Accepted
4+
**Date:** 2024-01-15
5+
**Authors:** [@rinafcode]
6+
**Reviewers:** [@rinafcode]
7+
**Tags:** contract, infrastructure
8+
9+
---
10+
11+
## Context
12+
13+
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.
14+
15+
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.
16+
17+
Key constraints:
18+
19+
- Micro-transactions (reward payouts as small as fractions of a token) require negligible fees
20+
- The team has existing experience with Rust systems programming
21+
- The contract surface area is large (bridge, escrow, rewards, reputation, assessment modules), so type safety and compile-time correctness guarantees are important
22+
- Long-term auditability matters; the contract code must be readable and verifiable by external reviewers
23+
24+
## Decision
25+
26+
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.
27+
28+
## Alternatives Considered
29+
30+
| Alternative | Reason Rejected |
31+
|-------------|-----------------|
32+
| 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 |
33+
| Move on Aptos / Sui | Ecosystem too early at decision time; limited tooling and auditor familiarity; cross-chain bridge support was less mature |
34+
| 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 |
35+
| Ink! on Substrate | Strong Rust support, but Polkadot parachain deployment complexity was disproportionate to the project's scale |
36+
37+
## Consequences
38+
39+
### Positive
40+
41+
- Rust's type system eliminates entire classes of contract bugs at compile time
42+
- `cargo test` and `cargo clippy` integrate naturally into CI, giving immediate feedback on contract correctness
43+
- Soroban's WASM execution environment is deterministic and sandboxed
44+
- Stellar's low fee model supports the micro-reward use cases central to TeachLink
45+
- The `wasm32-unknown-unknown` target produces compact, verifiable artifacts
46+
47+
### Negative / Trade-offs
48+
49+
- Soroban is a relatively new platform; the ecosystem of third-party libraries and auditors is smaller than EVM
50+
- Cross-chain bridge to EVM networks requires a custom bridge module, adding significant complexity
51+
- Windows development requires additional setup (MSVC toolchain or Docker) due to WASM linker limitations on MinGW
52+
53+
### Neutral
54+
55+
- 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`)
56+
57+
## Implementation Notes
58+
59+
**Affected modules:**
60+
61+
- `contracts/teachlink/` (entire contract workspace)
62+
63+
**Build command:**
64+
65+
```bash
66+
cargo build --release --target wasm32-unknown-unknown -p teachlink-contract
67+
```
68+
69+
**Related issues / PRs:** Initial project setup
70+
71+
---
72+
73+
## Review Checklist
74+
75+
- [x] Context accurately describes the problem without solution bias
76+
- [x] Decision is stated clearly and unambiguously
77+
- [x] At least two alternatives are documented with rejection rationale
78+
- [x] Consequences cover both positive and negative outcomes
79+
- [x] Status field is set correctly
80+
- [x] Tags accurately reflect the domain
81+
- [x] Linked to the relevant GitHub issue or PR
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ADR-0002: Tokenized Learning Rewards Architecture
2+
3+
**Status:** Accepted
4+
**Date:** 2024-02-10
5+
**Authors:** [@rinafcode]
6+
**Reviewers:** [@rinafcode]
7+
**Tags:** contract, platform
8+
9+
---
10+
11+
## Context
12+
13+
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).
14+
15+
Design questions at the time of this decision:
16+
17+
- Should rewards use a custom token standard or the Stellar Asset Contract (SAC)?
18+
- Should participation proofs be stored on-chain or referenced via content-addressed hashes?
19+
- How should educator incentives be structured relative to learner rewards to prevent gaming?
20+
21+
## Decision
22+
23+
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.
24+
25+
## Alternatives Considered
26+
27+
| Alternative | Reason Rejected |
28+
|-------------|-----------------|
29+
| 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 |
30+
| 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 |
31+
| Use only Stellar Classic assets (no SAC / contract layer) | Lacks programmable distribution logic; cannot encode conditional releases or reputation-weighted rewards |
32+
33+
## Consequences
34+
35+
### Positive
36+
37+
- Proof-of-participation events are permanent, publicly verifiable, and indexable by the TypeScript indexer layer
38+
- Escrow-based educator incentives align educator success with learner outcomes
39+
- Keeping participation data off-chain storage (in events) keeps contract storage footprint small and predictable
40+
- The separation of `rewards`, `escrow`, and `tokenization` modules allows each to be upgraded or audited independently
41+
42+
### Negative / Trade-offs
43+
44+
- Soroban events are not queryable from within the contract itself; external consumers (indexer) must subscribe and store event history for queries
45+
- Escrow release logic requires reliable milestone verification; an oracle or off-chain verifier must signal completion, introducing a trust assumption
46+
47+
### Neutral
48+
49+
- 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
50+
51+
## Implementation Notes
52+
53+
**Affected modules:**
54+
55+
- `contracts/teachlink/rewards`
56+
- `contracts/teachlink/escrow`
57+
- `contracts/teachlink/tokenization`
58+
- `contracts/teachlink/reputation`
59+
- `indexer/` (event subscription and storage)
60+
61+
**Related issues / PRs:** #
62+
63+
---
64+
65+
## Review Checklist
66+
67+
- [x] Context accurately describes the problem without solution bias
68+
- [x] Decision is stated clearly and unambiguously
69+
- [x] At least two alternatives are documented with rejection rationale
70+
- [x] Consequences cover both positive and negative outcomes
71+
- [x] Status field is set correctly
72+
- [x] Tags accurately reflect the domain
73+
- [x] Linked to the relevant GitHub issue or PR
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# ADR-0003: Cross-Chain Bridge Design
2+
3+
**Status:** Accepted
4+
**Date:** 2024-03-05
5+
**Authors:** [@rinafcode]
6+
**Reviewers:** [@rinafcode]
7+
**Tags:** contract, cross-chain, security
8+
9+
---
10+
11+
## Context
12+
13+
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.
14+
15+
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.
16+
17+
Key constraints:
18+
19+
- The bridge must not require a trusted single operator (single point of failure / centralization risk)
20+
- Slashing conditions must exist to punish malicious or faulty validators
21+
- The design must be extensible to additional chains beyond the initial target
22+
23+
## Decision
24+
25+
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.
26+
27+
No single validator can unilaterally authorize a cross-chain transfer; a quorum signature is required.
28+
29+
## Alternatives Considered
30+
31+
| Alternative | Reason Rejected |
32+
|-------------|-----------------|
33+
| 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 |
34+
| 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 |
35+
| 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 |
36+
37+
## Consequences
38+
39+
### Positive
40+
41+
- BFT consensus eliminates single-point-of-failure risk at the bridge layer
42+
- Slashing creates economic incentives for validators to behave correctly
43+
- The modular design (`bridge`, `bft_consensus`, `slashing`, `multichain`, `liquidity`) allows each component to be tested and audited in isolation
44+
- Extensible to additional chains by adding new chain adapters to the `multichain` module
45+
46+
### Negative / Trade-offs
47+
48+
- Building and maintaining a custom BFT consensus module is significantly more complex than delegating to a third-party bridge
49+
- Validator set management (onboarding, rotation, slashing) requires ongoing operational overhead
50+
- BFT consensus requires a minimum validator set size to be meaningful; a small or poorly distributed validator set reduces the security guarantees
51+
52+
### Neutral
53+
54+
- Cross-chain transfers have higher latency than native Stellar transactions due to the consensus round requirement; this is expected and documented for users
55+
56+
## Implementation Notes
57+
58+
**Affected modules:**
59+
60+
- `contracts/teachlink/bridge`
61+
- `contracts/teachlink/bft_consensus`
62+
- `contracts/teachlink/slashing`
63+
- `contracts/teachlink/multichain`
64+
- `contracts/teachlink/liquidity`
65+
66+
**Related issues / PRs:** #
67+
68+
---
69+
70+
## Review Checklist
71+
72+
- [x] Context accurately describes the problem without solution bias
73+
- [x] Decision is stated clearly and unambiguously
74+
- [x] At least two alternatives are documented with rejection rationale
75+
- [x] Consequences cover both positive and negative outcomes
76+
- [x] Status field is set correctly
77+
- [x] Tags accurately reflect the domain
78+
- [x] Linked to the relevant GitHub issue or PR
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ADR-0004: Indexer Technology Selection (TypeScript / NestJS)
2+
3+
**Status:** Accepted
4+
**Date:** 2024-03-20
5+
**Authors:** [@rinafcode]
6+
**Reviewers:** [@rinafcode]
7+
**Tags:** indexer, infrastructure
8+
9+
---
10+
11+
## Context
12+
13+
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.
14+
15+
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.
16+
17+
Key constraints:
18+
19+
- Must integrate with Stellar Horizon and Soroban RPC event subscription endpoints
20+
- Must support long-running background processes (event listeners, retry logic)
21+
- The team has more TypeScript experience than Go or Python for service development
22+
23+
## Decision
24+
25+
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.
26+
27+
## Alternatives Considered
28+
29+
| Alternative | Reason Rejected |
30+
|-------------|-----------------|
31+
| Go service | Strong concurrency model, but team TypeScript familiarity is higher; NestJS module structure maps well to the multi-feature indexer design |
32+
| Python (FastAPI / Celery) | Viable, but async event processing patterns in Python are less ergonomic than TypeScript; type safety weaker without strict mypy enforcement |
33+
| The Graph protocol | Designed primarily for EVM chains; Soroban subgraph support was not mature at decision time |
34+
| 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 |
35+
36+
## Consequences
37+
38+
### Positive
39+
40+
- NestJS's module system naturally maps to TeachLink's multi-feature architecture (one module per contract feature domain)
41+
- TypeScript's type system allows sharing schema types between indexer and frontend clients
42+
- Large ecosystem of Stellar JavaScript/TypeScript SDKs (`@stellar/stellar-sdk`)
43+
- NestJS integrates well with Prometheus metrics exporters used in the observability stack (ADR-0005)
44+
45+
### Negative / Trade-offs
46+
47+
- TypeScript/Node.js has higher memory overhead than Go or Rust for long-running processes
48+
- The indexer introduces a separate runtime dependency; operators must manage both the contract deployment and the indexer service
49+
- Schema drift between on-chain event payloads and indexer DTOs must be managed carefully (see `NAMING_CONVENTIONS.md`)
50+
51+
### Neutral
52+
53+
- The indexer is architecturally optional; the contract functions correctly without it, but the full product experience (learning history, analytics, recommendations) requires it
54+
55+
## Implementation Notes
56+
57+
**Affected modules:**
58+
59+
- `indexer/` (entire indexer workspace)
60+
61+
**Related issues / PRs:** #
62+
63+
---
64+
65+
## Review Checklist
66+
67+
- [x] Context accurately describes the problem without solution bias
68+
- [x] Decision is stated clearly and unambiguously
69+
- [x] At least two alternatives are documented with rejection rationale
70+
- [x] Consequences cover both positive and negative outcomes
71+
- [x] Status field is set correctly
72+
- [x] Tags accurately reflect the domain
73+
- [x] Linked to the relevant GitHub issue or PR
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# ADR-0005: Observability Stack (Prometheus, Alertmanager, Grafana)
2+
3+
**Status:** Accepted
4+
**Date:** 2024-04-08
5+
**Authors:** [@rinafcode]
6+
**Reviewers:** [@rinafcode]
7+
**Tags:** infrastructure, indexer
8+
9+
---
10+
11+
## Context
12+
13+
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.
14+
15+
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.
16+
17+
An observability stack must be chosen that:
18+
19+
- Collects and stores time-series metrics from the indexer runtime
20+
- Provides alerting for anomalies (ingestion lag, high error rates, validator slashing events)
21+
- Offers dashboards accessible to non-developer operators
22+
- Can be self-hosted alongside the indexer without external SaaS dependency
23+
24+
## Decision
25+
26+
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.
27+
28+
## Alternatives Considered
29+
30+
| Alternative | Reason Rejected |
31+
|-------------|-----------------|
32+
| Datadog / New Relic (SaaS APM) | Per-seat and per-metric pricing unsuitable for an open-source project; introduces external data dependency |
33+
| 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 |
34+
| InfluxDB + Chronograf | Viable time-series stack, but Prometheus + Grafana has broader community adoption, more pre-built dashboards, and stronger NestJS integration libraries |
35+
36+
## Consequences
37+
38+
### Positive
39+
40+
- Prometheus + Grafana is the de-facto standard for self-hosted service monitoring; large library of pre-built dashboards and exporters
41+
- Alertmanager integrates with common notification channels (PagerDuty, Slack, email) without custom webhook code
42+
- NestJS has first-class Prometheus integration via `@willsoto/nestjs-prometheus`
43+
- Entirely self-hosted; no external data egress required
44+
45+
### Negative / Trade-offs
46+
47+
- Requires operators to run three additional services (Prometheus, Alertmanager, Grafana) alongside the indexer
48+
- 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
49+
- Grafana dashboard-as-code tooling (Grafonnet) adds a learning curve for contributors who want to modify dashboards
50+
51+
### Neutral
52+
53+
- The observability stack is documented separately in `OBSERVABILITY.md` and `indexer/MONITORING.md`; this ADR records only the technology selection rationale
54+
55+
## Implementation Notes
56+
57+
**Affected modules:**
58+
59+
- `indexer/` (metrics endpoint and instrumentation)
60+
- `docker-compose.yml` (Prometheus, Alertmanager, Grafana service definitions)
61+
62+
**Reference docs:**
63+
64+
- `OBSERVABILITY.md`
65+
- `indexer/MONITORING.md`
66+
67+
**Related issues / PRs:** #
68+
69+
---
70+
71+
## Review Checklist
72+
73+
- [x] Context accurately describes the problem without solution bias
74+
- [x] Decision is stated clearly and unambiguously
75+
- [x] At least two alternatives are documented with rejection rationale
76+
- [x] Consequences cover both positive and negative outcomes
77+
- [x] Status field is set correctly
78+
- [x] Tags accurately reflect the domain
79+
- [x] Linked to the relevant GitHub issue or PR

0 commit comments

Comments
 (0)