ITX Meeting Proxy Service

September 3, 2026 ยท View on GitHub

The ITX Meeting Proxy Service is a lightweight stateless proxy that forwards meeting-related requests to the ITX Zoom API service. It provides a thin authentication and authorization layer for the Linux Foundation's LFX platform.

๐Ÿค– AI Agent Development

If you are an AI agent (Claude, Cursor, Copilot, etc.) working on this codebase, read CLAUDE.md in full before making any changes. It contains the authoritative architecture overview, coding conventions (audit stamping, PII redaction, pointer helpers, license headers), all environment variables, and the complete API endpoint inventory.

AGENTS.md at the repo root also points here for agent-oriented runtimes.

๐Ÿš€ Quick Start

For Local Development

  1. Prerequisites

    • Go 1.25+ installed
    • Make installed
  2. Clone and Setup

    git clone https://github.com/linuxfoundation/lfx-v2-meeting-service.git
    cd lfx-v2-meeting-service
    
    # Install dependencies and git hooks
    make deps
    
  3. Configure Environment

    # Copy the example environment file and fill in your ITX credentials
    cp .env.example .env
    # Edit .env โ€” at minimum set ITX_CLIENT_ID and ITX_CLIENT_PRIVATE_KEY
    

    Minimum required environment variables:

    ITX_CLIENT_ID=your-client-id
    ITX_CLIENT_PRIVATE_KEY="$(cat path/to/private.key)"
    

    For local JWT bypass (skips Heimdall validation):

    JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL=testuser
    
  4. Run the Service

    # Run with default settings
    make run
    
    # Or run with debug logging
    make debug
    

For Deployment (Helm)

See the Deployment section below.

๐Ÿ—๏ธ Architecture

The service is a stateless HTTP proxy built using a clean architecture pattern:

  • API Layer: Goa-generated HTTP handlers and OpenAPI specifications
  • Service Layer: Request validation and ITX client orchestration
  • Domain Layer: Core request/response models and interfaces
  • Infrastructure Layer: ITX HTTP client with OAuth2 authentication

Key Features

  • Stateless Proxy: No data persistence, all state managed by ITX service
  • ITX Meeting Operations: Full CRUD operations for meetings via ITX API
  • ITX Registrant Operations: Complete registrant management via ITX API
  • ITX Past Meeting Operations: Full CRUD operations for past meeting records via ITX API
  • ITX Past Meeting Summary Operations: Retrieve and update AI-generated meeting summaries
  • ITX Past Meeting Participant Operations: Add, update, and delete past meeting participants
  • ITX Attachment Operations: Create, read, update, delete, presign, and download attachments on both active meetings and past meetings
  • Event Processing: NATS JetStream KV bucket watching for v1โ†’v2 data sync (12 event families)
  • LFID Invite Feature: Outbound LFID invites for unregistered registrants, plus invite_accepted subscriber to enrich records when invites are accepted
  • JWT Authentication: Secure API access via Heimdall integration
  • ID Mapping: Optional v1/v2 ID translation via NATS (can be disabled)
  • OpenAPI Documentation: Auto-generated API specifications served at /_meetings/openapi.*
  • OAuth2 M2M: Machine-to-machine authentication with ITX service
  • Audit Stamping: Resolves requesting principal into created_by/updated_by user objects on ITX write requests
  • PII Redaction: Strips name/email from debug log output for all audit user fields

๐Ÿ“ Project Structure

