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
-
Prerequisites
- Go 1.25+ installed
- Make installed
-
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 -
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_KEYMinimum 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 -
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_acceptedsubscriber 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_byuser 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_acceptedNATS 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
-
Install Dependencies
make depsThis also installs the pre-commit hook that runs gofmt and a license-header check before each commit.
-
Generate API Code
make apigenGenerates HTTP transport, client, and OpenAPI documentation from
design/files. Run this whenever you changedesign/. -
Build the Application
make buildCreates 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:
-
Update Design Files in
design/directory -
Regenerate Code:
make apigen -
Verify Generation:
make verify -
Run Tests to ensure nothing breaks:
make test
Available Make Targets
| Target | Description |
|---|---|
make all | Complete build pipeline (clean, deps, apigen, fmt, lint, test, build) |
make deps | Install dependencies, tools, and git hooks |
make install-hooks | Install git hooks from scripts/hooks/ into .git/hooks/ |
make apigen | Generate API code from design files |
make build | Build the binary to bin/meeting-api |
make run | Run the service locally |
make debug | Run with debug logging |
make test | Run unit tests with race detection |
make test-verbose | Run tests with verbose output |
make test-coverage | Generate HTML coverage report in coverage/ |
make lint | Run golangci-lint |
make fmt | Format Go code with gofmt |
make license-check | Verify all non-generated Go, HTML, and TXT files carry LFX copyright and MIT SPDX headers (excludes gen/ and vendor/) |
make check | Verify formatting, linting, and license headers without modifying files |
make verify | Ensure generated code is up to date |
make clean | Remove build artifacts |
make docker-build | Build Docker image |
make helm-install | Install Helm chart from GHCR |
make helm-install-local | Install Helm chart using local Docker image |
make helm-templates | Print rendered Helm templates |
make helm-uninstall | Uninstall Helm chart |
make help | List 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.jsonhttp://localhost:8080/_meetings/openapi3.yaml
Available Endpoints
Health Checks
| Endpoint | Method | Description |
|---|---|---|
/livez | GET | Liveness check |
/readyz | GET | Readiness check |
OpenAPI Documentation
| Endpoint | Method | Description |
|---|---|---|
/_meetings/openapi.json | GET | OpenAPI 2 spec (JSON) |
/_meetings/openapi.yaml | GET | OpenAPI 2 spec (YAML) |
/_meetings/openapi3.json | GET | OpenAPI 3 spec (JSON) |
/_meetings/openapi3.yaml | GET | OpenAPI 3 spec (YAML) |
ITX Meeting Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/meetings | POST | Create meeting |
/itx/meetings/{meeting_id} | GET | Get meeting details |
/itx/meetings/{meeting_id} | PUT | Update meeting |
/itx/meetings/{meeting_id} | DELETE | Delete meeting |
/itx/meetings/{meeting_id}/join_link | GET | Get join link for user |
/itx/meetings/{meeting_id}/responses | POST | Submit RSVP (accepted/declined/maybe) |
/itx/meetings/{meeting_id}/occurrences/{occurrence_id} | PUT | Update occurrence |
/itx/meetings/{meeting_id}/occurrences/{occurrence_id} | DELETE | Delete occurrence |
/itx/meeting_count | GET | Get meeting count |
/itx/meetings/{meeting_id}/register_committee_members | POST | Register all committee members |
/itx/meetings/{meeting_id}/resend | POST | Resend invites to all registrants |
ITX Registrant Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/meetings/{meeting_id}/registrants | POST | Add registrant |
/itx/meetings/{meeting_id}/registrants/self | POST | Self-register (caller registers themselves) |
/itx/meetings/{meeting_id}/registrants/{registrant_id} | GET | Get registrant |
/itx/meetings/{meeting_id}/registrants/{registrant_id} | PUT | Update registrant |
/itx/meetings/{meeting_id}/registrants/{registrant_id} | DELETE | Delete registrant |
/itx/meetings/{meeting_id}/registrants/{registrant_id}/ics | GET | Download ICS calendar file |
/itx/meetings/{meeting_id}/registrants/{registrant_id}/resend | POST | Resend invite to one registrant |
ITX Past Meeting Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/past_meetings | POST | Create past meeting |
/itx/past_meetings/{past_meeting_id} | GET | Get past meeting |
/itx/past_meetings/{past_meeting_id} | PUT | Update past meeting |
/itx/past_meetings/{past_meeting_id} | DELETE | Delete past meeting |
ITX Past Meeting Summary Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/past_meetings/{past_meeting_id}/summaries/{summary_uid} | GET | Get AI-generated summary |
/itx/past_meetings/{past_meeting_id}/summaries/{summary_uid} | PUT | Update summary |
ITX Past Meeting Participant Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/past_meetings/{past_meeting_id}/participants | POST | Add participant |
/itx/past_meetings/{past_meeting_id}/participants/{participant_id} | PUT | Update participant |
/itx/past_meetings/{past_meeting_id}/participants/{participant_id} | DELETE | Delete participant |
ITX Meeting Attachment Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/meetings/{meeting_id}/attachments | POST | Create attachment |
/itx/meetings/{meeting_id}/attachments/{attachment_id} | GET | Get attachment metadata |
/itx/meetings/{meeting_id}/attachments/{attachment_id} | PUT | Update attachment |
/itx/meetings/{meeting_id}/attachments/{attachment_id} | DELETE | Delete attachment |
/itx/meetings/{meeting_id}/attachments/presign | POST | Generate presigned upload URL |
/itx/meetings/{meeting_id}/attachments/{attachment_id}/download | GET | Get download URL |
ITX Past Meeting Attachment Operations
| Endpoint | Method | Description |
|---|---|---|
/itx/past_meetings/{meeting_and_occurrence_id}/attachments | POST | Create past meeting attachment |
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id} | GET | Get attachment metadata |
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id} | PUT | Update attachment |
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id} | DELETE | Delete attachment |
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/presign | POST | Generate presigned upload URL |
/itx/past_meetings/{meeting_and_occurrence_id}/attachments/{attachment_id}/download | GET | Get download URL |
๐ง Configuration
Copy .env.example to .env for local development. All variables can also be exported directly.
Service Configuration
| Variable | Description | Default |
|---|---|---|
PORT | HTTP listen port | 8080 |
LFX_ENVIRONMENT | Deployment environment (dev, staging, prod) | prod |
PROJECT_LOGO_BASE_URL | Base URL for project logo images | https://lfx-one-project-logos-png-<env>.s3.us-west-2.amazonaws.com |
LFX_APP_ORIGIN | LFX app origin URL โ parsed but currently not consumed by any handler | "" |
ITX Configuration (Required)
| Variable | Description | Default |
|---|---|---|
ITX_BASE_URL | Base URL for ITX service | https://api.dev.itx.linuxfoundation.org |
ITX_CLIENT_ID | OAuth2 client ID for ITX | required |
ITX_CLIENT_PRIVATE_KEY | RSA private key in PEM format for ITX OAuth2 M2M | required |
ITX_AUTH0_DOMAIN | Auth0 domain for ITX OAuth2 | linuxfoundation-dev.auth0.com |
ITX_AUDIENCE | OAuth2 audience for ITX | https://api.dev.itx.linuxfoundation.org/ |
Load the private key from file: export ITX_CLIENT_PRIVATE_KEY="$(cat path/to/private.key)"
Authentication Configuration
| Variable | Description | Default |
|---|---|---|
JWKS_URL | JWKS URL for JWT verification | http://lfx-platform-heimdall.lfx.svc.cluster.local:4457/.well-known/jwks |
JWT_AUDIENCE | JWT token audience | lfx-v2-meeting-service |
JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL | Mock principal for local dev (bypasses Heimdall) | "" |
ID Mapping Configuration (Optional)
| Variable | Description | Default |
|---|---|---|
ID_MAPPING_DISABLED | Set to true to disable v1/v2 ID mapping | false |
NATS_URL | NATS 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)
| Variable | Description | Default |
|---|---|---|
USER_SERVICE_BASE_URL | v1 API gateway base URL for preferred-email RPC | Per LFX_ENVIRONMENT |
LFID Invite Configuration (Optional)
| Variable | Description | Default |
|---|---|---|
INVITES_ENABLED | Enable outbound LFID invite sending and invite_accepted subscriber | false |
LFX_SELF_SERVE_BASE_URL | LFX 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)
| Variable | Description | Default |
|---|---|---|
EVENT_PROCESSING_ENABLED | Enable KV-based event processing | true |
EVENT_CONSUMER_NAME | JetStream consumer name | meeting-service-kv-consumer |
EVENT_STREAM_NAME | KV bucket stream name | KV_v1-objects |
EVENT_V1_MAPPINGS_BUCKET | KV bucket name for v1 ID mappings | v1-mappings |
EVENT_MAX_DELIVER | Max delivery attempts per message | 3 |
EVENT_ACK_WAIT | Ack timeout | 30s |
EVENT_MAX_ACK_PENDING | Max pending acks | 1000 |
The KV filter subjects are 12 key-prefix patterns within the single
v1-objectsKV bucket/stream; there is noEVENT_FILTER_SUBJECTenv var.
Logging Configuration
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL | Log level (debug, info, warn, error) | debug |
LOG_ADD_SOURCE | Add source location to log lines | false |
Tracing Configuration
| Variable | Description | Default |
|---|---|---|
OTEL_SERVICE_NAME | Service name for traces | lfx-v2-meeting-service |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP collector endpoint | "" |
OTEL_EXPORTER_OTLP_PROTOCOL | OTLP protocol (grpc or http) | grpc |
OTEL_TRACES_EXPORTER | Traces 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-sadds DCOSigned-off-bytrailer) - 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 configurationsection 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:
- Edit files in
design/(never editgen/directly) - Run
make apigento regenerate - Run
make verifyto confirm generated code is current - Commit both the design changes and the regenerated files
๐ License
This project is licensed under the MIT License โ see the LICENSE file for details.