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
123 changes: 18 additions & 105 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ API base: [http://localhost:3000](http://localhost:3000).

### Environment

| Variable | Required | Description |
|-------------|----------|----------------------------------------------------------|
| `PORT` | No | Server port (default: `3000`) |
| `API_KEYS` | **Yes** | Comma-separated list of valid admin API keys (see below) |
| `DATABASE_URL` | No | PostgreSQL connection string (required for migrations) |
| Variable | Description |
|----------|-------------|
| `PORT` | Server port (default: 3000) |
| `DATABASE_URL` | PostgreSQL connection string (required for migrations) |

Optional later: `REDIS_URL`, `HORIZON_URL`, etc.

Expand All @@ -69,62 +68,6 @@ The PostgreSQL schema is designed and documented in **[docs/data-model.md](docs/
- **Apply migrations:** `DATABASE_URL=... npm run db:migrate`
- **Validate schema:** `DATABASE_URL=... npm run db:validate`

## Authentication

Admin and internal endpoints are protected by an **API key** sent in the
`X-API-Key` HTTP header.

### Configuring API keys

Set the `API_KEYS` environment variable to a comma-separated list of secret
keys before starting the service:

```bash
export API_KEYS="key-abc123,key-def456"
npm run dev
```

The service **will not start** (throws at boot) if `API_KEYS` is unset or
empty, preventing accidental exposure of unprotected admin routes.

### Making authenticated requests

```bash
curl -X POST http://localhost:3000/api/credit/lines/42/suspend \
-H "X-API-Key: key-abc123"
```

| Result | Condition |
|--------|-----------|
| `401 Unauthorized` | `X-API-Key` header is absent |
| `403 Forbidden` | Header present but key is not in `API_KEYS` |
| `200 OK` | Key matches one of the configured valid keys |

> **Security note:** The value of an invalid key is **never** included in
> error responses or server logs. Always use HTTPS in production.

### Protected endpoints

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/credit/lines/:id/suspend` | Suspend an active credit line |
| `POST` | `/api/credit/lines/:id/close` | Permanently close a credit line |
| `POST` | `/api/risk/admin/recalibrate` | Trigger risk model recalibration |

Public endpoints (`GET /api/credit/lines`, `POST /api/risk/evaluate`, etc.)
do **not** require a key.

### Rotating API keys

Use a **rolling rotation** to avoid downtime:

1. Add the new key to `API_KEYS` (keep the old key alongside it).
2. Deploy / restart the service.
3. Update all clients and CI secrets to use the new key.
4. Remove the old key from `API_KEYS` and redeploy.

This ensures no requests are rejected during the transition window.

## CI / Quality Gates

The GitHub Actions workflow (`.github/workflows/ci.yml`) runs on every push and pull request:
Expand Down Expand Up @@ -159,56 +102,23 @@ npm run test:watch
## API (current)

- `GET /health` — Service health
- `GET /api/credit/lines` — List credit lines (placeholder)
- `GET /api/credit/lines/:id` — Get credit line by id (placeholder)
- `POST /api/risk/evaluate` — Request risk evaluation; body: `{ "walletAddress": "..." }`; returns `400` with `{ "error": "Invalid wallet address format." }` for invalid Stellar addresses
### Public

- `GET /health` — Service health
- `GET /api/credit/lines` — List credit lines (placeholder)
- `GET /api/credit/lines/:id` — Get credit line by id (placeholder)
- `POST /api/risk/evaluate` — Risk evaluation; body: `{ "walletAddress": "..." }`

### Admin (requires `X-API-Key`)

- `POST /api/credit/lines/:id/suspend` — Suspend a credit line
- `POST /api/credit/lines/:id/close` — Close a credit line
- `POST /api/risk/admin/recalibrate` — Trigger risk model recalibration

## Running tests

```bash
npm test # run once with coverage report
npm run test:watch # interactive watch mode
```

Target: ≥ 95 % coverage on all middleware and route files.
- `GET /api/credit/lines` — List credit lines
- `GET /api/credit/lines/:id` — Get a full credit line by id; returns `404` with `{ "error": "Credit line \"<id>\" not found." }` when missing
- `POST /api/risk/evaluate` — Request risk evaluation; body: `{ "walletAddress": "..." }`

## Project layout

```
src/
config/
apiKeys.ts # loads + validates API_KEYS env var
middleware/
auth.ts # requireApiKey Express middleware
routes/
credit.ts # credit-line endpoints (public + admin)
risk.ts # risk endpoints (public + admin)
__tests__/
auth.test.ts # middleware unit tests
credit.test.ts # credit route integration tests
risk.test.ts # risk route integration tests
index.ts # app entry, middleware wiring, route mounting
db/ # migration and schema validation helpers
docs/
data-model.md # PostgreSQL data model documentation
security-checklist-backend.md
migrations/ # SQL migration files
index.ts — App entry, middleware, route mounting
routes/ — credit and risk route handlers
__tests__/ — Jest test suites
- `docs/` — Documentation and guidelines

.github/workflows/
ci.yml # CI pipeline
.eslintrc.cjs # ESLint config
tsconfig.json # TypeScript config
ci.yml CI pipeline
.eslintrc.cjs ESLint config
tsconfig.json TypeScript config
```

## Security
Expand All @@ -219,6 +129,9 @@ Security is a priority for Creditra. Before deploying or contributing:
- Ensure all security requirements are met
- Run `npm audit` to check for vulnerabilities
- Maintain minimum 95% test coverage
- `src/db/` — migration and schema validation helpers
- `docs/data-model.md` — PostgreSQL data model documentation
- `migrations/` — SQL migration files

## Merging to remote

Expand Down
Loading
Loading