Documentation

Full specification & API reference

MCP integration, adding a new application, postback payload contracts, authentication, and the BigQuery schema every registered app streams into.

01 · Onboarding Guide

How to Add a New App

The three-step path from an integration ticket to a shipped postback dispatcher.

Open an Integration Ticket

Step 1 · Submit an integration ticket

Open a GitHub Issue on the repo — it auto-populates as a ticket on the project board, no separate account or board access needed — specifying your sourceApp identifier (e.g. "my-task-app"), target domain group, and allowlisted DomainEventType names.

Step 2 · Enum & table provisioning

The Monolith maintainer registers SourceApp.java and DomainEventType.java enums, and provisions BigQuery destination tables (my_task_app_tasks) with permanent retention and daily partitioning.

Step 3 · Implement the postback dispatcher

Add non-blocking event dispatching in your application using your preferred programming language:

import { after } from "next/server";

export function recordDomainEvent(event: {
  eventType: string;
  userId: string;
  userEmail: string;
  entityId?: string;
  payload?: Record<string, any>;
}) {
  after(async () => {
    await fetch("https://monolith-postbacks.adithyakrishnan.com/api/v1/events/postback", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${process.env.MONOLITH_API_KEY}`,
      },
      body: JSON.stringify({
        sourceApp: "my-task-app",
        eventId: crypto.randomUUID(),
        eventType: event.eventType,
        userId: event.userId,
        entityId: event.entityId,
        itemCount: 1,
        timestamp: Date.now(),
        payload: {
          ...event.payload,
          userEmail: event.userEmail,
          environment: process.env.NODE_ENV || "production",
        },
      }),
    });
  });
}
02 · Telemetry Ingestion

Postback & Payload Spec

Field-level contract for every event Monolith accepts, and what happens when it doesn't validate.

POST https://monolith-postbacks.adithyakrishnan.com/api/v1/events/postback

Required & recommended fields

Field NameData TypeStatusDescription & Standard
sourceAppSTRINGREQUIREDApplication identifier (e.g. continuum-home). Must match registered SourceApp.java enum.
eventTypeSTRINGREQUIREDAllowlisted event enum (e.g. EXPENSE_CREATED, SALARY_UPDATED). Resolves BigQuery target table.
userIdSTRINGREQUIREDUser UID in source system. Used for BigQuery clustering and analytics indexing.
payload.userEmailSTRINGREQUIREDThe user's primary email. Direct payload field for multi-app user identity cross-referencing without joins.
eventIdSTRINGRECOMMENDEDUUID event insertId. Used as BigQuery insertId for automatic retry deduplication.
itemCountINT64OPTIONALAffected row count (default 1). Set >1 for CSV batch imports or bulk sync operations.
payload.environmentSTRINGRECOMMENDEDEnvironment tag (production, uat, test). Views filter non-production rows automatically.

Sample standard postback payload

{
  "sourceApp": "continuum-home",
  "eventId": "a7826cd3-fbe0-4503-ae48-200e598ed031",
  "eventType": "EXPENSE_CREATED",
  "userId": "imm9N7AL1Nf0QQR7u6WfpXqdp5D3",
  "itemCount": 1,
  "timestamp": 1787726400000,
  "payload": {
    "amount": 4200.0,
    "category": "Rent",
    "userEmail": "adiadithyakrishnan@gmail.com",
    "environment": "production"
  }
}
03 · Authentication & Security

API Keys & Auth Setup

A zero-trust, fails-closed model with three authentication paths depending on where your app runs.

Fails-Closed HTTP 401 Enforcement

Overview

Monolith enforces a zero-trust, fails-closed authentication model. Incoming postbacks and MCP tool calls are verified before processing, preventing unauthorized data writes or reads.

Three authentication paths

1. Google OIDC

Services on GCP, Firebase, or Google Auth send standard Google ID Tokens (Authorization: Bearer <id_token>). Verified via Google's public key verifier with zero Secret Manager setup required.

2. Shared Platform Key

Backend applications pass the platform postback key (MONOLITH_API_KEY). Evaluated using constant-time comparison (MessageDigest.isEqual) to prevent timing-attack side channels.

3. Multi-User MCP Keys

AI coding agents access /api/mcp using registered user tokens, configured via (MCP_USERS JSON map or MCP_API_KEY fallback).

Multi-user MCP configuration example

# Server-Side Allowed MCP Users (JSON Map: Email -> Token)
MCP_USERS='{"adiadithyakrishnan@gmail.com": "mcp_key_continuum_9918"}'

# Single Key Fallback
MCP_API_KEY="mcp_key_fallback_12345"
04 · AI Agent Protocol

MCP Server & AI Tools

How AI coding agents connect to Monolith's telemetry graph over the Model Context Protocol.

Overview

Monolith exposes an HTTP Model Context Protocol (MCP) server over SSE stream transport. AI coding assistants — Cursor, Claude Code, Antigravity — use this endpoint to inspect user event history, salary logs, domain telemetry, and BigQuery schemas directly inside the IDE, without a human ever running a query by hand.

https://monolith.adithyakrishnan.com/api/mcpSSE stream transport

Client configuration mcp_config.json

{
  "mcpServers": {
    "monolith-telemetry": {
      "url": "https://monolith.adithyakrishnan.com/api/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_MCP_USER_KEY"
      }
    }
  }
}

Registered MCP tool dictionary

query_user_activity

Queries complete user event history, salary logs, watchlists, and domain activity across all apps by email.

Inputs: email, limit
query_domain_events

Filters domain events by source application (continuum-home), domain group, or event enum name.

Inputs: sourceApp, domain, eventType
get_bigquery_schema

Fetches table definitions, partitioning options, and SQL view specifications directly into the agent.

Inputs: None
get_system_health

Checks backend Cloud Run health, dataset bindings, Discord notifier status, and BigQuery write stream.

Inputs: None
05 · Data Warehouse Architecture

BigQuery Architecture

Dataset bindings, partitioning strategy, and the analytics views every app's events land in.

portfolio-api-505006:events

Dataset & retention

Dataset Bindingportfolio-api-505006:events
Partitioning StrategyDAY on occurred_at
Retention PolicyPermanent / Infinite Retention

Clustering keys & analytics views

Clustering Keys(local_user_id, event_type)
Unified Viewevents.all_events
User Identity Viewevents.user_activity

Sample BigQuery user activity query

SELECT
  COALESCE(JSON_VALUE(e.payload.userEmail), 'adiadithyakrishnan@gmail.com') AS email,
  e.source_app,
  e.event_type,
  COUNT(*) AS total_events,
  MAX(e.occurred_at) AS last_activity
FROM `portfolio-api-505006.events.all_events` e
GROUP BY 1, 2, 3
ORDER BY total_events DESC;