fix: Schema alignment and code corrections (COA 2)
All checks were successful
Test Asgard Runner / test (push) Successful in 3s

- Replace owner_id → owner_user_id in all queries
- Replace auth_token → companion_agent_token in server_connections
- Replace l.active → (l.status = 'active') checks using ENUM
- Fix AppError → ApiError in all new API files
- Add missing imports (Path, PanelAdapter trait)
- Fix StoreConfig nullable type mismatches

Resolves 122 compilation errors. Only sqlx cache generation remains.

Phase 3: EXECUTE complete per V4_WORKFLOW
This commit is contained in:
Vantz Stockwell
2026-02-15 18:23:33 -05:00
parent d7dddca106
commit 500d92cbe3
8 changed files with 342 additions and 82 deletions

View File

@@ -1,5 +1,5 @@
use axum::{
extract::{Request, State},
extract::{Path, Request, State},
http::StatusCode,
middleware::{self, Next},
response::{IntoResponse, Response},
@@ -11,7 +11,7 @@ use std::sync::Arc;
use uuid::Uuid;
use crate::{
models::error::AppError,
models::error::ApiError,
services::host_provisioning::{HostProvisioningService, ProvisionedLicense},
AppState,
};
@@ -29,16 +29,16 @@ async fn host_auth_middleware(
State(state): State<Arc<AppState>>,
mut req: Request,
next: Next,
) -> Result<Response, AppError> {
) -> Result<Response, ApiError> {
// Extract API key from Authorization header (Bearer token)
let auth_header = req
.headers()
.get("Authorization")
.and_then(|h| h.to_str().ok())
.ok_or_else(|| AppError::Unauthorized("Missing Authorization header".to_string()))?;
.ok_or_else(|| ApiError::Unauthorized("Missing Authorization header".to_string()))?;
if !auth_header.starts_with("Bearer ") {
return Err(AppError::Unauthorized("Invalid Authorization format. Use: Bearer <api_key>".to_string()));
return Err(ApiError::Unauthorized("Invalid Authorization format. Use: Bearer <api_key>".to_string()));
}
let api_key = &auth_header[7..]; // Skip "Bearer "
@@ -48,7 +48,7 @@ async fn host_auth_middleware(
let host_id = service
.authenticate_host(api_key)
.await
.map_err(|_| AppError::Unauthorized("Invalid or inactive API key".to_string()))?;
.map_err(|_| ApiError::Unauthorized("Invalid or inactive API key".to_string()))?;
// Store host_id in request extensions for handlers to access
req.extensions_mut().insert(HostContext { host_id });
@@ -87,7 +87,7 @@ async fn provision_license(
State(state): State<Arc<AppState>>,
axum::extract::Extension(ctx): axum::extract::Extension<HostContext>,
Json(req): Json<ProvisionRequest>,
) -> Result<impl IntoResponse, AppError> {
) -> Result<impl IntoResponse, ApiError> {
let service = HostProvisioningService::new(state.db.clone());
// Use hostname if provided, otherwise use server_id
@@ -125,13 +125,13 @@ struct HostLicenseInfo {
async fn list_host_licenses(
State(state): State<Arc<AppState>>,
axum::extract::Extension(ctx): axum::extract::Extension<HostContext>,
) -> Result<impl IntoResponse, AppError> {
) -> Result<impl IntoResponse, ApiError> {
let licenses = sqlx::query!(
"SELECT
l.license_key,
l.server_name,
l.subdomain,
l.active,
(l.status = 'active') as \"active!\",
hl.customer_email,
hl.last_seen_at,
hl.provisioned_at
@@ -187,10 +187,10 @@ async fn get_billing_report(
State(state): State<Arc<AppState>>,
axum::extract::Extension(ctx): axum::extract::Extension<HostContext>,
Path(month): axum::extract::Path<String>,
) -> Result<impl IntoResponse, AppError> {
) -> Result<impl IntoResponse, ApiError> {
// Parse month (format: YYYY-MM)
let billing_month = chrono::NaiveDate::parse_from_str(&format!("{}-01", month), "%Y-%m-%d")
.map_err(|_| AppError::BadRequest("Invalid month format. Use YYYY-MM (e.g., 2026-02)".to_string()))?;
.map_err(|_| ApiError::BadRequest("Invalid month format. Use YYYY-MM (e.g., 2026-02)".to_string()))?;
// Get billing record
let record = sqlx::query!(
@@ -223,7 +223,7 @@ async fn get_billing_report(
"SELECT
l.license_key,
l.server_name,
l.active,
(l.status = 'active') as \"active!\",
hl.customer_email,
hl.last_seen_at
FROM host_licenses hl