527 lines
16 KiB
Markdown
527 lines
16 KiB
Markdown
# API Completion Plan: Implementing Suppressed Features
|
|
|
|
**Date:** 2026-01-27
|
|
**Status:** Phase 1 & 3 Complete, Phase 2 In Progress
|
|
**Context:** During zero-warnings cleanup, several API methods and features were marked with `#[allow(dead_code)]` because they represent planned but unimplemented functionality. This document outlines a plan to implement these features.
|
|
|
|
## Overview
|
|
|
|
We identified 4 main categories of suppressed features:
|
|
1. **CLI Client REST operations** - Missing HTTP methods for full CRUD
|
|
2. **CLI Configuration management** - Incomplete config commands and profile support
|
|
3. **Token refresh mechanism** - Session management for long-running CLI usage
|
|
4. **Executor monitoring APIs** - Runtime inspection of policies and queues
|
|
|
|
---
|
|
|
|
## Priority 1: Token Refresh Mechanism (High Impact)
|
|
|
|
### Problem
|
|
- Access tokens expire after 1 hour
|
|
- Long-running CLI sessions require manual re-login
|
|
- No automatic token refresh flow
|
|
|
|
### Suppressed Methods
|
|
- `ApiClient::set_auth_token()` - Update token after refresh
|
|
- `ApiClient::clear_auth_token()` - Clear on logout/refresh failure
|
|
- `CliConfig::refresh_token()` - Get refresh token from config
|
|
|
|
### Implementation Plan
|
|
|
|
#### 1.1: Add Token Refresh API Endpoint
|
|
**File:** `attune/crates/api/src/routes/auth.rs`
|
|
|
|
```rust
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/auth/refresh",
|
|
request_body = RefreshTokenRequest,
|
|
responses(
|
|
(status = 200, description = "Token refreshed", body = LoginResponse),
|
|
(status = 401, description = "Invalid refresh token")
|
|
),
|
|
tag = "auth"
|
|
)]
|
|
async fn refresh_token(
|
|
State(state): State<AppState>,
|
|
Json(req): Json<RefreshTokenRequest>,
|
|
) -> Result<Json<ApiResponse<LoginResponse>>, ApiError> {
|
|
// Validate refresh token
|
|
// Generate new access token (and optionally new refresh token)
|
|
// Return new tokens
|
|
}
|
|
```
|
|
|
|
**Add DTO:** `attune/crates/api/src/dto/auth.rs`
|
|
```rust
|
|
#[derive(Deserialize)]
|
|
pub struct RefreshTokenRequest {
|
|
pub refresh_token: String,
|
|
}
|
|
```
|
|
|
|
#### 1.2: Implement Automatic Refresh in CLI Client
|
|
**File:** `attune/crates/cli/src/client.rs`
|
|
|
|
Add method:
|
|
```rust
|
|
pub async fn refresh_auth_token(&mut self) -> Result<()> {
|
|
// Get refresh token from config
|
|
// Call /auth/refresh endpoint
|
|
// Update auth_token with set_auth_token()
|
|
// Update config file with new tokens
|
|
}
|
|
```
|
|
|
|
Enhance `execute()` method:
|
|
```rust
|
|
async fn execute<T: DeserializeOwned>(&self, req: RequestBuilder) -> Result<T> {
|
|
let response = req.send().await?;
|
|
|
|
// If 401 and we have refresh token, try refresh once
|
|
if response.status() == StatusCode::UNAUTHORIZED {
|
|
if let Ok(Some(_)) = config.refresh_token() {
|
|
self.refresh_auth_token().await?;
|
|
// Retry original request with new token
|
|
}
|
|
}
|
|
|
|
self.handle_response(response).await
|
|
}
|
|
```
|
|
|
|
#### 1.3: Add Refresh Command (Optional)
|
|
**File:** `attune/crates/cli/src/commands/auth.rs`
|
|
|
|
```rust
|
|
AuthCommands::Refresh => {
|
|
// Manually refresh token
|
|
// Useful for testing or explicit refresh
|
|
}
|
|
```
|
|
|
|
**Effort:** 4-6 hours
|
|
**Dependencies:** None
|
|
**Value:** High - significantly improves CLI UX
|
|
|
|
---
|
|
|
|
## Priority 2: Complete CRUD Operations (High Impact)
|
|
|
|
### Problem
|
|
- CLI can only Create (POST) and Read (GET) resources
|
|
- No Update (PUT/PATCH) or Delete (DELETE) commands
|
|
- REST client API incomplete
|
|
|
|
### Suppressed Methods
|
|
- `ApiClient::put()` - For update operations
|
|
- `ApiClient::delete()` - For delete operations
|
|
- `ApiClient::get_with_query()` - For filtering/search
|
|
|
|
### Implementation Plan
|
|
|
|
#### 2.1: Resource Update Commands
|
|
Add update subcommands to existing command modules:
|
|
|
|
**Pack Updates** (`attune/crates/cli/src/commands/pack.rs`):
|
|
```rust
|
|
PackCommands::Update {
|
|
ref_name: String,
|
|
#[arg(long)] name: Option<String>,
|
|
#[arg(long)] description: Option<String>,
|
|
#[arg(long)] version: Option<String>,
|
|
#[arg(long)] enabled: Option<bool>,
|
|
} => {
|
|
let update = UpdatePackRequest { name, description, version, enabled };
|
|
let pack = client.put(&format!("/packs/{}", ref_name), &update).await?;
|
|
// Display updated pack
|
|
}
|
|
```
|
|
|
|
**Action Updates** (`attune/crates/cli/src/commands/action.rs`):
|
|
```rust
|
|
ActionCommands::Update {
|
|
ref_name: String,
|
|
#[arg(long)] name: Option<String>,
|
|
#[arg(long)] description: Option<String>,
|
|
#[arg(long)] enabled: Option<bool>,
|
|
} => {
|
|
// Similar pattern
|
|
}
|
|
```
|
|
|
|
Repeat for: Rules, Triggers, Sensors, Workflows
|
|
|
|
#### 2.2: Resource Delete Commands
|
|
Add delete subcommands:
|
|
|
|
```rust
|
|
PackCommands::Delete {
|
|
ref_name: String,
|
|
#[arg(long)] force: bool, // Skip confirmation
|
|
} => {
|
|
if !force {
|
|
let confirm = dialoguer::Confirm::new()
|
|
.with_prompt(&format!("Delete pack '{}'?", ref_name))
|
|
.interact()?;
|
|
if !confirm { return Ok(()); }
|
|
}
|
|
|
|
client.delete::<()>(&format!("/packs/{}", ref_name)).await?;
|
|
print_success(&format!("Pack '{}' deleted", ref_name));
|
|
}
|
|
```
|
|
|
|
#### 2.3: Search and Filtering
|
|
Enhance list commands with query parameters:
|
|
|
|
```rust
|
|
PackCommands::List {
|
|
#[arg(long)] enabled: Option<bool>,
|
|
#[arg(long)] search: Option<String>,
|
|
#[arg(long)] limit: Option<u32>,
|
|
#[arg(long)] offset: Option<u32>,
|
|
} => {
|
|
let mut query = vec![];
|
|
if let Some(enabled) = enabled {
|
|
query.push(format!("enabled={}", enabled));
|
|
}
|
|
if let Some(search) = search {
|
|
query.push(format!("search={}", search));
|
|
}
|
|
// Build query string and use get_with_query()
|
|
}
|
|
```
|
|
|
|
**Effort:** 8-12 hours
|
|
**Dependencies:** API endpoints must support PUT/DELETE (most already do)
|
|
**Value:** High - completes CLI feature parity with API
|
|
|
|
---
|
|
|
|
## Priority 3: Profile and Configuration Management (Medium Impact)
|
|
|
|
### Problem
|
|
- `--profile` flag declared in main.rs but not used
|
|
- `attune config set api-url` command defined but not implemented
|
|
- Profile switching requires manual `attune config use` command
|
|
|
|
### Suppressed Methods
|
|
- `CliConfig::set_api_url()` - Direct API URL update
|
|
- `CliConfig::load_with_profile()` - Load with profile override
|
|
- `CliConfig::api_url()` - Get current API URL
|
|
|
|
### Implementation Plan
|
|
|
|
#### 3.1: Implement `--profile` Flag Support
|
|
**File:** `attune/crates/cli/src/main.rs`
|
|
|
|
Currently the flag exists but is unused. Update `main()`:
|
|
|
|
```rust
|
|
#[tokio::main]
|
|
async fn main() -> Result<()> {
|
|
let cli = Cli::parse();
|
|
|
|
// Load config with profile override
|
|
let config = if let Some(profile) = &cli.profile {
|
|
CliConfig::load_with_profile(Some(profile))?
|
|
} else {
|
|
CliConfig::load()?
|
|
};
|
|
|
|
// Pass config to command handlers instead of loading fresh each time
|
|
}
|
|
```
|
|
|
|
Update all command handlers to accept `&CliConfig` parameter.
|
|
|
|
#### 3.2: Complete Config Set Command
|
|
**File:** `attune/crates/cli/src/commands/config.rs`
|
|
|
|
The `handle_set()` function exists but uses `set_value()` which only handles specific keys. Add:
|
|
|
|
```rust
|
|
async fn handle_set(key: String, value: String, output_format: OutputFormat) -> Result<()> {
|
|
let mut config = CliConfig::load()?;
|
|
|
|
match key.as_str() {
|
|
"api_url" | "api-url" => {
|
|
config.set_api_url(value.clone())?;
|
|
}
|
|
_ => {
|
|
config.set_value(&key, value.clone())?;
|
|
}
|
|
}
|
|
|
|
// Output handling...
|
|
}
|
|
```
|
|
|
|
#### 3.3: Add Config Get/Show Commands
|
|
```rust
|
|
ConfigCommands::Show => {
|
|
let config = CliConfig::load()?;
|
|
let profile = config.current_profile()?;
|
|
|
|
// Display full config including:
|
|
// - Current profile
|
|
// - API URL (from config.api_url())
|
|
// - Auth status
|
|
// - All settings
|
|
}
|
|
```
|
|
|
|
**Effort:** 3-4 hours
|
|
**Dependencies:** None
|
|
**Value:** Medium - improves multi-environment workflow
|
|
|
|
---
|
|
|
|
## Priority 4: Executor Monitoring APIs (Low-Medium Impact)
|
|
|
|
### Problem
|
|
- No visibility into executor runtime state
|
|
- Cannot inspect queue depths or policy enforcement
|
|
- No way to adjust policies at runtime
|
|
|
|
### Suppressed Methods in `attune/crates/executor/src/`:
|
|
- `PolicyEnforcer::new()`, `with_global_policy()`, `set_*_policy()`
|
|
- `PolicyEnforcer::check_policies()`, `wait_for_policy_compliance()`
|
|
- `QueueManager::get_all_queue_stats()`, `cancel_execution()`, `clear_all_queues()`
|
|
- `ExecutorService::pool()`, `config()`, `publisher()`
|
|
|
|
### Implementation Plan
|
|
|
|
#### 4.1: Add Executor Admin API Endpoints
|
|
**New File:** `attune/crates/api/src/routes/executor_admin.rs`
|
|
|
|
```rust
|
|
// Queue monitoring
|
|
GET /api/v1/admin/executor/queues
|
|
-> List all action queues with stats (depth, active, capacity)
|
|
|
|
GET /api/v1/admin/executor/queues/{action_id}
|
|
-> Detailed queue stats for specific action
|
|
|
|
// Policy inspection
|
|
GET /api/v1/admin/executor/policies
|
|
-> List all configured policies (global, pack, action)
|
|
|
|
// Policy management (future)
|
|
POST /api/v1/admin/executor/policies/global
|
|
-> Set global execution policy
|
|
|
|
POST /api/v1/admin/executor/policies/pack/{pack_id}
|
|
-> Set pack-specific policy
|
|
|
|
POST /api/v1/admin/executor/policies/action/{action_id}
|
|
-> Set action-specific policy
|
|
|
|
// Queue operations
|
|
POST /api/v1/admin/executor/queues/{action_id}/clear
|
|
-> Clear queue for action (emergency)
|
|
|
|
DELETE /api/v1/admin/executor/queues/{action_id}/executions/{execution_id}
|
|
-> Cancel queued execution
|
|
```
|
|
|
|
#### 4.2: Expose Executor State via Message Queue
|
|
**Alternative approach:** Instead of HTTP API, use pub/sub:
|
|
|
|
```rust
|
|
// Executor publishes stats periodically
|
|
topic: "executor.stats"
|
|
payload: {
|
|
"queues": [...],
|
|
"policies": [...],
|
|
"active_executions": 42
|
|
}
|
|
|
|
// API service subscribes and caches latest stats
|
|
// Serves from cache on GET /admin/executor/stats
|
|
```
|
|
|
|
#### 4.3: Add CLI Admin Commands
|
|
**New File:** `attune/crates/cli/src/commands/admin.rs`
|
|
|
|
```rust
|
|
#[derive(Subcommand)]
|
|
pub enum AdminCommands {
|
|
/// Executor administration
|
|
Executor {
|
|
#[command(subcommand)]
|
|
command: ExecutorAdminCommands,
|
|
},
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
pub enum ExecutorAdminCommands {
|
|
/// Show queue statistics
|
|
Queues {
|
|
#[arg(long)] action: Option<String>,
|
|
},
|
|
/// Show policy configuration
|
|
Policies,
|
|
/// Clear a queue (dangerous)
|
|
ClearQueue {
|
|
action: String,
|
|
#[arg(long)] confirm: bool,
|
|
},
|
|
}
|
|
```
|
|
|
|
**Effort:** 6-10 hours
|
|
**Dependencies:** Requires deciding on HTTP API vs. message queue approach
|
|
**Value:** Medium - mainly for ops/debugging, not end-user facing
|
|
|
|
---
|
|
|
|
## Non-Priority Items (Keep Suppressed)
|
|
|
|
These items should remain with `#[allow(dead_code)]` for now:
|
|
|
|
### Test Infrastructure
|
|
- `attune/crates/api/tests/helpers.rs` - Test helper methods
|
|
- `attune/crates/cli/tests/common/mod.rs` - Mock functions
|
|
- `attune/crates/executor/tests/*` - Test runtime helpers
|
|
|
|
**Reason:** These are test utilities that may be used in future tests. They provide a complete test API surface even if not all methods are currently used.
|
|
|
|
### Service Internal Fields
|
|
- `WorkerService.config` - Kept for potential future use
|
|
- `ExecutorService.queue_name` - Backward compatibility
|
|
- `Subscriber.client_id`, `user_id` - Structural completeness
|
|
- `WorkflowExecutionHandle.workflow_def_id` - May be needed for advanced workflow features
|
|
|
|
**Reason:** These maintain API completeness and may be needed for future features. Removing them would require breaking changes.
|
|
|
|
### Methods Only Used in Tests
|
|
- `PolicyEnforcer::new()` (vs. `with_queue_manager()`)
|
|
- `QueueManager::new()`, `with_defaults()` (vs. `with_db_pool()`)
|
|
|
|
**Reason:** Simpler constructors useful for unit testing. Production code uses more complete constructors.
|
|
|
|
---
|
|
|
|
## Implementation Roadmap
|
|
|
|
### Phase 1: Foundation ✅ COMPLETE
|
|
1. ✅ **Token Refresh Mechanism** (Priority 1) - COMPLETE 2026-01-27
|
|
- ✅ API endpoint (already existed)
|
|
- ✅ CLI client auto-refresh implemented
|
|
- ✅ Manual refresh command (`attune auth refresh`)
|
|
- ✅ Config file persistence of refreshed tokens
|
|
- ✅ Zero warnings, fully functional
|
|
- **Testing:** Auto-refresh on 401, manual refresh command tested
|
|
|
|
### Phase 2: CLI Feature Completion ✅ COMPLETE
|
|
2. ✅ **CRUD Operations** (Priority 2) - COMPLETE 2026-01-27
|
|
- ✅ Update commands implemented for actions, rules, triggers, packs
|
|
- ✅ Delete commands with confirmation for actions, triggers (rules/packs already had it)
|
|
- ✅ All ApiClient HTTP methods now active (PUT, DELETE)
|
|
- ✅ Zero dead_code warnings for implemented features
|
|
- **Testing:** All CLI tests pass (2 pre-existing auth failures unrelated)
|
|
|
|
### Phase 3: Configuration Enhancement ✅ COMPLETE
|
|
3. ✅ **Profile Management** (Priority 3) - COMPLETE 2026-01-27
|
|
- ✅ `--profile` flag fully implemented across all commands
|
|
- ✅ `CliConfig::load_with_profile()` method
|
|
- ✅ All command handlers updated (auth, action, rule, execution, key, sensor, trigger, pack, config)
|
|
- ✅ Zero warnings, fully functional
|
|
- **Testing:** All CLI tests pass with profile support
|
|
|
|
### Phase 4: Operational Visibility (Week 6-8, Optional)
|
|
4. ⏳ **Executor Monitoring** (Priority 4)
|
|
- Design decision: HTTP API vs. pub/sub
|
|
- Implement chosen approach
|
|
- CLI admin commands
|
|
- **Blockers:** Architecture decision needed
|
|
- **Testing:** Requires running executor instances
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
### Phase 1 Complete ✅
|
|
- [x] Users can work with CLI for >1 hour without re-login
|
|
- [x] Expired tokens automatically refresh transparently
|
|
- [x] Manual `attune auth refresh` command works
|
|
|
|
### Phase 2 Complete ✅
|
|
- [x] All resources support full CRUD via CLI (Create, Read, Update, Delete)
|
|
- [x] Update commands accept optional fields (label, description, etc.)
|
|
- [x] Delete operations require confirmation (unless --yes flag)
|
|
- [x] Users can manage entire platform lifecycle from CLI
|
|
|
|
### Phase 3 Complete ✅
|
|
- [x] `--profile dev/staging/prod` flag works across all commands
|
|
- [x] `attune config set api-url <url>` updates current profile
|
|
- [x] Multi-environment workflows seamless
|
|
|
|
### Phase 4 Complete
|
|
- [ ] Operators can view executor queue depths
|
|
- [ ] Policy configuration visible via API/CLI
|
|
- [ ] Emergency queue operations available
|
|
|
|
---
|
|
|
|
## Risk Assessment
|
|
|
|
### Low Risk
|
|
- **Token refresh:** Well-defined pattern, existing JWT infrastructure
|
|
- **CRUD completion:** API endpoints mostly exist, just need CLI wiring
|
|
- **Profile flag:** Simple config plumbing
|
|
|
|
### Medium Risk
|
|
- **Executor monitoring:** Architecture decision required (HTTP vs. message queue)
|
|
- HTTP: Simpler but requires executor to expose endpoints
|
|
- Message Queue: More scalable but adds complexity
|
|
- **Recommendation:** Start with HTTP for simplicity
|
|
|
|
### Dependency Risks
|
|
- No major dependencies between phases
|
|
- Each phase can be implemented independently
|
|
- Phase 4 can be deferred if priorities change
|
|
|
|
---
|
|
|
|
## Documentation Updates Required
|
|
|
|
After implementation:
|
|
1. Update `docs/cli-reference.md` with new commands
|
|
2. Update `docs/api-authentication.md` with refresh flow
|
|
3. Add `docs/cli-configuration.md` with profile examples
|
|
4. Add `docs/executor-monitoring.md` (Phase 4)
|
|
5. Update this document's status to "Complete"
|
|
|
|
---
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: Remove Suppressed Methods
|
|
**Rejected:** These methods represent planned functionality with clear use cases. Removing them would require re-adding later with breaking changes.
|
|
|
|
### Alternative 2: Implement All at Once
|
|
**Rejected:** Phased approach allows for incremental value delivery and testing. Phase 4 can be deferred if needed.
|
|
|
|
### Alternative 3: Auto-generate CLI from OpenAPI
|
|
**Deferred:** Would eliminate need for manual CLI CRUD implementation, but requires significant tooling investment. Consider for future major version.
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Review this plan** with team/stakeholders
|
|
2. **Decide on Phase 4 architecture** (HTTP vs. message queue)
|
|
3. **Create GitHub issues** for each phase
|
|
4. **Implement Phase 1** (highest impact, no blockers)
|
|
5. **Update this document** as implementation progresses
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
- `attune/docs/dead-code-cleanup.md` - Warning cleanup context
|
|
- `attune/docs/cli-reference.md` - Current CLI commands
|
|
- `attune/docs/api-authentication.md` - Auth flow documentation
|
|
- `attune/CHANGELOG.md` - Historical context on warning fixes |