lfx-v2-meeting-service/
โ”œโ”€โ”€ cmd/                           # Application entry points
โ”‚   โ””โ”€โ”€ meeting-api/               # Main API server
โ”‚       โ”œโ”€โ”€ eventing/              # Event processor, KV handlers, invite_accepted subscriber
โ”‚       โ””โ”€โ”€ service/               # Goa-to-ITX converter functions
โ”œโ”€โ”€ charts/                        # Helm chart for Kubernetes deployment
โ”‚   โ””โ”€โ”€ lfx-v2-meeting-service/
โ”œโ”€โ”€ design/                        # Goa API design files
โ”‚   โ”œโ”€โ”€ meeting-svc.go             # Service definition (source of truth for endpoints)
โ”‚   โ””โ”€โ”€ itx_types.go               # ITX type definitions
โ”œโ”€โ”€ docs/                          # Architecture and contract documentation
โ”‚   โ”œโ”€โ”€ event-processing.md        # Event processing deep-dive
โ”‚   โ”œโ”€โ”€ itx-proxy-implementation.md
โ”‚   โ”œโ”€โ”€ tracing.md
โ”‚   โ”œโ”€โ”€ indexer-contract.md
โ”‚   โ””โ”€โ”€ fga-contract.md
โ”œโ”€โ”€ gen/                           # Generated code (DO NOT EDIT)
โ”‚   โ”œโ”€โ”€ http/                      # HTTP transport layer and OpenAPI specs
โ”‚   โ””โ”€โ”€ meeting_service/           # Service interfaces
โ”œโ”€โ”€ internal/                      # Private application code
โ”‚   โ”œโ”€โ”€ domain/                    # Business domain layer
โ”‚   โ”‚   โ”œโ”€โ”€ models/                # Domain models (CreateITXMeetingRequest, etc.)
โ”‚   โ”‚   โ”œโ”€โ”€ errors.go              # Domain-specific errors
โ”‚   โ”‚   โ”œโ”€โ”€ itx_proxy.go           # ITX proxy interface
โ”‚   โ”‚   โ”œโ”€โ”€ id_mapper.go           # ID mapper interface
โ”‚   โ”‚   โ”œโ”€โ”€ user_metadata.go       # UserMetadataReader interface
โ”‚   โ”‚   โ””โ”€โ”€ user_service.go        # UserServiceClient interface (preferred email)
โ”‚   โ”œโ”€โ”€ infrastructure/            # Infrastructure layer
โ”‚   โ”‚   โ”œโ”€โ”€ auth/                  # JWT authentication
โ”‚   โ”‚   โ”œโ”€โ”€ proxy/                 # ITX HTTP client with PII-redacted debug logging
โ”‚   โ”‚   โ”œโ”€โ”€ idmapper/              # NATS-based ID mapping
โ”‚   โ”‚   โ”œโ”€โ”€ nats/                  # NATS subsystem (preferred-email, user-metadata, invites)
โ”‚   โ”‚   โ”œโ”€โ”€ userservice/           # v1 user-service HTTP client
โ”‚   โ”‚   โ””โ”€โ”€ eventing/              # Event publishing (indexer + FGA-sync)
โ”‚   โ”œโ”€โ”€ middleware/                # HTTP middleware (logging, auth, request ID)
โ”‚   โ””โ”€โ”€ service/                   # Service layer implementation
โ”‚       โ”œโ”€โ”€ auth_service.go        # Auth service
โ”‚       โ”œโ”€โ”€ preferred_email_service.go  # NATS RPC handler for preferred email
โ”‚       โ””โ”€โ”€ itx/                   # ITX services + auditStamper
โ”œโ”€โ”€ pkg/                           # Shared packages
โ”‚   โ”œโ”€โ”€ constants/                 # NATS subjects, meeting roles, HTTP context keys
โ”‚   โ”œโ”€โ”€ models/itx/                # ITX wire types (meetings, registrants, attachments, etc.)
โ”‚   โ”œโ”€โ”€ redaction/                 # Redact(s) and RedactEmail(email) helpers
โ”‚   โ””โ”€โ”€ utils/                     # Pointer helpers, coalesce, map utils, OTel helpers
โ”œโ”€โ”€ scripts/                       # Standalone one-off data operation scripts
โ”‚   โ”œโ”€โ”€ backfill_meeting_host_credentials/
โ”‚   โ”œโ”€โ”€ backfill_participant_mappings/
โ”‚   โ”œโ”€โ”€ reindex_meetings/
โ”‚   โ””โ”€โ”€ reconcile_meeting_registrants/
โ”œโ”€โ”€ tmp/                           # Temporary ad-hoc migration scripts (not tracked in git)
โ”œโ”€โ”€ Dockerfile                     # Container build configuration
โ”œโ”€โ”€ Makefile                       # Build and development commands
โ”œโ”€โ”€ CLAUDE.md                      # AI agent guide (architecture, conventions, env vars)
โ”œโ”€โ”€ AGENTS.md                      # Agent runtime pointer โ†’ CLAUDE.md
โ””โ”€โ”€ go.mod                         # Go module definition

