{"id":51608690,"url":"https://github.com/writer/aperio","last_synced_at":"2026-07-12T04:30:27.979Z","repository":{"id":362765874,"uuid":"1260666630","full_name":"writer/aperio","owner":"writer","description":"Open-source SSPM for SIEM-native teams: detect SaaS posture risks, inventory OAuth shadow IT, and stream normalized findings to your security stack.","archived":false,"fork":false,"pushed_at":"2026-06-22T14:51:58.000Z","size":3015,"stargazers_count":0,"open_issues_count":29,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T16:27:32.951Z","etag":null,"topics":["cloud-security","cybersecurity","identity-security","mcp","multi-tenant","oauth","oauth-security","posture-management","saas","saas-security","security-automation","security-monitoring","security-posture-management","shadow-it","siem","sspm"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/writer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-06-05T18:34:05.000Z","updated_at":"2026-06-22T14:53:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/writer/aperio","commit_stats":null,"previous_names":["writer/aperio"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/writer/aperio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/writer%2Faperio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/writer%2Faperio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/writer%2Faperio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/writer%2Faperio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/writer","download_url":"https://codeload.github.com/writer/aperio/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/writer%2Faperio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35382323,"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-07-12T02:00:06.386Z","response_time":87,"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":["cloud-security","cybersecurity","identity-security","mcp","multi-tenant","oauth","oauth-security","posture-management","saas","saas-security","security-automation","security-monitoring","security-posture-management","shadow-it","siem","sspm"],"created_at":"2026-07-12T04:30:27.158Z","updated_at":"2026-07-12T04:30:27.974Z","avatar_url":"https://github.com/writer.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Aperio\n\n**SaaS Detection \u0026 Response on top of Cerebro.**\n\nAperio is an open-source SaaS Detection \u0026 Response platform. It connects to your SaaS estate, fires Cerebro-grounded SaaS detections, opens human-owned incidents with a replayable timeline, runs human-gated response actions with separation of duties, and forwards every lifecycle event to the SIEM you already operate. The current `main` branch ships a Go/ConnectRPC API backed by Prisma/Postgres data, a Next.js operator console, an stdio MCP broker, an ingestion worker, an optional NATS JetStream event bus, and a durable SIEM dispatcher with adapters for Splunk HEC, Panther, Panopticon, Elasticsearch, Datadog Logs, generic webhooks, and JSON Lines files.\n\nIn practical terms, Aperio ingests connector events, evaluates SaaS detection rules, opens and dedupes incidents enriched with Cerebro graph and claim context, gates response actions behind two-person approval, and fans canonical `aperio.finding.v1` envelopes out to your SIEM destinations.\n\n![Node](https://img.shields.io/badge/Node-20%2B-green?style=flat\u0026logo=node.js) ![Next.js](https://img.shields.io/badge/Next.js-16-black?style=flat\u0026logo=next.js) ![Prisma](https://img.shields.io/badge/Prisma-5-2D3748?style=flat\u0026logo=prisma) ![License](https://img.shields.io/badge/License-MIT-blue.svg)\n\n---\n\n## Current capabilities\n\n- **Connector catalog** — built-in support for GitHub, Slack, Google Workspace, Okta, 1Password, Microsoft 365, and Atlassian (Jira \u0026 Confluence), with encrypted credential storage (AES-256-GCM) and per-check toggles.\n- **SaaS detections** — public-repo detection (GitHub), MFA-disabled detection (Slack), and a deep Google Workspace pack covering external sharing, admin posture (super-admin 2SV, recovery emails), Gmail auto-forwarding / delegates / send-as, and the domain-wide-delegation allow-list.\n- **Shadow IT** — per-user `users.tokens.list` scan that catalogs every third-party OAuth app users have authorized, with graduated risk scoring (CRITICAL/HIGH/MEDIUM/LOW) calibrated against Google scope sensitivity.\n- **Findings lifecycle** — auto-resolution on next sync when the underlying signal disappears, evidence persistence, severity scoring, dedupe by stable key, and risk exceptions with compensating controls.\n- **SIEM fanout** — durable outbox with adapters for Splunk HEC, Panther, Panopticon, Elasticsearch, Datadog Logs, generic webhooks, and JSON Lines file sinks. Canonical envelope `aperio.finding.v1`.\n- **Event contracts** — protobuf-backed Aperio lifecycle envelopes wrapped in Cerebro-compatible `EventEnvelope` messages, with optional NATS JetStream publishing for ingestion, finding lifecycle, and claim fanout events.\n- **Remediation** — real handlers for Okta (suspend, reset MFA) and Slack (revoke OAuth app); the rest are stubbed and pluggable.\n- **Operator console** — Next.js app with dashboard, findings, apps, shadow IT, security graph, connectors, SIEM destinations, and admin pages. Full-text command palette, role-aware navigation, MFA enrollment.\n- **Agents and MCP** — tenant-scoped agent runtime that creates `AgentProposal` rows requiring human approval before any provider-side write executes. An stdio MCP broker mirrors core task and SIEM actions over JSON-RPC for MCP-native clients.\n- **Multi-tenant by default** — every entity is scoped to an `Organization`. Tenant isolation is enforced at the route, repository, and integration layer, with cross-tenant test coverage in `internal/bootstrap/tenant_isolation_test.go`.\n\n---\n\n## Architecture\n\n```\n            Operator console (Next.js)        MCP clients (stdio)\n                       |                              |\n                       v                              v\n              Go/ConnectRPC API                 MCP broker\n             (cmd/aperio, internal)     (cmd/mcp-broker, internal/mcpbroker)\n                       |\n        +-----------------------------+\n        |              |              |\n        v              v              v\n   Connectors    Detection      SIEM dispatcher\n  (GitHub,      rules +         (outbox worker)\n   Slack,       findings              |\n   Google,      lifecycle             v\n   Okta,         |              Splunk / Panther /\n   1Pass,        v              Panopticon / Elastic /\n   M365,    Postgres           Datadog / Webhook / JSONL\n   Atlassian)  (state)\n                  |\n                  v\n          Optional NATS JetStream\n       (Cerebro-compatible events)\n```\n\nThe Go API is the single source of truth for connector, finding, admin, auth, and SIEM workflows. The ingestion worker pulls audit-log events into the same Postgres state store. The SIEM dispatcher reads the `SiemDelivery` outbox and ships each finding to every enabled destination with retry/backoff. When `APERIO_EVENT_BUS=nats`, Go and worker processes also publish validated protobuf lifecycle events to JetStream; otherwise publishing is a safe no-op. Credentials are encrypted at rest with AES-256-GCM via `packages/security`.\n\n---\n\n## Quick start\n\n### Prerequisites\n\n- Node.js 20+ (the repo targets the active LTS line).\n- Go 1.25+ (for the ConnectRPC API in `cmd/aperio`).\n- Docker (for local Postgres and NATS via `docker-compose.yml`) or any reachable Postgres 15+.\n- npm 10+ (ships with Node 20).\n- GNU Make (preinstalled on macOS and most Linux distros) to use the `make` targets below.\n\n### First run\n\nThe fastest path uses the Makefile; run `make help` to see every target.\n\n```bash\ngit clone https://github.com/writer/Aperio.git\ncd Aperio\nmake setup                          # .env, deps, Postgres, migrations, and seed data\nmake dev                            # Go API on :4100 + Next.js console on :3000\n```\n\n`DATABASE_URL` in `.env` is the single source of truth for the local Postgres port: `make` publishes the docker-compose database on the port embedded there and hands the Go server a pgx-compatible DSN automatically (Prisma's `?schema=public` is stripped and `sslmode=disable` is added for local connections).\n\nPrefer to run each step yourself? The manual flow is equivalent:\n\n```bash\ngit clone https://github.com/writer/Aperio.git\ncd Aperio\n\ndocker compose up -d                # local Postgres on :5432\nnpm install\ncp .env.example .env                # fill in local secrets before sharing\nnpm run db:generate\nnpx prisma migrate dev --schema packages/db/prisma/schema.prisma\n\n# create your local .env (see Configuration below for the full reference)\ncat \u003e .env \u003c\u003cEOF\nDATABASE_URL=\"postgresql://aperio:aperio@localhost:5432/aperio?schema=public\"\nAPERIO_ENCRYPTION_KEY=\"base64:$(openssl rand -base64 32)\"\nAPERIO_AUTH_SECRET=\"$(openssl rand -hex 32)\"\nAPERIO_WEB_ORIGIN=\"http://localhost:3000\"\nNEXT_PUBLIC_CONNECT_API_BASE_URL=\"http://localhost:4100\"\nEOF\n\n# start the API and the web console in two shells\nnpm run dev:connect                 # http://localhost:4100\nnpm run dev:web                     # http://localhost:3000\n```\n\nThe first time you sign in, run the seed script to provision a demo organization, owner user, and example findings:\n\n```bash\nnpx tsx scripts/seed.ts\n```\n\n### Background workers\n\nLong-running pipelines run as separate processes. The event bus is optional; set `APERIO_EVENT_BUS=nats` to publish protobuf envelopes to the local NATS service started by `npm run dev`.\n\nThe default worker and MCP commands are Go-owned. Worker commands load local `.env` settings and derive a pgx-safe Postgres DSN with `scripts/dev-config.mjs go-database-url`, so Prisma-only query parameters are not passed to Go database clients.\n\n```bash\nnpm run worker:ingestion -- -once -limit 1  # Go ingestion worker\nnpm run worker:siem -- -once -limit 1       # Go SIEM dispatcher\nnpm run mcp:broker                         # Go stdio MCP broker for agent clients\n```\n\nRemaining TypeScript is limited to the Next.js frontend, generated clients/contracts, tests, Prisma, and local tooling.\n\n---\n\n## Choose your path\n\n| Goal | Start here | Notes |\n| --- | --- | --- |\n| Run the API only | `npm run dev:connect` | Go/ConnectRPC server on `:4100`; serves native RPCs, compatibility calls, and OAuth callbacks. |\n| Run the operator console | `npm run dev:web` | Next.js dev server on `:3000`; expects the API at `NEXT_PUBLIC_CONNECT_API_BASE_URL`. |\n| Seed demo data | `npx tsx scripts/seed.ts` | Idempotent; creates Aperio Demo Security org + owner/admin/analyst users. |\n| Connect Google Workspace | `/connectors` → Google Workspace | Uses OAuth; needs `GOOGLE_WORKSPACE_*` env vars. |\n| Connect other providers | `/connectors` → pick provider | GitHub, Slack, Okta, 1Password, M365, Atlassian use scoped tokens or service accounts. |\n| Wire up a SIEM | `/connectors` → SIEM destinations | Splunk HEC, Panther, Panopticon, Elasticsearch, Datadog Logs, generic webhook, JSONL sink. |\n| Audit shadow IT | `/shadow-it` | Lists every third-party OAuth app users have granted, with per-user drilldown. |\n| Author detection rules | `internal/ingestionworker` | Go rules produce findings and SIEM deliveries from queued ingestion events. |\n| Inspect the schema | `packages/db/prisma/schema.prisma` | Single Prisma schema for all entities. |\n| Run all checks | `npm run verify` | Aggregate gate for generation, typecheck, guardrails, tests, build, smokes, production audit, and leak check. |\n\n---\n\n## Configuration\n\nAperio reads runtime configuration from environment variables. Create a `.env` file at the repository root (it is gitignored).\n\n### Core variables\n\n| Variable | Purpose | Default |\n| --- | --- | --- |\n| `DATABASE_URL` | Postgres connection string consumed by Prisma | required |\n| `APERIO_ENCRYPTION_KEY` | base64-encoded 32-byte key used for AES-256-GCM credential encryption | required |\n| `APERIO_AUTH_SECRET` | HMAC secret for session cookies and email tokens | required |\n| `APERIO_WEB_ORIGIN` | canonical origin for the Next.js console; used for CORS and OAuth redirects | `http://localhost:3000` |\n| `NEXT_PUBLIC_CONNECT_API_BASE_URL` | base URL the web app uses to call the Go/ConnectRPC API | `http://localhost:4100` |\n| `APERIO_SESSION_TTL_HOURS` | absolute session lifetime | `12` |\n| `APERIO_SESSION_IDLE_MINUTES` | idle session timeout | `120` |\n| `APERIO_MFA_ISSUER` | TOTP issuer label shown in authenticator apps | `Aperio` |\n| `APERIO_EVENT_BUS` | optional event publisher backend; set to `nats` to enable JetStream fanout | unset / noop |\n| `APERIO_NATS_URL` | NATS server URL used when event bus publishing is enabled | `nats://127.0.0.1:4222` |\n| `APERIO_NATS_STREAM` | JetStream stream for Cerebro-compatible event envelopes | `CEREBRO_EVENTS` |\n\n### Cerebro integration\n\nWhen `CEREBRO_BASE_URL`, a credential, and `CEREBRO_TENANT_ID` are configured,\nthe Go API and ingestion worker ensure Aperio's Cerebro source runtime at\nstartup. The ingestion worker also writes supported findings directly to\nCerebro as tenant-scoped claims. Leave these unset for local-only development\nwithout Cerebro.\n\n| Variable | Purpose | Default |\n| --- | --- | --- |\n| `CEREBRO_BASE_URL` | Hosted Cerebro API origin, for example `https://cerebro.example.com` | unset |\n| `CEREBRO_MCP_URL` | Optional explicit Cerebro Streamable HTTP MCP endpoint shown in incident context | derived from `CEREBRO_BASE_URL` |\n| `CEREBRO_API_KEY` | Tenant-scoped Cerebro API key sent as `Authorization: Bearer` | unset |\n| `CEREBRO_TOKEN` | Backward-compatible fallback when `CEREBRO_API_KEY` is not set | unset |\n| `CEREBRO_TENANT_ID` | Tenant id sent as `X-Cerebro-Tenant` and stored on the source runtime | unset |\n| `CEREBRO_SOURCE_RUNTIME_ID` | Source runtime id Aperio ensures in Cerebro | `writer-aperio-saas-dr` |\n| `CEREBRO_SOURCE_ID` | Cerebro source id for the Aperio SaaS DR runtime | `aperio_saas_dr` |\n| `CEREBRO_HTTP_TIMEOUT_SECONDS` | Timeout for startup runtime ensure and Cerebro HTTP calls | `15` |\n\n### Email\n\n| Variable | Purpose | Default |\n| --- | --- | --- |\n| `APERIO_EMAIL_PROVIDER` | currently supports `resend` | unset (transactional email disabled) |\n| `APERIO_RESEND_API_KEY` | Resend API key | unset |\n| `APERIO_EMAIL_FROM` | RFC 5322 `From:` header | unset |\n\n### Google Workspace OAuth\n\n| Variable | Purpose |\n| --- | --- |\n| `GOOGLE_WORKSPACE_CLIENT_ID` | Google OAuth client ID (`...apps.googleusercontent.com`) |\n| `GOOGLE_WORKSPACE_CLIENT_SECRET` | Google OAuth client secret |\n| `GOOGLE_WORKSPACE_REDIRECT_URI` | OAuth callback (defaults to `${API}/api/v1/integrations/google-workspace/oauth/callback`) |\n| `GOOGLE_WORKSPACE_SERVICE_ACCOUNT_CLIENT_EMAIL` | optional; used for DWD-impersonated Gmail forwarding scans |\n| `GOOGLE_WORKSPACE_SERVICE_ACCOUNT_PRIVATE_KEY` | PEM private key for the same service account |\n\n### Backups (optional)\n\n| Variable | Purpose | Default |\n| --- | --- | --- |\n| `APERIO_BACKUP_STORAGE_URL` | destination URL (e.g. `s3://bucket/path`) | unset |\n| `APERIO_BACKUP_SCHEDULE` | cron expression | `0 */6 * * *` |\n| `APERIO_BACKUP_RETENTION_DAYS` | retention horizon | `30` |\n\n### Generating secrets\n\n```bash\n# 32-byte AES key, base64-encoded\necho -n \"base64:$(openssl rand -base64 32)\"\n\n# 64-char hex auth secret\nopenssl rand -hex 32\n```\n\n---\n\n## Built-in connectors\n\n| Provider | Auth model | What it detects today |\n| --- | --- | --- |\n| GitHub | PAT or GitHub App | Public repositories in the org |\n| Slack | User OAuth token (`xoxp-`) | Workspace 2FA enforcement disabled |\n| Google Workspace | OAuth + optional service account | External sharing, super-admin 2SV, recovery emails, Gmail auto-forwarding / delegates / send-as, domain-wide delegations, shadow-IT OAuth grants |\n| Okta | OIDC API Services (private-key JWT) | Connection only; rule pack pending |\n| 1Password | SCIM bridge bearer token | Connection only; rule pack pending |\n| Microsoft 365 | Graph API delegated/app token | Connection only; rule pack pending |\n| Atlassian (Jira \u0026 Confluence) | OAuth + audit-log read | Connection only; rule pack pending |\n\n---\n\n## SIEM destinations\n\nThe SIEM dispatcher writes a canonical `aperio.finding.v1` envelope and adapts it to each destination:\n\n| Destination | Transport | Authentication |\n| --- | --- | --- |\n| Splunk HEC | HTTPS POST | HEC token |\n| Panther | HTTPS POST | API token |\n| Panopticon | HTTPS POST | API key |\n| Elasticsearch | HTTPS POST `_bulk` | basic / API key |\n| Datadog Logs | HTTPS POST | DD API key |\n| Generic Webhook | HTTPS POST | HMAC signature header |\n| JSON Lines File | local filesystem write | none |\n\nEach delivery row is durable, retried with exponential backoff, and de-duplicated by finding ID + destination ID.\n\n---\n\n## Scripts\n\nEvery workflow below is also wrapped by the Makefile — run `make help` for the full list (`make dev`, `make verify`, `make test`, `make migrate`, and more). The underlying npm scripts remain available:\n\n```bash\nnpm run dev:connect            # Go ConnectRPC API on :4100\nnpm run dev:web                # Next.js console on :3000\nnpm run worker:ingestion       # Go ingestion worker\nnpm run worker:siem            # Go SIEM dispatcher worker\nnpm run mcp:broker             # Go stdio MCP broker\nnpm run build:web              # production Next.js build\nnpm run proto:lint             # Buf lint for protobuf contracts\nnpm run proto:check            # lint, regenerate, and verify generated code is current\nnpm run test:go                # Go unit tests for ConnectRPC service\nnpm run typecheck              # tsc --noEmit\nnpm run test:api               # node --test (tsx loader)\nnpm run verify                 # aggregate final gate: generate, typecheck, guardrails, tests, build, smokes, audit, leak check\nnpm run db:generate            # prisma generate\nnpm run db:validate            # prisma validate\nnpm run backup:check           # backup-readiness preflight\nnpm run audit:prod             # npm audit --omit=dev\n```\n\nUse the full preflight before opening a PR:\n\n```bash\nnpm run verify\n```\n\nProduction deployments should pair Aperio's process-local route limits with edge or load-balancer rate limiting. Ingestion and SIEM delivery both use database-backed queues so accepted events and outbound deliveries survive API restarts.\n\n---\n\n## Go / ConnectRPC backend\n\nAperio's API runtime is Go/ConnectRPC. Native RPCs serve first-class read paths, and the `CallApi` compatibility RPC preserves the existing `/api/v1/*` web contract while remaining REST-shaped workflows are promoted into typed RPCs.\n\n| Surface | Purpose |\n| --- | --- |\n| `cmd/aperio/main.go` | Go process entrypoint, listening on `APERIO_CONNECT_ADDR` (`:4100` locally) |\n| `internal/bootstrap` | ConnectRPC handler wiring, CORS, cookie-session auth, compatibility dispatch, dashboard metrics query |\n| `proto/aperio/v1/api.proto` | Stable service contract for `AperioService` |\n| `gen/aperio/v1` | Generated Go protobuf and ConnectRPC handlers |\n| `packages/connect/src` | Generated TypeScript contracts plus browser Connect client |\n\nThe web app talks to the Go API through `NEXT_PUBLIC_CONNECT_API_BASE_URL`, for example:\n\n```bash\nDATABASE_URL=postgresql://aperio:aperio@localhost:5432/aperio npm run dev:connect\nNEXT_PUBLIC_CONNECT_API_BASE_URL=http://localhost:4100 npm run dev:web\n```\n\nAuthentication uses the `aperio_session` HttpOnly cookie and the `user_sessions` table. The Go service validates the cookie token hash directly in Postgres and only reflects the configured `APERIO_WEB_ORIGIN` for credentialed browser calls.\n\nProtobuf contracts follow Cerebro-style Buf conventions:\n\n```bash\nnpm run proto:lint\nnpm run proto:check\nnpm run test:go\n```\n\nEvent contracts live in `proto/aperio/contracts/v1/events.proto` and are encoded from `packages/shared/src/protobuf-contracts.ts` and `internal/bootstrap/event_bus.go`. Producers validate required envelope attributes before publishing so consumers can filter by schema, kind, tenant, finding, delivery, or job id without decoding every payload.\n\n---\n\n## HTTP API surface\n\nNative Go-backed RPCs live under ConnectRPC procedure paths such as `/aperio.v1.AperioService/GetDashboardMetrics`. The web console still uses REST-shaped `/api/v1/*` compatibility paths through the `CallApi` RPC while those workflows move to typed RPCs. Key compatibility groups:\n\n| Prefix | Purpose |\n| --- | --- |\n| `/auth/*` | Session login, signup, password reset, MFA enrollment |\n| `/admin/*` | Organization settings, users, roles, audit log |\n| `/integrations/*` | Connector lifecycle, OAuth start/callback, force-sync, per-check toggles |\n| `/findings/*` | List, filter, view, resolve, suppress, export |\n| `/remediations/*` | Propose, approve, execute provider-side fixes |\n| `/dashboard/*` | Aggregated metrics, trend lines, top assets |\n| `/security/*` | Security graph and posture overview |\n| `/shadow-it/*` | OAuth apps inventory and per-app user drilldown |\n| `/siem/*` | SIEM destinations CRUD and delivery introspection |\n| `/agents/*` | Agent tasks, messages, and proposals (human-approval gated) |\n\nThe Go MCP broker (`cmd/mcp-broker` and `internal/mcpbroker`) exposes a JSON-RPC superset of the task and SIEM surfaces for agent clients.\n\n---\n\n## Repository layout\n\n```\naperio/\n├── apps/\n│   └── web/                # Next.js operator console\n├── cmd/aperio/             # Go ConnectRPC server entrypoint\n├── cmd/ingestion-worker/   # Go ingestion worker entrypoint\n├── cmd/mcp-broker/         # Go stdio MCP broker entrypoint\n├── cmd/siem-dispatcher/    # Go SIEM dispatcher entrypoint\n├── gen/                    # Generated Go protobuf/ConnectRPC code\n├── internal/               # Go service config and bootstrap packages\n├── packages/\n│   ├── connect/            # TypeScript ConnectRPC client and generated contracts\n│   ├── db/                 # Prisma schema and client\n│   ├── security/           # AES-256-GCM helpers and password hashing\n│   └── shared/             # Zod schemas, connector catalog, SIEM catalog\n├── proto/                  # ConnectRPC API + Cerebro-compatible event contracts\n├── workers/                # TypeScript validation helpers only\n├── scripts/                # dev orchestration, seed, and operational scripts\n├── tests/                  # node --test suites\n├── droid-wiki/             # generated architecture and reference docs\n└── docker-compose.yml      # local Postgres\n```\n\n---\n\n## Documentation\n\nThe `droid-wiki/` directory contains generated documentation. Useful entry points:\n\n| Document | Notes |\n| --- | --- |\n| [Overview](droid-wiki/overview/index.md) | High-level introduction and repo map |\n| [Architecture](droid-wiki/overview/architecture.md) | Layered architecture description |\n| [Getting started](droid-wiki/overview/getting-started.md) | Local setup walkthrough |\n| [Glossary](droid-wiki/overview/glossary.md) | Domain terms used across the codebase |\n| [Apps](droid-wiki/apps/index.md) | API, web, MCP entry points |\n| [Features](droid-wiki/features/index.md) | Connectors, findings, SIEM, admin, agents |\n| [Packages](droid-wiki/packages/index.md) | `db`, `shared`, `security` package guides |\n| [API](droid-wiki/api/index.md) | Route reference |\n| [Security](droid-wiki/security.md) | Threat model and security controls |\n| [Reference](droid-wiki/reference/index.md) | Configuration, data models, dependencies |\n| [How to contribute](droid-wiki/how-to-contribute/index.md) | Workflow, testing, debugging, conventions |\n\n---\n\n## Stack\n\n| Component | Technology |\n| --- | --- |\n| Language | TypeScript 5.7, Go 1.25 |\n| Runtime | Node.js 20+, Go `net/http` |\n| API server | Go `net/http` + ConnectRPC |\n| Web console | Next.js 16 + React 18 + Tailwind |\n| ORM | Prisma 5 |\n| Database | PostgreSQL 15+ |\n| Background workers | Go ingestion worker + Go SIEM dispatcher with database-backed queues/outbox |\n| Contracts | Protobuf + Buf + generated Go/TypeScript clients + Cerebro event envelopes |\n| Event bus | Optional NATS JetStream (`APERIO_EVENT_BUS=nats`) |\n| Validation | Zod |\n| MCP transport | stdio JSON-RPC |\n| Auth | Cookie sessions, TOTP MFA, RBAC |\n| Crypto | AES-256-GCM (`packages/security`) |\n| Connector catalog | GitHub, Slack, Google Workspace, Okta, 1Password, Microsoft 365, Atlassian |\n| SIEM adapters | Splunk HEC, Panther, Panopticon, Elasticsearch, Datadog Logs, generic webhook, JSONL |\n| Testing | `node --test` via `tsx`, plus `prisma validate` and `tsc --noEmit` |\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwriter%2Faperio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwriter%2Faperio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwriter%2Faperio/lists"}