Files
go-caatsm/CLAUDE.md
T
windyboyandClaude Sonnet 4.5 c0a66cf845 Enhance aviation parser with security fixes and comprehensive refactoring
This commit implements a complete refactoring of the ICAO aviation parser,
addressing 15 identified issues across security, performance, code quality,
and documentation.

Security Enhancements (P0 - Critical):
- Add input size validation (max 1800 chars per AFTN standard)
- Implement ReDoS protection with 100ms regex timeout mechanism
- Add field validation to prevent nil pointer dereferences
- Document intentional error handling pattern for audit compliance

Performance & Design Improvements (P1 - Important):
- Remove unnecessary mutex from BodyParser (eliminates serialization)
- Fix tokenizer slash handling logic
- Remove global logger dependencies (zap.S() calls)

Code Quality Improvements (P2):
- Refactor parseRemainingLines with clear helper functions
- Document all regex patterns with ICAO format specifications
- Replace magic numbers with named constants (5 new constants)
- Add error message sanitization to prevent data leakage

Documentation & Polish (P3):
- Create comprehensive package documentation (doc.go)
- Verify naming consistency across all functions
- Add 54 comprehensive tests (all passing)
- Verify performance with benchmarks (~10µs for simple messages)

New Files:
- validation.go: Input validation utilities with AFTN limits
- validation_test.go: Comprehensive validation tests
- regex_timeout.go: ReDoS protection mechanism
- regex_timeout_test.go: Timeout protection tests
- suite_test.go: Ginkgo test suite registration
- doc.go: Package-level documentation

All changes maintain backward compatibility and existing architecture
while significantly enhancing security, maintainability, and code quality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-26 17:55:25 +08:00