๐Ÿ“ก Event Processing

The service includes a comprehensive event processing system for v1โ†’v2 data synchronization. It watches NATS JetStream KV buckets for meeting-related data changes and publishes events to both indexer and FGA-sync services.

Features:

  • 12 event families: meetings, meeting-committee mappings, registrants, RSVPs, past meetings, past-meeting mappings, past meeting invitees, past meeting attendees, recordings and transcripts (shared handler), AI summaries, meeting attachments, past meeting attachments
  • RRULE occurrence calculation for recurring meetings
  • v1 user enrichment and Auth0 mapping
  • Dual publishing architecture (indexer + FGA-sync)
  • Parent-child dependency handling with retry logic
  • Separate invite_accepted NATS queue subscriber (not KV-based)

For complete details, see Event Processing Documentation.

For the data schemas, tags, access control values, and parent references for all indexed resource types โ€” see Indexer Contract.

๐Ÿ› ๏ธ Development

Prerequisites

  • Go 1.25+
  • Make
  • Git (configured with GPG signing and DCO signoff โ€” see Contributing)

Getting Started

  1. Install Dependencies

    make deps
    

    This also installs the pre-commit hook that runs gofmt and a license-header check before each commit.

  2. Generate API Code

    make apigen
    

    Generates HTTP transport, client, and OpenAPI documentation from design/ files. Run this whenever you change design/.

  3. Build the Application

    make build
    

    Creates the binary in bin/meeting-api.

Development Workflow

Running the Service

# Run with default settings
make run

# Run with debug logging
make debug

# Build and run binary directly
make build
./bin/meeting-api

Code Quality

Always run these before committing:

# Format code
make fmt

# Run linter
make lint

# Check license headers on all Go files
make license-check

# Run all tests (with race detection)
make test

# Check everything (format + lint + license headers) without modifying files
make check

API Development

When modifying the API:

  1. Update Design Files in design/ directory

  2. Regenerate Code:

    make apigen
    
  3. Verify Generation:

    make verify
    
  4. Run Tests to ensure nothing breaks:

    make test
    

Available Make Targets

TargetDescription
make allComplete build pipeline (clean, deps, apigen, fmt, lint, test, build)
make depsInstall dependencies, tools, and git hooks
make install-hooksInstall git hooks from scripts/hooks/ into .git/hooks/
make apigenGenerate API code from design files
make buildBuild the binary to bin/meeting-api
make runRun the service locally
make debugRun with debug logging
make testRun unit tests with race detection
make test-verboseRun tests with verbose output
make test-coverageGenerate HTML coverage report in coverage/
make lintRun golangci-lint
make fmtFormat Go code with gofmt
make license-checkVerify all non-generated Go, HTML, and TXT files carry LFX copyright and MIT SPDX headers (excludes gen/ and vendor/)
make checkVerify formatting, linting, and license headers without modifying files
make verifyEnsure generated code is up to date
make cleanRemove build artifacts
make docker-buildBuild Docker image
make helm-installInstall Helm chart from GHCR
make helm-install-localInstall Helm chart using local Docker image
make helm-templatesPrint rendered Helm templates
make helm-uninstallUninstall Helm chart
make helpList all available targets

๐Ÿงช Testing

# Run all tests
make test

