CODEX_ADK/FRONTEND/claude.md
jean-philippe 3fae2fcbe1 Initial commit: CODEX_ADK (Svrnty Console) MVP v1.0.0
This is the initial commit for the CODEX_ADK project, a full-stack AI agent
management platform featuring:

BACKEND (ASP.NET Core 8.0):
- CQRS architecture with 6 commands and 7 queries
- 16 API endpoints (all working and tested)
- PostgreSQL database with 5 entities
- AES-256 encryption for API keys
- FluentValidation on all commands
- Rate limiting and CORS configured
- OpenAPI/Swagger documentation
- Docker Compose setup (PostgreSQL + Ollama)

FRONTEND (Flutter 3.x):
- Dark theme with Svrnty branding
- Collapsible sidebar navigation
- CQRS API client with Result<T> error handling
- Type-safe endpoints from OpenAPI schema
- Multi-platform support (Web, iOS, Android, macOS, Linux, Windows)

DOCUMENTATION:
- Comprehensive API reference
- Architecture documentation
- Development guidelines for Claude Code
- API integration guides
- context-claude.md project overview

Status: Backend ready (Grade A-), Frontend integration pending

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 18:32:38 -04:00

416 lines
10 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Svrnty Console is a Flutter-based management console for the Svrnty AI platform. It communicates with a C# CQRS backend using a type-safe, OpenAPI-driven API contract system.
**Tech Stack:**
- Flutter 3.x / Dart 3.9.2+
- CQRS API pattern (Command Query Responsibility Segregation)
- OpenAPI 3.0.1 contract-first architecture
- Custom theme: Crimson Red (#C44D58), Slate Blue (#475C6C)
- Fonts: Montserrat (UI), IBM Plex Mono (code/technical)
---
## Essential Commands
### Development
```bash
# Install dependencies
flutter pub get
# Run the application
flutter run
# Run on specific platform
flutter run -d macos
flutter run -d chrome
```
### Testing & Quality
```bash
# Run tests
flutter test
# Run static analysis
flutter analyze
# Verify API type safety (custom script)
./scripts/verify_api_types.sh
```
### API Contract Updates
```bash
# After backend updates openapi.json:
cp ../backend/docs/openapi.json ./api-schema.json
./scripts/update_api_client.sh
# Or run code generation directly:
flutter pub run build_runner build --delete-conflicting-outputs
# Clean build (if generation fails):
flutter clean
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputs
```
### Build
```bash
# Build for production
flutter build macos
flutter build web
flutter build ios
```
---
## Architecture Principles
### 1. OpenAPI-Driven API Contract
The backend and frontend share a single source of truth: `api-schema.json` (OpenAPI specification).
**Flow:**
1. Backend exports `docs/openapi.json` from C# controllers + XML docs
2. Frontend copies to `api-schema.json`
3. Code generation creates Dart types from contract
4. Frontend creates endpoint extensions using generated types
**Key Files:**
- `api-schema.json` - OpenAPI contract (copy from backend)
- `lib/api/client.dart` - CQRS client implementation
- `lib/api/types.dart` - Core types (Result, Serializable, errors)
- `lib/api/endpoints/` - Type-safe endpoint extensions
- `lib/api/generated/` - Auto-generated code (git-ignored)
### 2. CQRS Pattern
All backend endpoints follow CQRS with three operation types:
**Queries (Read):**
```dart
final result = await client.executeQuery<UserDto>(
endpoint: 'users/123',
query: GetUserQuery(userId: '123'),
fromJson: UserDto.fromJson,
);
```
**Commands (Write):**
```dart
final result = await client.executeCommand(
endpoint: 'createUser',
command: CreateUserCommand(name: 'John', email: 'john@example.com'),
);
```
**Paginated Queries (Lists):**
```dart
final result = await client.executePaginatedQuery<UserDto>(
endpoint: 'users',
query: ListUsersQuery(),
itemFromJson: UserDto.fromJson,
page: 1,
pageSize: 20,
filters: [FilterCriteria(field: 'status', operator: FilterOperator.equals, value: 'active')],
sorting: [SortCriteria(field: 'createdAt', direction: SortDirection.descending)],
);
```
**Important:** ALL CQRS endpoints use JSON body via POST, even empty queries send `{}`.
### 3. Functional Error Handling
Never use try-catch for API calls. Use the `Result<T>` type:
```dart
// Pattern matching
final result = await client.getUser('123');
result.when(
success: (user) => print('Hello ${user.name}'),
error: (error) => print('Error: ${error.message}'),
);
// Or switch expression
final message = switch (result) {
ApiSuccess(value: final user) => 'Hello ${user.name}',
ApiError(error: final err) => 'Error: ${err.message}',
};
```
---
## Mandatory Coding Standards
### Strict Typing - NO EXCEPTIONS
See `.claude-docs/strict-typing.md` for complete requirements.
**Core Rules:**
1. Every variable must have explicit type annotation
2. Every function parameter must be typed
3. Every function return value must be typed
4. **NEVER** use `dynamic` (Dart's version of `any`)
5. **NEVER** use untyped `var` declarations
6. Use proper generics, interfaces, and type unions
**Examples:**
❌ FORBIDDEN:
```dart
dynamic value = getValue();
void handleData(var data) { ... }
```
✅ REQUIRED:
```dart
UserData value = getValue();
void handleData(RequestData data) { ... }
```
### Serializable Interface
All queries, commands, and DTOs must implement:
```dart
abstract interface class Serializable {
Map<String, Object?> toJson();
}
// Example:
class GetUserQuery implements Serializable {
final String userId;
const GetUserQuery({required this.userId});
@override
Map<String, Object?> toJson() => {'userId': userId};
}
```
---
## Response Protocol
See `.claude-docs/response-protocol.md` for complete protocol.
**All responses must end with structured choices:**
**Binary Choice:**
```
(always read claude.md to keep context between interactions)
(Y) Yes — [brief action summary]
(N) No — [brief alternative/reason]
(+) I don't understand — ask for clarification
```
**Multiple Choice:**
```
(always read claude.md to keep context between interactions)
(A) Option A — [≤8 words description]
(B) Option B — [≤8 words description]
(C) Option C — [≤8 words description]
(+) I don't understand — ask for clarification
```
When user selects `(+)`, explain the concept, then re-present options.
---
## Adding New API Endpoints
### Step 1: Backend adds endpoint
Backend team documents in C# controller with XML comments and exports `docs/openapi.json`.
### Step 2: Update contract
```bash
cp ../backend/docs/openapi.json ./api-schema.json
./scripts/update_api_client.sh
```
### Step 3: Create endpoint extension
Create file in `lib/api/endpoints/`:
```dart
import '../client.dart';
import '../types.dart';
extension UserEndpoint on CqrsApiClient {
Future<Result<UserDto>> getUser(String userId) async {
return executeQuery<UserDto>(
endpoint: 'users/$userId',
query: GetUserQuery(userId: userId),
fromJson: UserDto.fromJson,
);
}
}
// Define query (matches backend contract)
class GetUserQuery implements Serializable {
final String userId;
const GetUserQuery({required this.userId});
@override
Map<String, Object?> toJson() => {'userId': userId};
}
// Define DTO (from OpenAPI schema)
class UserDto {
final String id;
final String name;
final String email;
const UserDto({required this.id, required this.name, required this.email});
factory UserDto.fromJson(Map<String, Object?> json) => UserDto(
id: json['id'] as String,
name: json['name'] as String,
email: json['email'] as String,
);
}
```
### Step 4: Export from api.dart
Add to `lib/api/api.dart`:
```dart
export 'endpoints/user_endpoint.dart';
```
---
## Configuration
### API Client Setup
**Development (localhost):**
```dart
final client = CqrsApiClient(
config: ApiClientConfig.development, // http://localhost:5246
);
```
**Android Emulator:**
```dart
final client = CqrsApiClient(
config: ApiClientConfig(
baseUrl: 'http://10.0.2.2:5246', // Special emulator IP
timeout: Duration(seconds: 30),
),
);
```
**Production:**
```dart
final client = CqrsApiClient(
config: ApiClientConfig(
baseUrl: 'https://api.svrnty.com',
timeout: Duration(seconds: 30),
defaultHeaders: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $accessToken',
},
),
);
```
Always call `client.dispose()` when done.
---
## Error Handling
### Error Types
- `ApiErrorType.network` - No internet/DNS failure
- `ApiErrorType.http` - 4xx/5xx responses
- `ApiErrorType.serialization` - JSON parsing failed
- `ApiErrorType.timeout` - Request took too long
- `ApiErrorType.validation` - Backend validation error (422)
- `ApiErrorType.unknown` - Unexpected errors
### Handling Patterns
```dart
result.when(
success: (data) { /* handle success */ },
error: (error) {
switch (error.type) {
case ApiErrorType.network:
showSnackbar('No internet connection');
case ApiErrorType.timeout:
showSnackbar('Request timed out');
case ApiErrorType.validation:
showValidationErrors(error.details);
case ApiErrorType.http:
if (error.statusCode == 401) navigateToLogin();
else showSnackbar('Server error: ${error.message}');
default:
showSnackbar('Unexpected error: ${error.message}');
}
},
);
```
---
## Important Workflows
### When Backend Changes API Contract
1. Backend team notifies: "Updated API - added X endpoint"
2. Check backend CHANGELOG: `cat ../backend/docs/CHANGELOG.md`
3. Update contract: `cp ../backend/docs/openapi.json ./api-schema.json`
4. Regenerate: `./scripts/update_api_client.sh`
5. Add endpoint extension if needed (see "Adding New API Endpoints")
6. Run tests: `flutter test`
7. Verify types: `./scripts/verify_api_types.sh`
8. Commit: `git commit -m "feat: Add X endpoint integration"`
### Troubleshooting
**Code generation fails:**
```bash
flutter clean
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputs
```
**Type errors after regenerating:**
Backend made breaking changes. Check `../backend/docs/CHANGELOG.md` and update code accordingly.
**Network error on device:**
- iOS/Real device: Use actual IP (e.g., `http://192.168.1.100:5246`)
- Android emulator: Use `http://10.0.2.2:5246`
**JSON parsing error:**
1. Verify `api-schema.json` matches backend's `docs/openapi.json`
2. Check DTO `fromJson` matches OpenAPI schema
3. Verify backend returned correct content-type
---
## Additional Documentation
- **API Integration Guide:** `README_API.md` (comprehensive API documentation)
- **Strict Typing Rules:** `.claude-docs/strict-typing.md` (mandatory)
- **Response Protocol:** `.claude-docs/response-protocol.md` (mandatory)
- **Backend Docs:** `../backend/docs/` (architecture, changelog)
- **OpenAPI Contract:** `api-schema.json` (source of truth)
---
## Key Reminders
1. **OpenAPI is Source of Truth** - Always regenerate from `api-schema.json`
2. **CQRS Pattern** - All endpoints use POST with JSON body (even empty `{}`)
3. **Type Safety** - No `dynamic` types, use `Serializable` interface
4. **Functional Errors** - Use `Result<T>`, not try-catch
5. **Monitor Backend CHANGELOG** - Breaking changes documented there
6. **Test Everything** - Unit tests + integration tests
7. **Follow Response Protocol** - All responses end with structured choices
8. **Strict Typing** - Explicit types everywhere, no exceptions