Skip to content

Latest commit

 

History

History
236 lines (162 loc) · 8.06 KB

File metadata and controls

236 lines (162 loc) · 8.06 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Essential Commands

Build and Development

# Install dependencies and development tools
make setup
make deps

# Generate API code from Goa design (required after design changes)
make apigen
# Or directly: goa gen github.com/linuxfoundation/lfx-v2-query-service/design

# Build the application
make build

# Run locally with mock implementations (development)
SEARCH_SOURCE=mock ACCESS_CONTROL_SOURCE=mock go run ./cmd

# Run with OpenSearch and NATS (production-like)
SEARCH_SOURCE=opensearch ACCESS_CONTROL_SOURCE=nats \
OPENSEARCH_URL=http://localhost:9200 \
OPENSEARCH_INDEX=resources \
NATS_URL=nats://localhost:4222 \
go run ./cmd

Testing and Validation

# Run tests
make test
# Or: go test -v -race -coverprofile=coverage.out ./...

# Run linting
make lint
# Or: golangci-lint run ./...

# Run specific test
go test -v -run TestResourceSearch ./internal/service/

Docker Operations

# Build Docker image
make docker-build

# Run Docker container
make docker-run

Architecture Overview

This service follows clean architecture principles with clear separation of concerns:

Layer Structure

  1. Domain Layer (internal/domain/)

    • model/: Core business entities (Resource, SearchCriteria, AccessCheck)
    • port/: Interfaces defining contracts (ResourceSearcher, AccessControlChecker)
  2. Service Layer (internal/service/)

    • Business logic orchestration
    • Coordinates between domain and infrastructure
  3. Infrastructure Layer (internal/infrastructure/)

    • opensearch/: OpenSearch implementation for resource search
    • nats/: NATS implementation for access control
    • mock/: Mock implementations for testing
  4. Presentation Layer (gen/, cmd/)

    • Generated Goa code for HTTP endpoints
    • Service implementation connecting Goa to domain logic

Key Design Patterns

  • Dependency Injection: Concrete implementations injected in cmd/main.go
  • Port/Adapter Pattern: Domain interfaces (ports) with swappable implementations
  • Repository Pattern: Search and access control abstracted behind interfaces

API Design (Goa Framework)

  • Design specifications in design/ directory
  • Generated code in gen/ (DO NOT manually edit)
  • After design changes, always run make apigen

Request Flow

  1. HTTP request → Goa generated server (gen/http/query_svc/server/)
  2. Service layer (cmd/query_svc/query_svc.go)
  3. Use case orchestration (internal/service/resource_search.go)
  4. Domain interfaces called with concrete implementations
  5. Response formatted and returned through Goa

Configuration

Environment variables control implementation selection:

  • SEARCH_SOURCE: "mock" or "opensearch"
  • ACCESS_CONTROL_SOURCE: "mock" or "nats"
  • Additional configs for OpenSearch and NATS connections

Testing Strategy

  • Unit tests use mock implementations
  • Integration tests can switch between real and mock implementations
  • Test files follow *_test.go pattern alongside implementation files

API Features

Page Size

The query-resources endpoint supports a page_size query parameter to control how many documents are returned per page.

Query Parameter:

  • page_size (int, optional): Number of results per page (min: 1, max: 1000, default: 50)

Examples:

# Custom page size
GET /query/resources?v=1&type=project&page_size=20

# Combined with other filters
GET /query/resources?v=1&type=project&tags=active&date_field=updated_at&date_from=2025-01-01&page_size=100

Interaction with post-query filters: cel_filter and access control checks are applied after OpenSearch returns results, so a page may return fewer than page_size results.

Implementation Details:

  • Goa design: design/types.go (Sortable type), design/query-svc.go (HTTP param)
  • Converter: cmd/service/converters.go (payloadToCriteria() passes p.PageSize to criteria)
  • Domain model: internal/domain/model/search_criteria.go (PageSize field)
  • OpenSearch pagination: internal/infrastructure/opensearch/client.go (page token generated when len(hits) == pageSize)
  • Constants: pkg/constants/query.go (DefaultPageSize, MaxPageSize)

Date Range Filtering

The query service supports filtering resources by date ranges on fields within the data object.

Query Parameters:

  • date_field (string, optional): Date field to filter on (automatically prefixed with "data.")
  • date_from (string, optional): Start date (inclusive, gte operator)
  • date_to (string, optional): End date (inclusive, lte operator)

Supported Date Formats:

  1. ISO 8601 datetime: 2025-01-10T15:30:00Z (time used as provided)
  2. Date-only: 2025-01-10 (converted to start/end of day UTC)
    • date_from2025-01-10T00:00:00Z (start of day)
    • date_to2025-01-10T23:59:59Z (end of day)

Examples:

# Date range with date-only format
GET /query/resources?v=1&date_field=updated_at&date_from=2025-01-10&date_to=2025-01-28

# Date range with ISO 8601 format
GET /query/resources?v=1&date_field=created_at&date_from=2025-01-10T15:30:00Z&date_to=2025-01-28T18:45:00Z

# Open-ended range (only start date)
GET /query/resources?v=1&date_field=created_at&date_from=2025-01-01

# Combined with other filters
GET /query/resources?v=1&type=project&tags=active&date_field=updated_at&date_from=2025-01-01&date_to=2025-03-31

Implementation Details:

  • Date parsing logic: cmd/service/converters.go (parseDateFilter() function)
  • Domain model: internal/domain/model/search_criteria.go (DateField, DateFrom, DateTo)
  • OpenSearch query: internal/infrastructure/opensearch/template.go (range query with gte/lte)
  • API design: design/query-svc.go (Goa design specification)
  • Test coverage: cmd/service/converters_test.go (17 comprehensive test cases)

CEL Filter

The service supports Common Expression Language (CEL) filtering for post-query resource filtering.

CEL filtering allows API consumers to filter resources on arbitrary data fields using a safe, non-Turing complete expression language. The filter is applied after the OpenSearch query but before access control checks.

Location: internal/infrastructure/filter/cel_filter.go

Key Components:

  • ResourceFilter Interface (internal/domain/port/filter.go): Domain interface for filtering
  • CELFilter Implementation: Uses google/cel-go library for expression evaluation
  • Expression Caching: LRU cache with TTL for compiled CEL programs
  • Security Features: Max expression length (1000 chars), evaluation timeout (100ms per resource)

Integration Point: internal/service/resource_search.go (lines 84-102)

  • CEL filter applied after OpenSearch query
  • Filters resources before access control checks
  • Reduces number of access control checks needed

Available Variables in CEL Expressions:

  • data (map): Resource data object
  • resource_type (string): Resource type
  • id (string): Resource ID

Note: type is a reserved word in CEL, so we use resource_type instead.

Example Usage:

GET /query/resources?type=project&cel_filter=data.slug == "tlf"

Common CEL Operations:

  • Equality: data.status == "active"
  • Comparison: data.priority > 5
  • Boolean logic: data.status == "active" && data.priority > 5
  • String operations: data.name.contains("LF")
  • List membership: data.category in ["security", "networking"]
  • Field existence: has(data.archived)

Performance Considerations:

  • Compiled CEL programs are cached (100 max entries, 5-minute TTL)
  • Each resource evaluation has 100ms timeout
  • Post-query filtering means pagination may return fewer results than page size
  • For best performance, use specific OpenSearch criteria first, then CEL for refinement

Important Limitations:

CEL filters apply only to results from each OpenSearch page. If the target resource is not in the first page of OpenSearch results, it won't be found even if it matches the CEL filter. Always use specific primary search criteria (type, name, parent) to narrow OpenSearch results first.