# Run with verbose output
make test-verbose

# Generate coverage report (opens at coverage/coverage.html)
make test-coverage

๐Ÿš€ Deployment

Helm Chart

The service includes a Helm chart for Kubernetes deployment.

Prerequisites: Kubernetes Secret

Before installing the chart, create the meeting-secrets secret in the lfx namespace. The auth0_client_id and auth0_client_private_key values are in 1Password under the LFX V2 vault, in the note LFX Platform Chart Values Secrets - Local Development.

kubectl create secret generic meeting-secrets -n lfx \
  --from-literal=auth0_client_id="<client-id-from-1password>" \
  --from-file=auth0_client_private_key=./path/to/private.key

Option 1: Install from GHCR (no local code changes)

Use this if you just want to run the service without modifying its code. The image is pulled directly from the container registry:

make helm-install

# Or using Helm directly
helm upgrade --install lfx-v2-meeting-service ./charts/lfx-v2-meeting-service \
  --namespace lfx \
  --create-namespace

Option 2: Install from a Local Build (active development)

Use this if you are making changes to the service code. First, copy the example local values file (it is gitignored):

cp charts/lfx-v2-meeting-service/values.local.example.yaml \
   charts/lfx-v2-meeting-service/values.local.yaml

Then, whenever you make a code change and want to apply it:

# Rebuild the local image
make docker-build

# Install/upgrade the chart using the local image
make helm-install-local

Docker

# Build Docker image
make docker-build

# Run with Docker
docker run -p 8080:8080 \
  -e ITX_BASE_URL=https://api.dev.itx.linuxfoundation.org \
  -e ITX_CLIENT_ID=your-client-id \
  -e ITX_CLIENT_PRIVATE_KEY="$(cat path/to/private.key)" \
  linuxfoundation/lfx-v2-meeting-service:latest

๐Ÿ“– API Documentation

The service automatically generates OpenAPI documentation:

  • OpenAPI 2.0: gen/http/openapi.yaml / gen/http/openapi.json
  • OpenAPI 3.0: gen/http/openapi3.yaml / gen/http/openapi3.json

Access the live docs when the service is running:

  • http://localhost:8080/_meetings/openapi.json
  • http://localhost:8080/_meetings/openapi3.yaml

Available Endpoints

Health Checks

EndpointMethodDescription
/livezGETLiveness check
/readyzGETReadiness check

OpenAPI Documentation

EndpointMethodDescription
/_meetings/openapi.jsonGETOpenAPI 2 spec (JSON)
/_meetings/openapi.yamlGETOpenAPI 2 spec (YAML)
/_meetings/openapi3.jsonGETOpenAPI 3 spec (JSON)
/_meetings/openapi3.yamlGETOpenAPI 3 spec (YAML)

ITX Meeting Operations

EndpointMethodDescription
/itx/meetingsPOSTCreate meeting
/itx/meetings/{meeting_id}GETGet meeting details
/itx/meetings/{meeting_id}PUTUpdate meeting
/itx/meetings/{meeting_id}DELETEDelete meeting
/itx/meetings/{meeting_id}/join_linkGETGet join link for user
/itx/meetings/{meeting_id}/responsesPOSTSubmit RSVP (accepted/declined/maybe)
/itx/meetings/{meeting_id}/occurrences/{occurrence_id}PUTUpdate occurrence
/itx/meetings/{meeting_id}/occurrences/{occurrence_id}DELETEDelete occurrence
/itx/meeting_countGETGet meeting count
/itx/meetings/{meeting_id}/register_committee_membersPOSTRegister all committee members
/itx/meetings/{meeting_id}/resendPOSTResend invites to all registrants

ITX Registrant Operations

