Skip to content

Latest commit

Β 

History

1,164 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ITX Meeting Proxy Service

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

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.json
  • http://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-objects KV bucket/stream; there is no EVENT_FILTER_SUBJECT env 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 -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

  1. Create a feature branch from main
  2. Make changes, run make check and make test
  3. Run the local review cycle: /lfx-skills:lfx-local-review (see CLAUDE.md for details)
  4. Open a 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.

About

LFX v2 Platform Meeting Service

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages