Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
project: './tsconfig.eslint.json',
tsconfigRootDir: __dirname,
ecmaVersion: 2020,
sourceType: 'module'
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
env: {
node: true,
jest: true,
es2021: true
es2021: true,
},
rules: {}
rules: {},
};
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
- name: Validate env example
run: node scripts/validate-env.js

- name: Check formatting
run: npm run format:check

- name: Lint
run: npm run lint

Expand Down
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
*.db
*.db-journal
package-lock.json
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"endOfLine": "lf"
}
65 changes: 41 additions & 24 deletions BACKEND_API_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Tokens are issued after a successful SEP-10 Stellar wallet challenge/response fl
Liveness check. No auth required.

**Response `200`**

```json
{
"status": "ok",
Expand All @@ -44,11 +45,12 @@ Returns a SEP-10 challenge XDR for the given Stellar account. No auth required.

**Query params**

| Param | Type | Required | Description |
|-----------|--------|----------|--------------------------|
| `account` | string | ✅ | Stellar public key (G…) |
| Param | Type | Required | Description |
| --------- | ------ | -------- | ----------------------- |
| `account` | string | ✅ | Stellar public key (G…) |

**Response `200`**

```json
{
"challenge": "<XDR string>",
Expand All @@ -63,6 +65,7 @@ Returns a SEP-10 challenge XDR for the given Stellar account. No auth required.
Submit a signed SEP-10 XDR to receive a JWT. No auth required.

**Request body**

```json
{
"signedXdr": "<signed XDR string>",
Expand All @@ -71,6 +74,7 @@ Submit a signed SEP-10 XDR to receive a JWT. No auth required.
```

**Response `200`**

```json
{
"token": "<JWT>",
Expand All @@ -88,6 +92,7 @@ Submit a signed SEP-10 XDR to receive a JWT. No auth required.
Pin player metadata to IPFS and return the content ID. No auth required.

**Request body**

```json
{
"wallet": "GABC...XYZ",
Expand All @@ -104,6 +109,7 @@ Pin player metadata to IPFS and return the content ID. No auth required.
```

**Response `201`**

```json
{
"success": true,
Expand All @@ -122,15 +128,16 @@ Filter players by region, position, and minimum verified tier. No auth required.

**Query params**

| Param | Type | Required | Description |
|------------|---------|----------|--------------------------------------|
| `region` | string | ❌ | Filter by region |
| `position` | string | ❌ | Filter by position |
| `minTier` | integer | ❌ | Minimum progress level (0–3) |
| `page` | integer | ❌ | Page number (default: 1) |
| Param | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------- |
| `region` | string | ❌ | Filter by region |
| `position` | string | ❌ | Filter by position |
| `minTier` | integer | ❌ | Minimum progress level (0–3) |
| `page` | integer | ❌ | Page number (default: 1) |
| `pageSize` | integer | ❌ | Results per page (default: 20, max: 100) |

**Response `200`**

```json
{
"success": true,
Expand All @@ -150,6 +157,7 @@ Filter players by region, position, and minimum verified tier. No auth required.
```

**Error `400`** — invalid `minTier`

```json
{
"success": false,
Expand All @@ -164,6 +172,7 @@ Filter players by region, position, and minimum verified tier. No auth required.
Retrieve a single player profile. No auth required.

**Response `200`**

```json
{
"success": true,
Expand All @@ -180,6 +189,7 @@ Retrieve a single player profile. No auth required.
```

**Error `404`**

```json
{ "success": false, "error": "Player not found" }
```
Expand All @@ -191,6 +201,7 @@ Retrieve a single player profile. No auth required.
Tamper-proof milestone history for a player. No auth required.

**Response `200`**

```json
{
"success": true,
Expand Down Expand Up @@ -218,6 +229,7 @@ Tamper-proof milestone history for a player. No auth required.
Check active subscription status for a scout. **Requires Bearer auth.**

**Response `200`**

```json
{
"success": true,
Expand All @@ -237,12 +249,11 @@ Check active subscription status for a scout. **Requires Bearer auth.**
List players unlocked by a scout. **Requires Bearer auth.**

**Response `200`**

```json
{
"success": true,
"data": [
{ "playerId": "abc123", "unlockedAt": 1700000000 }
]
"data": [{ "playerId": "abc123", "unlockedAt": 1700000000 }]
}
```

Expand All @@ -257,6 +268,7 @@ List players unlocked by a scout. **Requires Bearer auth.**
Pin milestone evidence to IPFS and return the CID. **Requires Bearer auth (validator role).**

**Request body**

```json
{
"playerId": "abc123",
Expand All @@ -269,6 +281,7 @@ Pin milestone evidence to IPFS and return the CID. **Requires Bearer auth (valid
```

**Response `201`**

```json
{
"success": true,
Expand All @@ -286,6 +299,7 @@ Pin milestone evidence to IPFS and return the CID. **Requires Bearer auth (valid
List pending milestone approvals. **Requires Bearer auth (validator role).**

**Response `200`**

```json
{
"success": true,
Expand All @@ -312,6 +326,7 @@ List pending milestone approvals. **Requires Bearer auth (validator role).**
Platform-wide counts. **Requires Bearer auth (admin role).**

**Response `200`**

```json
{
"success": true,
Expand All @@ -331,6 +346,7 @@ Platform-wide counts. **Requires Bearer auth (admin role).**
All indexed contract events. **Requires Bearer auth.**

**Response `200`**

```json
{
"success": true,
Expand All @@ -352,6 +368,7 @@ All indexed contract events. **Requires Bearer auth.**
Fee withdrawal history. **Requires Bearer auth.**

**Response `200`**

```json
{
"success": true,
Expand All @@ -372,11 +389,11 @@ Fee withdrawal history. **Requires Bearer auth.**

The following routes currently return data sourced entirely from indexed on-chain events and have no corresponding write/mutation endpoint in the backend:

| Route | Reason |
|-------|--------|
| `GET /api/scouts/:wallet/subscription` | Subscription state managed on-chain via `subscribe()`; backend is read-only |
| `GET /api/scouts/:wallet/contacts` | Contact unlocks managed on-chain via `pay_to_contact()`; backend is read-only |
| `GET /api/validators/milestones/pending` | Milestone approval is an on-chain transaction; backend only indexes events |
| Route | Reason |
| ---------------------------------------- | ----------------------------------------------------------------------------- |
| `GET /api/scouts/:wallet/subscription` | Subscription state managed on-chain via `subscribe()`; backend is read-only |
| `GET /api/scouts/:wallet/contacts` | Contact unlocks managed on-chain via `pay_to_contact()`; backend is read-only |
| `GET /api/validators/milestones/pending` | Milestone approval is an on-chain transaction; backend only indexes events |

---

Expand All @@ -393,10 +410,10 @@ All error responses follow this shape:

Common HTTP status codes:

| Code | Meaning |
|------|--------------------------------|
| 400 | Validation error |
| 401 | Missing or invalid auth token |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 500 | Internal server error |
| Code | Meaning |
| ---- | ----------------------------- |
| 400 | Validation error |
| 401 | Missing or invalid auth token |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 500 | Internal server error |
35 changes: 19 additions & 16 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

Copy `.env.example` to `.env` and fill in all required values before starting the server.

| Variable | Required | Notes |
|---|---|---|
| `CONTRACT_ID` | ✅ | Deployed Soroban contract address |
| `JWT_SECRET` | ✅ | Min 32 chars; rotate on compromise |
| `HORIZON_URL` | ✅ | e.g. `https://horizon-testnet.stellar.org` |
| `SOROBAN_RPC_URL` | ✅ | e.g. `https://soroban-testnet.stellar.org` |
| `NETWORK` | ✅ | `testnet` or `mainnet` |
| `PINATA_API_KEY` / `PINATA_SECRET` | ✅ | IPFS upload credentials |
| `DB_PATH` | — | SQLite file path (default: `scout-off.db`) |
| `PORT` | — | API port (default: `4000`) |
| `LOG_LEVEL` | — | `debug` / `info` / `warn` / `error` |
| `STELLAR_HEALTH_CHECK_ENABLED` | — | Set `false` in staging to skip Stellar RPC check |
| `TRUSTED_PROXY_COUNT` | — | Number of trusted reverse proxies (default: `1`) |
| Variable | Required | Notes |
| ---------------------------------- | -------- | ------------------------------------------------ |
| `CONTRACT_ID` | ✅ | Deployed Soroban contract address |
| `JWT_SECRET` | ✅ | Min 32 chars; rotate on compromise |
| `HORIZON_URL` | ✅ | e.g. `https://horizon-testnet.stellar.org` |
| `SOROBAN_RPC_URL` | ✅ | e.g. `https://soroban-testnet.stellar.org` |
| `NETWORK` | ✅ | `testnet` or `mainnet` |
| `PINATA_API_KEY` / `PINATA_SECRET` | ✅ | IPFS upload credentials |
| `DB_PATH` | — | SQLite file path (default: `scout-off.db`) |
| `PORT` | — | API port (default: `4000`) |
| `LOG_LEVEL` | — | `debug` / `info` / `warn` / `error` |
| `STELLAR_HEALTH_CHECK_ENABLED` | — | Set `false` in staging to skip Stellar RPC check |
| `TRUSTED_PROXY_COUNT` | — | Number of trusted reverse proxies (default: `1`) |

## Build & Start

Expand Down Expand Up @@ -52,15 +52,18 @@ Always back up the database file before running migrations in production.

## Health & Monitoring

| Endpoint | Purpose |
|---|---|
| Endpoint | Purpose |
| ------------- | ------------------------------------------- |
| `GET /health` | Liveness check; includes Stellar RPC status |
| `GET /ready` | Readiness probe; checks IPFS connectivity |
| `GET /ready` | Readiness probe; checks IPFS connectivity |

Configure your load balancer or orchestrator to poll `/health` every 30 seconds.
Alert on consecutive failures (≥ 2) to catch Stellar RPC or IPFS outages early.

In the event of an outage, refer to the [Dependency Outages Runbook](docs/runbooks/dependency-outages.md) for mitigation and recovery procedures.

Recommended metrics to track:

- HTTP 5xx error rate
- Event indexer lag (gap between latest on-chain event and last indexed event)
- SQLite file size growth
Expand Down
2 changes: 1 addition & 1 deletion ISSUE_PUSH_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Issue Push Summary

This repository has new GitHub issues created programmatically from the notebook.
This repository has new GitHub issues created programmatically from the notebook.
Loading