Files
notifier/docs/CLIENT_INTEGRATION_PROMPT.md

345 lines
12 KiB
Markdown

# Notifier Service Client Integration Prompt
**Use this prompt with Claude or another AI assistant when building a client application that integrates with the Notifier service.**
---
## Prompt for AI Assistant
I need to build a client application that integrates with a notification service using gRPC. Please help me implement a production-ready client that follows best practices for performance, security, and reliability.
### Service Details
**Protocol:** gRPC (HTTP/2)
**Service Address:** `notifier-grpc:50051` (Kubernetes internal DNS)
**Authentication:** API Key via gRPC metadata
**API Key Format:** `nk_` prefix followed by 64 hex characters (e.g., `nk_abc123...`)
### Authentication Requirements
1. **API Key Delivery:**
- Send API key in gRPC metadata with EVERY request
- Two accepted header formats:
- `authorization: Bearer nk_your_api_key_here` (preferred)
- `x-api-key: nk_your_api_key_here`
2. **Per-Request Authentication:**
- The service validates the API key on every RPC call
- Authentication is NOT done at connection time
- This means you can (and should) use long-lived connections
3. **Rate Limiting:**
- Rate limits are enforced per API key
- Default: 100 requests per minute (configurable per key)
- Rate limit exceeded returns: `codes.ResourceExhausted`
- Implement exponential backoff retry for rate limit errors
4. **Credential Management:**
- Load API key from environment variable: `NOTIFIER_API_KEY`
- NEVER hardcode API keys in source code
- NEVER log the full API key (mask it: `nk_abc...xyz`)
- Store in Kubernetes Secret if deploying to k8s
### Connection Management Requirements
**CRITICAL:** Use long-lived gRPC connections for optimal performance.
1. **Connection Lifecycle:**
- Create ONE connection at application startup
- Reuse the connection for ALL requests
- Close the connection only when application exits
- Do NOT create a new connection for each request
2. **Keepalive Configuration:**
- Configure client keepalive to prevent connection timeouts
- Recommended settings:
- Time: 10 seconds (ping every 10s of inactivity)
- Timeout: 3 seconds (wait for ping response)
- PermitWithoutStream: true (allow pings when idle)
3. **Why This Matters:**
- Connection reuse: 10x faster (1.5ms vs 15ms per request)
- Eliminates TCP + TLS handshake overhead (10-15ms per request)
- HTTP/2 multiplexing: handle multiple concurrent requests on one connection
- Lower resource usage: one connection vs thousands
### Error Handling Requirements
1. **Handle These Error Codes:**
- `codes.Unauthenticated` - Invalid or missing API key → Log error, don't retry
- `codes.ResourceExhausted` - Rate limit exceeded → Retry with exponential backoff
- `codes.InvalidArgument` - Bad request payload → Log error, don't retry
- `codes.Unavailable` - Service temporarily unavailable → Retry with backoff
- `codes.DeadlineExceeded` - Request timeout → Retry (may be transient)
2. **Retry Strategy:**
- Implement exponential backoff: 100ms, 200ms, 400ms, 800ms
- Maximum 3-5 retry attempts for retryable errors
- Only retry: rate limits, unavailable, deadline exceeded
- Do NOT retry: authentication errors, invalid arguments
3. **Context Timeouts:**
- Set reasonable timeout for each request (5-30 seconds)
- Use `context.WithTimeout()` for every RPC call
- Allow timeout to be configurable
### Code Structure Requirements
1. **Client Structure:**
```
NotifierClient struct:
- conn: *grpc.ClientConn (long-lived)
- client: pb.NotifierServiceClient
- apiKey: string (loaded from env)
- logger: logging interface
```
2. **Required Methods:**
- `NewNotifierClient(address, apiKey string) (*NotifierClient, error)` - Initialize
- `SendNotification(ctx, request) (response, error)` - Send single notification
- `SendBatchNotifications(ctx, requests) (responses, error)` - Send batch
- `HealthCheck(ctx) error` - Verify connection health
- `Close() error` - Clean up connection
3. **Initialization Pattern:**
- Create client as singleton at application startup
- Use `sync.Once` to ensure only one instance
- Defer `Close()` in main() to ensure cleanup
### Observability Requirements
1. **Logging:**
- Log connection establishment (info level)
- Log authentication failures (warn level)
- Log rate limit exceeded (warn level)
- Log successful sends (debug level)
- NEVER log the full API key (mask it)
2. **Metrics (if using Prometheus):**
- Counter: `notifier_requests_total` (labels: status, method)
- Counter: `notifier_requests_failed_total` (labels: error_code)
- Histogram: `notifier_request_duration_seconds`
- Counter: `notifier_rate_limit_errors_total`
3. **Health Checks:**
- Implement background health check goroutine
- Check every 30-60 seconds
- Call the service's HealthCheck RPC
- Log warnings if health checks fail
### Security Requirements
1. **Credential Security:**
- Load API key ONLY from environment variables
- Never commit API keys to version control
- Use `.gitignore` to exclude any files with credentials
- Implement a `String()` method that masks the API key for logging
2. **TLS Configuration:**
- For local development: `grpc.WithInsecure()` is acceptable
- For production: Use TLS with proper certificate validation
- For Kubernetes: Internal communication may use insecure (cluster network is trusted)
3. **Graceful Degradation:**
- If notifier service is unavailable, application should continue
- Log notification failures but don't crash the application
- Consider implementing a circuit breaker pattern for resilience
### Testing Requirements
1. **Unit Tests:**
- Mock the gRPC client interface
- Test retry logic with rate limit errors
- Test context timeout handling
- Test credential masking in logs
2. **Integration Tests:**
- Test actual connection to notifier service (if available)
- Test authentication with valid and invalid keys
- Test rate limiting behavior
### Kubernetes Deployment Requirements (if applicable)
1. **Environment Variables:**
```yaml
env:
- name: NOTIFIER_API_KEY
valueFrom:
secretKeyRef:
name: notifier-credentials
key: api-key
- name: NOTIFIER_ADDRESS
value: "notifier-grpc:50051"
```
2. **Secrets Configuration:**
```yaml
apiVersion: v1
kind: Secret
metadata:
name: notifier-credentials
type: Opaque
stringData:
api-key: nk_your_actual_api_key_here
```
### Available gRPC Methods
The NotifierService provides these RPC methods:
1. **SendNotification** - Send a single notification
- Request: `SendNotificationRequest`
- Response: `SendNotificationResponse` (contains notification_id)
2. **SendBatchNotifications** - Send multiple notifications at once
- Request: `SendBatchNotificationsRequest`
- Response: `SendBatchNotificationsResponse` (contains notification_ids)
3. **GetNotification** - Retrieve notification status by ID
- Request: `GetNotificationRequest` (notification_id)
- Response: `GetNotificationResponse`
4. **ListNotifications** - List recent notifications
- Request: `ListNotificationsRequest` (pagination)
- Response: `ListNotificationsResponse`
5. **CancelNotification** - Cancel a pending notification
- Request: `CancelNotificationRequest` (notification_id)
- Response: `CancelNotificationResponse`
6. **RetryNotification** - Retry a failed notification
- Request: `RetryNotificationRequest` (notification_id)
- Response: `RetryNotificationResponse`
7. **GetStats** - Get service statistics
- Request: `GetStatsRequest`
- Response: `GetStatsResponse`
8. **GetNotifiers** - List available notifier types and accounts
- Request: `GetNotifiersRequest`
- Response: `GetNotifiersResponse`
9. **HealthCheck** - Verify service health
- Request: `HealthCheckRequest`
- Response: `HealthCheckResponse`
### Notification Types Supported
- `NOTIFICATION_TYPE_EMAIL` - Email notifications
- `NOTIFICATION_TYPE_SLACK` - Slack messages
- `NOTIFICATION_TYPE_NTFY` - Ntfy.sh push notifications
- `NOTIFICATION_TYPE_STDOUT` - Console output (development only)
### Request Example Structure
```protobuf
message SendNotificationRequest {
NotificationType type = 1; // Required: email, slack, ntfy, stdout
string subject = 2; // Required: notification subject/title
string body = 3; // Required: notification body/content
repeated string recipients = 4; // Required: email addresses, slack channels, etc.
Priority priority = 5; // Optional: normal, high, critical
string account = 6; // Optional: specific notifier account to use
map<string, string> metadata = 7; // Optional: additional metadata
}
```
### Implementation Goals
Please implement a client that:
1. ✅ Uses a single long-lived gRPC connection
2. ✅ Sends API key in metadata with every request
3. ✅ Implements exponential backoff retry for rate limits
4. ✅ Loads credentials from environment variables
5. ✅ Uses context with timeout for all requests
6. ✅ Implements keepalive to prevent connection timeouts
7. ✅ Includes proper error handling for all error codes
8. ✅ Logs important events without exposing credentials
9. ✅ Provides a health check mechanism
10. ✅ Includes graceful shutdown (connection cleanup)
11. ✅ Is production-ready with proper error handling and logging
12. ✅ Includes basic unit tests
### Example Usage Pattern
The client should be usable like this:
```go
// Initialize once at startup
client, err := notifier.NewClient(
os.Getenv("NOTIFIER_ADDRESS"),
os.Getenv("NOTIFIER_API_KEY"),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Use throughout application lifetime
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := client.SendNotification(ctx, &notifier.SendRequest{
Type: notifier.TypeEmail,
Subject: "Important Alert",
Body: "This is a critical notification",
Recipients: []string{"admin@example.com"},
Priority: notifier.PriorityHigh,
})
if err != nil {
log.Printf("Failed to send notification: %v", err)
// Application continues - notification failure is not fatal
return
}
log.Printf("Notification sent successfully: %s", resp.NotificationID)
```
### Additional Context
- This is a microservices architecture running in Kubernetes
- The notifier service handles routing to multiple notification backends (SMTP, Slack, Ntfy)
- The client may need to send notifications from multiple goroutines concurrently
- High reliability is important, but notification failures should not crash the application
- The API key has a rate limit of 100 requests per minute (may vary per key)
### Code Generation Note
If you need the protobuf definitions, they can be generated from the service's proto files located at `api/grpc/proto/notifier.proto` in the notifier service repository.
---
## Usage Instructions
**Copy the prompt above and provide it to your AI assistant when building the client. The prompt includes:**
- All authentication requirements and formats
- Connection management best practices
- Error handling strategies
- Security requirements
- Observability guidelines
- Complete API method listing
- Production-ready patterns
- Kubernetes deployment configuration
**The AI assistant should generate:**
- Complete, production-ready client code
- Proper connection pooling and keepalive
- Comprehensive error handling
- Secure credential management
- Health check implementation
- Unit tests
- Usage documentation
**Review the generated code for:**
- ✅ Single long-lived connection (not creating connections per request)
- ✅ API key sent in metadata with every RPC
- ✅ Keepalive configuration present
- ✅ Exponential backoff retry logic
- ✅ No hardcoded credentials
- ✅ Proper context timeouts
- ✅ Error handling for all gRPC error codes
- ✅ Graceful shutdown (Close() method)