{"id":50333513,"url":"https://github.com/lafronzt/standards-api","last_synced_at":"2026-05-29T11:31:25.335Z","repository":{"id":359175224,"uuid":"1242853450","full_name":"lafronzt/standards-api","owner":"lafronzt","description":"AI-generated POC for a ReviewOps standards API that stores versioned engineering rules and serves latest applicable standards for automated code review workflows.","archived":false,"fork":false,"pushed_at":"2026-05-20T18:25:40.000Z","size":77,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-20T23:11:08.708Z","etag":null,"topics":["ai-generated","api","code-review","docker","engineering-standards","fastify","kubernetes","nodejs","openapi","poc","postgresql","prisma","reviewops","standards-api","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lafronzt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-18T20:22:14.000Z","updated_at":"2026-05-20T18:19:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lafronzt/standards-api","commit_stats":null,"previous_names":["lafronzt/standards-api"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lafronzt/standards-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lafronzt%2Fstandards-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lafronzt%2Fstandards-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lafronzt%2Fstandards-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lafronzt%2Fstandards-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lafronzt","download_url":"https://codeload.github.com/lafronzt/standards-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lafronzt%2Fstandards-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33650712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-generated","api","code-review","docker","engineering-standards","fastify","kubernetes","nodejs","openapi","poc","postgresql","prisma","reviewops","standards-api","typescript"],"created_at":"2026-05-29T11:31:25.257Z","updated_at":"2026-05-29T11:31:25.330Z","avatar_url":"https://github.com/lafronzt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Standards API\n\nProduction-ready API for ReviewOps engineering standards. It stores versioned standards in PostgreSQL and returns the latest active rules for AI code review tooling.\n\n## Stack\n\n- Node.js 22\n- TypeScript\n- Fastify\n- PostgreSQL\n- Prisma\n- Vitest\n\n## Environment\n\nCopy `.env.example` to `.env` and adjust values for your environment.\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `DATABASE_URL` | required | PostgreSQL connection string used by Prisma |\n| `HOST` | `0.0.0.0` | Bind host |\n| `PORT` | `3000` | API port |\n| `LOG_LEVEL` | `info` | Fastify logger level |\n| `STANDARDS_API_KEY` | unset | Optional write API key. Required for writes when set, and always required when `NODE_ENV=production` |\n\nDo not commit real database credentials or secrets.\n\n## Local Development\n\n```bash\nnpm install\ncp .env.example .env\ndocker compose up -d postgres\nnpx prisma migrate dev\nnpm run prisma:seed\nnpm run dev\n```\n\nThe API listens on `http://localhost:3000`.\n\n## Docker\n\nRun the full app and database:\n\n```bash\ndocker compose up --build\n```\n\nSeed data after the app/database are running:\n\n```bash\ndocker compose exec app npm run prisma:seed:prod\n```\n\n## Scripts\n\n```bash\nnpm run dev              # start local HTTP dev server\nnpm run build            # compile TypeScript\nnpm run lint             # strict TypeScript check\nnpm test                 # run tests\nnpm run mcp:dev          # start MCP stdio server (tsx, no build required)\nnpm run mcp:start        # start compiled MCP stdio server\nnpm run mcp:http:dev     # start MCP Streamable HTTP server (tsx, no build required)\nnpm run mcp:http:start   # start compiled MCP Streamable HTTP server\nnpm run prisma:migrate   # create/apply local migration\nnpm run prisma:deploy    # apply migrations in deployed environments\nnpm run prisma:seed      # load example standards\n```\n\n## MCP Server\n\nThe MCP server exposes read-only access to engineering standards over the [Model Context Protocol](https://modelcontextprotocol.io) stdio transport. It shares the same PostgreSQL database as the HTTP API.\n\n### Running locally\n\n```bash\n# Development (no build step required)\nDATABASE_URL=postgresql://user:password@localhost:5432/standards npm run mcp:dev\n\n# Production (build first)\nnpm run build\nDATABASE_URL=postgresql://user:password@localhost:5432/standards npm run mcp:start\n```\n\n### Client configuration\n\nAdd the following to your MCP client configuration (for example, `claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"standards-api\": {\n      \"command\": \"npm\",\n      \"args\": [\"run\", \"mcp:start\"],\n      \"cwd\": \"/absolute/path/to/standards-api\",\n      \"env\": {\n        \"DATABASE_URL\": \"postgresql://user:password@localhost:5432/standards\"\n      }\n    }\n  }\n}\n```\n\n### Tools\n\n| Tool | Description |\n| --- | --- |\n| `list_standards` | List standards with optional `status`, `category`, `severity`, `owner`, `limit`, `offset` filters |\n| `get_standard` | Get the latest version of a single standard by `rule_key` |\n| `latest_standards` | Return the latest active standards payload (same as `GET /api/v1/standards/latest`) |\n| `applicable_standards` | Return active standards matching `repo`, `team`, `language`, `framework`, `runtime`, `environment`, and/or `changed_paths` |\n\n### Resources\n\n| URI | Description |\n| --- | --- |\n| `standards://latest` | Latest active standards payload as JSON |\n| `standards://rule/{rule_key}` | A single standard by rule key |\n\n## MCP Streamable HTTP Server\n\nThe Streamable HTTP server exposes the same tools and resources as the stdio server over the [MCP Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). Remote MCP clients (such as Claude.ai) can connect to it over HTTPS via a reverse proxy.\n\n### Environment variables\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `MCP_API_KEY` | required | API key sent in `x-api-key` on every request. Unset = all requests rejected. |\n| `MCP_HTTP_PORT` | `3001` | Port for the Streamable HTTP MCP server (avoids collision with Fastify on `3000`). |\n\n### Running locally\n\n```bash\n# Development (no build step required)\nDATABASE_URL=postgresql://user:password@localhost:5432/standards \\\n  MCP_API_KEY=secret \\\n  npm run mcp:http:dev\n\n# Production (build first)\nnpm run build\nDATABASE_URL=postgresql://user:password@localhost:5432/standards \\\n  MCP_API_KEY=secret \\\n  npm run mcp:http:start\n```\n\nRequests without a valid `x-api-key` header return `401`. Deploy behind a TLS-terminating reverse proxy (nginx, Caddy, AWS ALB, etc.) before exposing to the public internet.\n\n### Client configuration\n\nAdd the following to your MCP client configuration to connect to a remotely hosted instance:\n\n```json\n{\n  \"mcpServers\": {\n    \"standards-api-remote\": {\n      \"type\": \"http\",\n      \"url\": \"https://your-host/mcp\",\n      \"headers\": {\n        \"x-api-key\": \"your-secret-key\"\n      }\n    }\n  }\n}\n```\n\nReplace `https://your-host/mcp` with the public URL of your reverse proxy.\n\n### Tools and resources\n\nThe Streamable HTTP server exposes the same four tools and two resources as the stdio server. See the [MCP Server](#mcp-server) section above for the full list.\n\n\n## Database\n\nThe service creates one table:\n\n- `standards`: versioned standards/rules with status, severity, category, applicability metadata, guidance, examples, owner, timestamps, and deprecation timestamp.\n\nThere is a unique constraint on `(rule_key, version)` to prevent duplicate versions and a partial unique index that allows only one active version for a given `rule_key`.\n\n## Versioning\n\n- `rule_key` is stable across versions.\n- Each database row represents one version of a rule.\n- Draft rules are updated in place by `PUT /api/v1/standards/:ruleKey`.\n- Updating an active or deprecated rule creates a new version.\n- Creating a new active version automatically marks the previous active version for the same `rule_key` as `deprecated` and sets `deprecated_at`.\n- Deprecated rules remain queryable with list filters such as `?status=deprecated`, but they do not appear in `/api/v1/standards/latest` or `/api/v1/standards/applicable`.\n\n## Endpoints\n\n- `GET /health`\n- `GET /api/v1/standards`\n- `GET /api/v1/standards/:ruleKey`\n- `GET /api/v1/standards/latest`\n- `POST /api/v1/standards`\n- `PUT /api/v1/standards/:ruleKey`\n- `GET /api/v1/standards/applicable`\n- `GET /openapi.json`\n- `GET /docs`\n\n`GET /openapi.json` includes detailed schemas for request/response payloads, validation constraints, and error responses.\n\n`GET /api/v1/standards` defaults to active latest standards. Supported filters:\n\n- `status`: `active`, `draft`, `deprecated`\n- `category`: `reliability`, `security`, `observability`, `performance`, `cost`, `maintainability`, `architecture`, `compliance`\n- `severity`: `critical`, `high`, `medium`, `low`, `info`\n- `owner`\n- `limit`\n- `offset`\n\nValidation notes:\n\n- `limit` must be `1.500`\n- `offset` must be `\u003e= 0`\n- invalid filters return `400` with `error.code = \"validation_error\"`\n\n`GET /api/v1/standards/applicable` accepts:\n\n- `repo`\n- `team`\n- `language`\n- `framework`\n- `runtime`\n- `environment`\n- `changed_paths`, comma-separated file paths\n\nValidation notes:\n\n- `changed_paths` must be a comma-separated list with no empty entries (for example, `src/a.ts,infra/main.tf`)\n- malformed `changed_paths` returns `400` with `error.code = \"validation_error\"`\n\n`GET /api/v1/standards/:ruleKey` returns the latest version for the provided `rule_key`, or `404` if it does not exist.\n\nMatching is deterministic:\n\n- Only active rules are returned.\n- Empty or missing `applies_to` fields are global for that field.\n- If an `applies_to` field has values, the request must match one of those values.\n- Supported fields are `languages`, `frameworks`, `runtimes`, `file_patterns`, `teams`, `repos`, and `environments`.\n- `changed_paths` is parsed as comma-separated file paths.\n- `file_patterns` use glob matching against `changed_paths`.\n- A rule with no file patterns can still match on repo, team, language, framework, runtime, or environment.\n- Each returned applicable rule includes `match_reason`.\n\n`/api/v1/standards/latest` and `/api/v1/standards/applicable` return:\n\n```json\n{\n  \"standards_version\": \"2026-05-18T15:30:00.000Z-count-6\",\n  \"rules\": []\n}\n```\n\nThe current `standards_version` is generated from the latest `updated_at` timestamp among returned rules and the returned rule count.\n\n## Write API Key\n\nWrite endpoints are `POST /api/v1/standards` and `PUT /api/v1/standards/:ruleKey`.\n\n- If `NODE_ENV=production`, writes require `x-api-key`.\n- If `STANDARDS_API_KEY` is set in any environment, writes require `x-api-key`.\n- In non-production, writes are allowed without a key only when `STANDARDS_API_KEY` is unset.\n- Missing or invalid keys return a JSON `401` response with `error.code = \"unauthorized\"`.\n\nWrite payload notes:\n\n- `rule_key` format for create: `^[A-Z0-9]+(?:-[A-Z0-9]+)+-\\d{3,}$` (example: `SRE-K8S-003`)\n- for create, `rule_key`, `title`, `description`, `severity`, `category`, `applies_to`, `rule_text`, `review_guidance`, and `owner` are required\n- `status` defaults to `draft` and `version` defaults to `1` when omitted\n- if `status=deprecated`, `deprecated_at` is required in create payloads\n- `PUT /api/v1/standards/:ruleKey` always returns `201`; it updates drafts in place and creates a new version for active/deprecated rules\n\nError response shape for non-2xx responses:\n\n```json\n{\n  \"error\": {\n    \"code\": \"validation_error\",\n    \"message\": \"Request validation failed\",\n    \"details\": {}\n  }\n}\n```\n\n## Example Curl Commands\n\nHealth:\n\n```bash\ncurl http://localhost:3000/health\n```\n\nList active standards:\n\n```bash\ncurl http://localhost:3000/api/v1/standards\n```\n\nGet a standard:\n\n```bash\ncurl http://localhost:3000/api/v1/standards/SRE-K8S-003\n```\n\nCreate a standard:\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/standards \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"rule_key\": \"PERF-API-010\",\n    \"title\": \"Pagination required for collection endpoints\",\n    \"description\": \"Collection endpoints must support bounded pagination.\",\n    \"status\": \"active\",\n    \"severity\": \"medium\",\n    \"category\": \"performance\",\n    \"applies_to\": {\n      \"languages\": [\"typescript\"],\n      \"file_patterns\": [\"src/**/*.ts\"]\n    },\n    \"rule_text\": \"Collection endpoints must enforce page size limits.\",\n    \"review_guidance\": \"Look for unbounded list queries and missing limit parameters.\",\n    \"owner\": \"api-platform\",\n    \"version\": 1\n  }'\n```\n\nGet ReviewOps applicable standards:\n\n```bash\ncurl 'http://localhost:3000/api/v1/standards/applicable?repo=payments-api\u0026team=platform\u0026language=typescript\u0026environment=production\u0026changed_paths=src/client.ts,infra/main.tf'\n```\n\nGet Kubernetes standards for a changed manifest:\n\n```bash\ncurl 'http://localhost:3000/api/v1/standards/applicable?framework=kubernetes\u0026runtime=container\u0026environment=production\u0026changed_paths=deploy/deployment.yaml'\n```\n\n## Example ReviewOps Response\n\n```json\n{\n  \"standards_version\": \"2026-05-18T19:42:00.000Z-count-1\",\n  \"rules\": [\n    {\n      \"id\": \"c3c3d7a9-2e30-4c12-9f18-0bcb4b5f4b7a\",\n      \"rule_key\": \"REL-NET-004\",\n      \"title\": \"External calls must define timeouts/retries\",\n      \"description\": \"External network calls must bound latency and define retry behavior appropriate to idempotency.\",\n      \"status\": \"active\",\n      \"severity\": \"high\",\n      \"category\": \"reliability\",\n      \"applies_to\": {\n        \"languages\": [\"typescript\", \"javascript\", \"go\", \"python\"],\n        \"file_patterns\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.go\", \"src/**/*.py\"]\n      },\n      \"rule_text\": \"Every external HTTP/RPC call must define a timeout and explicit retry policy.\",\n      \"review_guidance\": \"Inspect clients and SDK calls for configured timeouts, retry limits, and backoff.\",\n      \"good_example\": \"fetch(url, { signal: AbortSignal.timeout(3000) }) with bounded retry wrapper.\",\n      \"bad_example\": \"await fetch(url)\",\n      \"owner\": \"platform\",\n      \"version\": 1,\n      \"created_at\": \"2026-05-18T19:42:00.000Z\",\n      \"updated_at\": \"2026-05-18T19:42:00.000Z\",\n      \"deprecated_at\": null,\n      \"match_reason\": \"Matched language=typescript and Matched changed_paths=src/client.ts\"\n    }\n  ]\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flafronzt%2Fstandards-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flafronzt%2Fstandards-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flafronzt%2Fstandards-api/lists"}