EndpointMethodDescription
/itx/meetings/{meeting_id}/registrantsPOSTAdd registrant
/itx/meetings/{meeting_id}/registrants/selfPOSTSelf-register (caller registers themselves)
/itx/meetings/{meeting_id}/registrants/{registrant_id}GETGet registrant
/itx/meetings/{meeting_id}/registrants/{registrant_id}PUTUpdate registrant
/itx/meetings/{meeting_id}/registrants/{registrant_id}DELETEDelete registrant
/itx/meetings/{meeting_id}/registrants/{registrant_id}/icsGETDownload ICS calendar file
/itx/meetings/{meeting_id}/registrants/{registrant_id}/resendPOSTResend invite to one registrant

ITX Past Meeting Operations

EndpointMethodDescription
/itx/past_meetingsPOSTCreate past meeting
/itx/past_meetings/{past_meeting_id}GETGet past meeting
/itx/past_meetings/{past_meeting_id}PUTUpdate past meeting
/itx/past_meetings/{past_meeting_id}DELETEDelete past meeting

ITX Past Meeting Summary Operations

EndpointMethodDescription
/itx/past_meetings/{past_meeting_id}/summaries/{summary_uid}GETGet AI-generated summary
/itx/past_meetings/{past_meeting_id}/summaries/{summary_uid}PUTUpdate summary

ITX Past Meeting Participant Operations

EndpointMethodDescription
/itx/past_meetings/{past_meeting_id}/participantsPOSTAdd participant
/itx/past_meetings/{past_meeting_id}/participants/{participant_id}PUTUpdate participant
/itx/past_meetings/{past_meeting_id}/participants/{participant_id}DELETEDelete participant

ITX Meeting Attachment Operations

EndpointMethodDescription
/itx/meetings/{meeting_id}/attachmentsPOSTCreate attachment
/itx/meetings/{meeting_id}/attachments/{attachment_id}GETGet attachment metadata
/itx/meetings/{meeting_id}/attachments/{attachment_id}PUTUpdate attachment
/itx/meetings/{meeting_id}/attachments/{attachment_id}DELETEDelete attachment
/itx/meetings/{meeting_id}/attachments/presignPOSTGenerate presigned upload URL
/itx/meetings/{meeting_id}/attachments/{attachment_id}/downloadGETGet download URL

ITX Past Meeting Attachment Operations

EndpointMethodDescription
/itx/past_meetings/{meeting_and_occurrence_id}/attachmentsPOSTCreate past meeting attachment
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id}GETGet attachment metadata
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id}PUTUpdate attachment
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id}DELETEDelete attachment
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/presignPOSTGenerate presigned upload URL
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id}/downloadGETGet download URL

๐Ÿ”ง Configuration

Copy .env.example to .env for local development. All variables can also be exported directly.

Service Configuration

VariableDescriptionDefault
PORTHTTP listen port8080
LFX_ENVIRONMENTDeployment environment (dev, staging, prod)prod
PROJECT_LOGO_BASE_URLBase URL for project logo imageshttps://lfx-one-project-logos-png-<env>.s3.us-west-2.amazonaws.com
LFX_APP_ORIGINLFX app origin URL โ€” parsed but currently not consumed by any handler""

ITX Configuration (Required)

VariableDescriptionDefault
ITX_BASE_URLBase URL for ITX servicehttps://api.dev.itx.linuxfoundation.org
ITX_CLIENT_IDOAuth2 client ID for ITXrequired
ITX_CLIENT_PRIVATE_KEYRSA private key in PEM format for ITX OAuth2 M2Mrequired
ITX_AUTH0_DOMAINAuth0 domain for ITX OAuth2linuxfoundation-dev.auth0.com
ITX_AUDIENCEOAuth2 audience for ITXhttps://api.dev.itx.linuxfoundation.org/

Load the private key from file: export ITX_CLIENT_PRIVATE_KEY="$(cat path/to/private.key)"

Authentication Configuration

VariableDescriptionDefault
JWKS_URLJWKS URL for JWT verificationhttp://lfx-platform-heimdall.lfx.svc.cluster.local:4457/.well-known/jwks
JWT_AUDIENCEJWT token audiencelfx-v2-meeting-service
JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPALMock principal for local dev (bypasses Heimdall)""

