From ff7de25516744e97733fc8fd724fc066a6bcacd9 Mon Sep 17 00:00:00 2001 From: SONIA Date: Thu, 28 May 2026 15:03:29 +0000 Subject: [PATCH] docs: enhance developer onboarding guide Closes #308 - Add architecture overview diagram with data flow and key files table - Add Docker Compose setup instructions (Option A) - Expand env vars section with Redis and observability vars - Add test commands for all packages (web unit, e2e, contracts, stellar) - Add troubleshooting entries for idempotency, OpenTelemetry, Docker, inactive meter, and missing env vars - Expand project structure with src/ subdirectory breakdown --- docs/ONBOARDING.md | 179 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 144 insertions(+), 35 deletions(-) diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 8152d24..37290b0 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -12,9 +12,10 @@ Install the following before cloning: |------|---------|---------| | Node.js | v22+ | [nodejs.org](https://nodejs.org) or `nvm install 22` | | pnpm | v10+ | `npm install -g pnpm@10` | -| Rust + Cargo | stable | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` | +| Rust + Cargo | stable (1.78+) | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` | | wasm32 target | — | `rustup target add wasm32-unknown-unknown` | | Stellar CLI | latest | `cargo install --locked stellar-cli --features opt` | +| Docker + Compose | v24+ | [docs.docker.com](https://docs.docker.com/get-docker/) *(optional, recommended)* | Verify: @@ -27,6 +28,44 @@ stellar --version # stellar x.x.x --- +## Architecture overview + +``` +Smart Meter (Ed25519 keypair) + │ POST /api/readings { kwh, timestamp, signature_hex } + │ Header: Idempotency-Key: + ▼ +SolarProof API (Next.js 15 — apps/web) + │ 1. Check Idempotency-Key in Redis → return cached response if hit + │ 2. Verify Ed25519 signature against meter public key + │ 3. Anchor reading hash → audit_registry contract (Stellar) + │ 4. Mint energy_token (1 token = 1 kWh) to cooperative admin + │ 5. Store certificate in Supabase + ▼ +Stellar Testnet (Soroban — apps/contracts) + ├── energy_token SEP-41 certificate token (minter-gated) + ├── audit_registry immutable signed-reading anchors + └── community_governance cooperative proposals + voting + ▼ +Public Verifier (https://solarproof.vercel.app/verify) + Input: certificate ID or tx hash + Output: meter reading → Ed25519 proof → ledger anchor → certificate +``` + +### Key data flows + +| Flow | Entry point | Key files | +|------|-------------|-----------| +| Meter reading submission | `POST /api/readings` | `src/app/api/readings/route.ts` | +| Signature verification | `src/lib/crypto.ts` | `@noble/ed25519` | +| Stellar interactions | `src/lib/stellar.ts` | `@stellar/stellar-sdk` | +| Idempotency | `src/lib/idempotency.ts` | Upstash Redis | +| Certificate cache | `src/lib/cache.ts` | Upstash Redis | +| Structured logging | `src/lib/logger.ts` | Logtail / stdout | +| APM traces | `src/instrumentation.ts` | OpenTelemetry OTLP | + +--- + ## 1. Clone and install ```bash @@ -46,14 +85,26 @@ cp apps/web/.env.example apps/web/.env.local Edit `apps/web/.env.local` and fill in: ```env +# Supabase NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key SUPABASE_SERVICE_ROLE_KEY=your-service-role-key + +# Stellar NEXT_PUBLIC_STELLAR_NETWORK=testnet NEXT_PUBLIC_ENERGY_TOKEN_ID= # from contract deployment NEXT_PUBLIC_AUDIT_REGISTRY_ID= # from contract deployment NEXT_PUBLIC_COMMUNITY_GOVERNANCE_ID= # from contract deployment -MINTER_SECRET_KEY= # from contract deployment +MINTER_SECRET_KEY= # Stellar secret key for the minter account + +# Redis (Upstash) — optional for local dev, required for idempotency + caching +UPSTASH_REDIS_REST_URL=https://your-instance.upstash.io +UPSTASH_REDIS_REST_TOKEN=your-token + +# Observability — optional +LOGTAIL_SOURCE_TOKEN= # Better Stack structured logs +OTEL_EXPORTER_OTLP_ENDPOINT= # OpenTelemetry collector URL +OTEL_EXPORTER_OTLP_HEADERS= # e.g. Authorization=Basic ``` For contract IDs, see [Deploying contracts locally](#4-deploying-contracts-locally) below, or ask a teammate for the shared testnet IDs. @@ -62,17 +113,29 @@ For contract IDs, see [Deploying contracts locally](#4-deploying-contracts-local ## 3. Run the web app +### Option A — Docker (recommended) + +Spins up Next.js, Supabase, and Redis together: + +```bash +docker compose up +``` + +App available at http://localhost:3000. Data persists in named volumes across restarts. + +### Option B — Local dev server + ```bash pnpm dev ``` -Opens at [http://localhost:3000](http://localhost:3000). +Opens at http://localhost:3000. Requires Supabase and Redis to be running separately (or set env vars to cloud instances). --- ## 4. Deploying contracts locally -Build all three contracts: +Build all contracts: ```bash cd apps/contracts @@ -98,10 +161,6 @@ REGISTRY_ID=$(stellar contract deploy \ GOV_ID=$(stellar contract deploy \ --wasm target/wasm32-unknown-unknown/release/community_governance.wasm \ --source deployer --network testnet) - -echo "TOKEN_ID=$TOKEN_ID" -echo "REGISTRY_ID=$REGISTRY_ID" -echo "GOV_ID=$GOV_ID" ``` Initialize each contract: @@ -123,31 +182,58 @@ Copy the IDs into `apps/web/.env.local`. ## 5. Running tests -### Web (lint + type-check + build) +### Web — unit tests + +```bash +# From repo root (Turborepo runs all packages) +pnpm test + +# From apps/web only +cd apps/web +pnpm test # vitest run (single pass) +pnpm test:watch # vitest watch mode +``` + +### Web — lint and type-check ```bash -pnpm lint # ESLint -pnpm type-check # TypeScript -pnpm build # Next.js production build +pnpm lint # ESLint +pnpm type-check # TypeScript (tsc --noEmit) +pnpm build # Next.js production build ``` -Run from `apps/web/` or from the repo root (Turborepo runs all). +### Web — end-to-end tests + +```bash +cd apps/web +pnpm e2e # Playwright (requires running dev server) +``` -### Contracts (fmt + clippy + tests) +### Contracts — unit tests ```bash cd apps/contracts cargo fmt --all -- --check # formatting cargo clippy --all-targets # lints -cargo test --all # unit tests +cargo test --all # unit tests (all contracts) + +# Single contract +cargo test --package energy-token +cargo test --package audit-registry +cargo test --package community-governance +``` + +### Shared packages + +```bash +cd packages/stellar +pnpm test ``` --- ## 6. Simulate a meter reading end-to-end -This sends a signed reading through the full stack: script → API → Stellar. - **Step 1 — Generate a meter keypair:** ```bash @@ -157,13 +243,12 @@ node scripts/gen-meter-key.mjs **Step 2 — Register the meter in Supabase:** -Insert a row into the `meters` table with the `public_key_hex` from step 1. You can do this via the Supabase dashboard or SQL: - ```sql -INSERT INTO meters (id, public_key_hex, name) VALUES (gen_random_uuid(), '', 'dev-meter'); +INSERT INTO meters (id, public_key_hex, name, cooperative_id, active) +VALUES (gen_random_uuid(), '', 'dev-meter', '', true); ``` -**Step 3 — Start the dev server** (if not already running): +**Step 3 — Start the dev server:** ```bash pnpm dev @@ -189,45 +274,69 @@ Reading hash: **Step 5 — Verify on-chain:** -Open [http://localhost:3000/verify](http://localhost:3000/verify) and enter the reading hash or token transaction ID. +Open http://localhost:3000/verify and enter the reading hash or token transaction ID. --- ## 7. Troubleshooting **`pnpm install` fails with peer dependency errors** -→ Ensure Node.js v22+ is active: `node --version` +→ Ensure Node.js v22+ is active: `node --version`. Switch with `nvm use 22`. **`stellar contract build` fails with `wasm32-unknown-unknown` not found** → Run: `rustup target add wasm32-unknown-unknown` **`stellar keys fund` returns an error** -→ Testnet friendbot may be rate-limited. Try: `curl "https://friendbot.stellar.org?addr=$(stellar keys address deployer)"` +→ Testnet friendbot may be rate-limited. Try directly: +```bash +curl "https://friendbot.stellar.org?addr=$(stellar keys address deployer)" +``` -**API returns `invalid signature`** +**API returns `Invalid meter signature`** → The `meter_id` passed to `send-reading.mjs` must exactly match the UUID registered in Supabase. UUIDs are case-sensitive. +**API returns `Meter not found or inactive`** +→ Ensure the meter row has `active = true` and the `cooperative_id` references a valid cooperative with an `admin_address`. + **`cargo test` fails with `ed25519` import errors** → Ensure you're using the `soroban-sdk` version pinned in `apps/contracts/Cargo.toml`. Run `cargo update` only if explicitly needed. **Next.js build fails with missing env vars** -→ All `NEXT_PUBLIC_*` vars must be set at build time. Check `apps/web/.env.local` exists and is populated. +→ All `NEXT_PUBLIC_*` vars must be set at build time. Check `apps/web/.env.local` exists and is populated. See `apps/web/src/env.ts` for the full list of required vars. + +**Idempotency-Key not working (duplicate requests re-process)** +→ `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` must be set. Without Redis, idempotency is a no-op (by design, for local dev). + +**OpenTelemetry traces not appearing** +→ Set `OTEL_EXPORTER_OTLP_ENDPOINT` and `OTEL_EXPORTER_OTLP_HEADERS`. Verify the collector is reachable. Check stdout for SDK startup errors. + +**Docker compose fails to start Supabase** +→ Ensure ports 5432 and 54321 are free: `lsof -i :5432`. Stop any local Postgres instances first. --- -## Project structure recap +## Project structure ``` solarproof/ ├── apps/ -│ ├── contracts/ # Soroban smart contracts (Rust) -│ │ ├── energy_token/ -│ │ ├── audit_registry/ -│ │ └── community_governance/ -│ └── web/ # Next.js app + API routes -├── packages/stellar/ # Shared Stellar client utilities -├── scripts/ # Meter simulation scripts -└── docs/ # Deployment guide, ADRs, database schema +│ ├── contracts/ # Soroban smart contracts (Rust) +│ │ ├── energy_token/ # SEP-41 certificate token (minter-gated) +│ │ ├── audit_registry/ # Immutable reading anchors +│ │ └── community_governance/ # Cooperative proposals + voting +│ └── web/ # Next.js 15 app + API routes +│ ├── src/ +│ │ ├── app/ # Next.js App Router pages + API routes +│ │ │ └── api/ # REST API (readings, certificates, meters…) +│ │ ├── lib/ # Shared utilities (stellar, crypto, cache…) +│ │ ├── components/ # React UI components +│ │ └── instrumentation.ts # OpenTelemetry hook +│ └── e2e/ # Playwright end-to-end tests +├── packages/ +│ └── stellar/ # Shared Stellar client utilities +├── scripts/ # Meter simulation scripts +├── docs/ # ADRs, deployment guide, API docs +└── supabase/ # Migrations and seed data ``` See [CONTRIBUTING.md](../CONTRIBUTING.md) for commit conventions and PR workflow.