297 lines
13 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**go-caatsm** is a Civil Aviation Authority Telegram Message Processor - a high-performance, production-ready message processing system for aviation telegrams. It uses Clean Architecture, NATS JetStream for reliable message streaming, and PostgreSQL/TimescaleDB for persistence.
The system processes ICAO-format aviation telegrams (ARR, DEP, CNL, DLA, FPL), parsing raw messages from NATS JetStream, storing them in PostgreSQL, and republishing structured JSON to downstream consumers.
## Essential Commands
### Build & Run
```bash
# Build binary (outputs to bin/receiver)
make build # or: task build
VERSION=v1.0.0 make build # with custom version
# Development (JetStream mode, auto-creates stream/consumer)
make run-dev # or: task run-dev
make run-local # or: task run-local (go run, honors GO_ENV)
# Production (requires config.prod.toml, manual stream/consumer setup)
make run-prod # or: task run-prod
```
### Testing
```bash
# Unit tests (Ginkgo, verbose)
make test # or: task test
ginkgo -r -v ./cmd ./internal
# Run single test by description
ginkgo -r -v --focus "Test Description" ./path/to/package
# Integration tests (requires Docker)
make test-int # or: task test-int
# All tests
make test-all # or: task test-all
# Coverage report (target >80%)
make coverage # or: task coverage
# Opens coverage/coverage.html
```
### Code Quality
```bash
# Lint (golangci-lint)
make lint # or: task lint
# Format code
make fmt # or: task fmt
go fmt ./...
# Regenerate dependency injection (after modifying pkg/di/wire.go)
make wire # or: task wire
wire ./pkg/di
```
### Development Tools
```bash
# Install Ginkgo tooling
task install-test
go install github.com/onsi/ginkgo/v2/ginkgo@latest
# Generate sample telegrams (burst mode)
make seed COUNT=100 CATEGORY=mixed STATUS=random # or: task seed
# Continuous slow seeding (useful for monitoring)
make seed-slow INTERVAL_MIN=2s INTERVAL_MAX=5s # or: task seed-slow
# Press Ctrl-C to stop
# Start dev infrastructure (Docker Compose)
task up # Postgres, NATS, observability stack
task dev-run # Start infra + run receiver locally
task down # Stop and remove containers
```
## Architecture Overview
### Clean Architecture Layers
```
internal/
├── domain/ # Pure business entities (no dependencies)
│ └── aviation.go # ARR, DEP, CNL, DLA, FPL, Weather domain models
├── port/ # Interface contracts (Repository, Publisher)
│ ├── repository.go
│ └── publisher.go
├── app/ # Application logic (orchestration)
│ └── processor.go # MessageProcessor - main processing pipeline
├── adapter/ # Interface implementations & data transformations
│ ├── parser/ # Telegram parsers (composite pattern)
│ │ ├── aviation/ # Aviation telegrams (ARR, DEP, CNL, DLA, FPL)
│ │ ├── weather/ # Weather reports (METAR, SPECI, TAF)
│ │ └── schedule/ # Flight schedule messages
│ ├── mapper/ # Domain ↔ DTO transformations
│ └── dto/ # Data Transfer Objects (ParsedTelegram, MessageStatus)
└── infra/ # Infrastructure concerns
├── nats/ # NATS JetStream consumer & publisher
├── postgres/ # PostgreSQL repository (pgx, batch inserts)
├── config/ # Koanf configuration loading
├── log/ # Zap structured logging
├── telemetry/ # OpenTelemetry traces/metrics
├── metrics/ # Prometheus metrics
├── monitoring/ # Health/metrics HTTP server
└── buildinfo/ # Build metadata
```
**Dependency Flow**: `infra``adapter``app``domain``port`
The domain layer has zero external dependencies. All layers depend on interfaces (ports), not concrete implementations.
### Key Components
1. **NATS Consumer** (`internal/infra/nats/consumer.go`)
- Pulls messages from JetStream in batches (default: 50)
- ACK/NAK handling with automatic retries
- Routes to DLQ after max delivery attempts (default: 3)
- Monitors consumer lag and pending messages
2. **MessageProcessor** (`internal/app/processor.go`)
- Orchestrates: Parse → Persist → Publish
- Error categorization: `parsed`, `header_error`, `body_error`, `publish_error`, `repository_error`
- Parser failures are permanent (ACK'd, no retry)
- Repository failures are transient (NAK'd, retry with backoff)
3. **Parser** (`internal/adapter/parser/`)
- Composite parser architecture with specialized sub-parsers
- **Aviation Parser** (`internal/adapter/parser/aviation/`) - ICAO telegram formats (ARR, DEP, CNL, DLA, FPL)
- **Weather Parser** (`internal/adapter/parser/weather/`) - Weather reports (METAR, SPECI, TAF)
- **Schedule Parser** (`internal/adapter/parser/schedule/`) - Flight schedule messages
- Uses pattern matching, tokenization, and lexical analysis
- Returns structured domain models or error status
4. **Repository** (`internal/infra/postgres/repository.go`)
- PostgreSQL persistence via pgx connection pool
- Batch insert support via `COPY FROM`
- Stores parsed telegrams in `aviation.telegrams` table
5. **Monitoring Server** (`internal/infra/monitoring/server.go`)
- `GET /livez` - Liveness (process info, no dependencies checked)
- `GET /readyz` - Readiness (pings Postgres & NATS, 503 on failure)
- `GET /metrics` - Prometheus metrics endpoint
- Default address: `:2112`
### Configuration
Uses Koanf for config loading from TOML files + environment variables:
- Config file: `configs/config.{GO_ENV}.toml` (GO_ENV defaults to `dev`)
- Env overrides: `CAATSM_` prefix (e.g., `CAATSM_NATS_URL`, `CAATSM_POSTGRES_URL`)
- Key settings:
- `nats.mode`: Must be `"jetstream"` (only supported mode)
- `nats.stream`: JetStream stream name (default: `TELEGRAM`)
- `nats.consumer`: Durable consumer name (default: `telegram-consumer`)
- `nats.consumer_rules.max_deliver`: Max retry attempts (default: 3)
- `dlq.enabled`: Enable Dead-Letter Queue for poison messages
- `app.batch_size`: JetStream pull batch size (default: 50)
- `monitoring.addr`: Metrics/health server address (default: `:2112`)
### Parser Architecture
The system uses a **composite parser pattern** with specialized sub-parsers:
1. **Composite Parser** (`internal/adapter/parser/composite.go`)
- Orchestrates multiple specialized parsers
- Routes messages to appropriate parser based on content classification
- Falls back gracefully if primary parser fails
2. **Aviation Parser** (`internal/adapter/parser/aviation/`)
- Pattern-based parsing using registry of message type patterns
- Tokenizer for breaking down telegram structure
- Handles ARR, DEP, CNL, DLA, FPL message types
- Extracts flight details, aircraft info, timestamps, airports
3. **Weather Parser** (`internal/adapter/parser/weather/`)
- Lexer-based parsing for weather reports
- Classifier to identify METAR, SPECI, or TAF format
- Pattern matching for weather elements (wind, visibility, clouds, etc.)
- Normalizes weather data into structured format
4. **Schedule Parser** (`internal/adapter/parser/schedule/`)
- Extracts flight schedule information
- Pattern matching for schedule-specific fields
- Handles recurring flight patterns and time ranges
Each parser implements the `Parser` interface from `internal/port/parser.go`, enabling easy extension and testing.
### Dependency Injection
Uses Google Wire for compile-time DI:
- Wire spec: `pkg/di/wire.go`
- Generated code: `pkg/di/wire_gen.go` (NEVER edit manually)
- To add a new dependency:
1. Create a `ProvideXxx` function in the appropriate package
2. Add it to the `runtimeSet` in `pkg/di/wire.go`
3. Run `make wire` or `task wire`
### Message Processing Flow
```
NATS JetStream → Consumer.Fetch(batch) → MessageProcessor.Handle(msg) →
├─ Parser.Parse(raw) → domain model or error status
├─ Repository.Insert(parsed) → Postgres aviation.telegrams
├─ Publisher.Publish(json) → NATS output topic
└─ ACK (success) | NAK (transient failure) | ACK (permanent failure)
```
**Error Handling**:
- **Parser failures** (invalid format): Store raw + status in DB, ACK message (permanent)
- **Repository failures** (DB down): NAK message, JetStream redelivers (transient)
- **Publisher failures** (downstream topic): Store raw + error status, ACK message (permanent, can replay from DB)
- After `max_deliver` attempts: Route to DLQ if enabled, else discard
### Observability
Three observability surfaces:
1. **Prometheus Metrics** (`/metrics`)
- `caatsm_messages_total{stream,consumer,result}` - Throughput & results
- `caatsm_handle_latency_seconds_bucket{stream,consumer}` - Processing latency
- `caatsm_retries_total{stream,consumer,reason}` - JetStream retries
- `caatsm_db_queries_total{operation,result}` - DB activity
- `caatsm_nats_consumer_pending_messages{stream,consumer}` - Consumer lag
- `caatsm_dlq_messages_total{stream,consumer}` - DLQ routing
2. **OpenTelemetry** (traces + metrics)
- Environment-based sampling: Production (1%), Staging (10%), Dev/Test (100%)
- Semantic attributes: `messaging.system`, `db.system`, `caatsm.message.category`
- Configure via `[telemetry]` block (endpoint, enabled, insecure)
- Export to OTLP/HTTP collector (default: `localhost:4318`)
3. **Health Endpoints**
- `GET /livez` - Process liveness (no dependency checks)
- `GET /readyz` - Readiness (checks Postgres & NATS, timeout: 2s)
- Both return JSON with build metadata + dependency status
### Testing Philosophy
- **Unit tests**: Ginkgo BDD style, table-driven, mock interfaces
- Location: Alongside code (`*_test.go`)
- Run with `make test` or `ginkgo -r -v ./cmd ./internal`
- Target: >80% coverage
- **Integration tests**: Docker-based (testcontainers), full E2E flow
- Location: `test/integration/`
- Run with `make test-int` (requires Docker)
- Spins up real Postgres + NATS JetStream
- **Benchmarks**: Performance-critical paths (parser, mapper, processor)
- Run with `go test -bench=BenchmarkXxx -benchmem ./path/to/pkg`
## Important Development Notes
### Code Style (from .cursor/rules/do.mdc)
- **Clean Architecture**: Strict layer separation, dependency inversion
- **Interface-driven**: All public functions interact with interfaces, not concrete types
- **Error handling**: Always wrap errors with context (`fmt.Errorf("context: %w", err)`)
- **Context propagation**: Pass `context.Context` everywhere (deadlines, cancellations, tracing)
- **No global state**: Use constructor functions with DI
- **Resource cleanup**: Use `defer` for closing resources
- **Security**: Input validation, secure defaults, retries with exponential backoff
- **Observability**: Trace all service boundaries (HTTP, NATS, DB), structured logs (JSON)
### Never Edit Generated Files
- `pkg/di/wire_gen.go` - Wire-generated DI code
- Any `*_gen.go` files - Code generation output
### Common Gotchas
1. **JetStream-only mode**: The system only supports JetStream mode (`nats.mode = "jetstream"`). Do not attempt to use Core NATS mode.
2. **Production setup**: In production (`GO_ENV=prod`):
- Stream and Consumer must be created manually (not auto-created)
- Requires `configs/config.prod.toml` or `CAATSM_*` env vars
- Enable TLS for NATS/Postgres connections
3. **Parsing failures are permanent**: Parser errors (invalid format) are ACK'd and stored with error status. They do NOT trigger JetStream retries.
4. **Repository failures are transient**: DB connection failures trigger NAK, causing JetStream to redeliver the message.
5. **Batch processing**: Default batch size is 50 messages. Tune `app.batch_size` for your workload. Larger batches improve throughput but increase latency.
6. **Consumer lag**: Monitor `caatsm_nats_consumer_pending_messages` metric. High values indicate slow processing or insufficient consumer instances.
7. **DLQ routing**: Enable DLQ (`dlq.enabled = true`) to capture poison messages after max delivery attempts. Inspect DLQ subject (`caatsm.dlq`) for failed messages.
## Additional Documentation
- `README.md` - Comprehensive user guide (setup, configuration, deployment)
- `AGENTS.md` - Quick reference for AI assistants (commands, style guide)
- `docs/prod-guide.md` - Production deployment guide
- `docs/nats.md` - NATS/JetStream configuration details
- `docs/observability.md` - Observability setup & metrics
- `docs/migrations.md` - Database migration strategy
- `docs/performance.md` - Performance tuning guidelines