ID Mapping Configuration (Optional)

VariableDescriptionDefault
ID_MAPPING_DISABLEDSet to true to disable v1/v2 ID mappingfalse
NATS_URLNATS server URL. Required when ID mapping is enabled. Also enables the preferred-email responder, user-metadata resolution, and (when INVITES_ENABLED=true) the invite feature.""

User Service Configuration (Optional)

VariableDescriptionDefault
USER_SERVICE_BASE_URLv1 API gateway base URL for preferred-email RPCPer LFX_ENVIRONMENT

LFID Invite Configuration (Optional)

VariableDescriptionDefault
INVITES_ENABLEDEnable outbound LFID invite sending and invite_accepted subscriberfalse
LFX_SELF_SERVE_BASE_URLLFX self-serve app URL embedded in invite emails as return_url (defaults per LFX_ENVIRONMENT when unset; sending disabled when resolved URL fails validation)Per LFX_ENVIRONMENT

Event Processing Configuration (Optional)

VariableDescriptionDefault
EVENT_PROCESSING_ENABLEDEnable KV-based event processingtrue
EVENT_CONSUMER_NAMEJetStream consumer namemeeting-service-kv-consumer
EVENT_STREAM_NAMEKV bucket stream nameKV_v1-objects
EVENT_V1_MAPPINGS_BUCKETKV bucket name for v1 ID mappingsv1-mappings
EVENT_MAX_DELIVERMax delivery attempts per message3
EVENT_ACK_WAITAck timeout30s
EVENT_MAX_ACK_PENDINGMax pending acks1000

The KV filter subjects are 12 key-prefix patterns within the single v1-objects KV bucket/stream; there is no EVENT_FILTER_SUBJECT env var.

Logging Configuration

VariableDescriptionDefault
LOG_LEVELLog level (debug, info, warn, error)debug
LOG_ADD_SOURCEAdd source location to log linesfalse

Tracing Configuration

VariableDescriptionDefault
OTEL_SERVICE_NAMEService name for traceslfx-v2-meeting-service
OTEL_EXPORTER_OTLP_ENDPOINTOTLP collector endpoint""
OTEL_EXPORTER_OTLP_PROTOCOLOTLP protocol (grpc or http)grpc
OTEL_TRACES_EXPORTERTraces exporter (otlp or none)none

See Tracing Documentation for full configuration details.

๐Ÿค Contributing

This repository follows the Linux Foundation contribution conventions.

Commit Requirements

All commits must be:

  • GPG-signed: git commit -S -s (the -s adds DCO Signed-off-by trailer)
  • Conventional commit format: <type>(<scope>): <summary> โ€” e.g. feat(registrants): add self-registration endpoint

Types: feat | fix | docs | test | refactor | chore | build | ci | perf | style | revert

Code Standards

Before opening a PR, ensure all of these pass:

make check   # gofmt + golangci-lint + license-header check
make test    # unit tests with -race -cover

Every non-generated Go source file (outside gen/ and vendor/) must carry these two header lines before the package declaration:

// Copyright The Linux Foundation and each contributor to LFX.
// SPDX-License-Identifier: MIT

make check will fail if any checked file is missing them (generated files in gen/ are excluded).

Pull Request Workflow

  • Work on a feature branch created from main.
  • Review lifecycle: /lfx-skills:lfx-local-review, configured by the ## Review lifecycle configuration section of CLAUDE.md.
  • PR title must follow <type>(<scope>): <summary> format; append [LFXV2-XXXX] only when a relevant Jira ticket exists.

API Changes

When changing the API:

  1. Edit files in design/ (never edit gen/ directly)
  2. Run make apigen to regenerate
  3. Run make verify to confirm generated code is current
  4. Commit both the design changes and the regenerated files

๐Ÿ“„ License

This project is licensed under the MIT License โ€” see the LICENSE file for details.