diff options
Diffstat (limited to 'makima/src/server')
| -rw-r--r-- | makima/src/server/handlers/directives.rs | 60 | ||||
| -rw-r--r-- | makima/src/server/mod.rs | 1 | ||||
| -rw-r--r-- | makima/src/server/openapi.rs | 1 |
3 files changed, 62 insertions, 0 deletions
diff --git a/makima/src/server/handlers/directives.rs b/makima/src/server/handlers/directives.rs index 91f5892..7a7aff4 100644 --- a/makima/src/server/handlers/directives.rs +++ b/makima/src/server/handlers/directives.rs @@ -227,6 +227,17 @@ pub async fn update_directive( "Snapshotted directive revision on PR creation" ); } + + // Transition the contract to 'inactive' now that its + // iteration is "shipped" — editing the goal again starts + // an amendment cycle, surfaced via the New draft action. + if let Err(e) = repository::set_directive_inactive(pool, directive.id).await { + tracing::warn!( + directive_id = %directive.id, + error = %e, + "Failed to mark directive inactive after PR creation" + ); + } } } Json(directive).into_response() @@ -2094,6 +2105,55 @@ pub struct DirectiveRevisionListResponse { pub total: i64, } +/// Reset a directive for a new draft cycle — clears its goal and detaches +/// the current PR linkage. Past revisions remain attached as history. +/// +/// Intended for the sidebar's "New draft" right-click on an inactive +/// directive: the contract has shipped, the user wants to start the next +/// iteration on a clean slate without losing the prior PR's record. +#[utoipa::path( + post, + path = "/api/v1/directives/{id}/new-draft", + params(("id" = Uuid, Path, description = "Directive ID")), + responses( + (status = 200, description = "Directive reset to draft", body = Directive), + (status = 404, description = "Not found", body = ApiError), + (status = 503, description = "Database not configured", body = ApiError), + ), + security(("bearer_auth" = []), ("api_key" = [])), + tag = "Directives" +)] +pub async fn new_directive_draft( + State(state): State<SharedState>, + Authenticated(auth): Authenticated, + Path(id): Path<Uuid>, +) -> impl IntoResponse { + let Some(ref pool) = state.db_pool else { + return ( + StatusCode::SERVICE_UNAVAILABLE, + Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")), + ) + .into_response(); + }; + + match repository::reset_directive_for_new_draft(pool, auth.owner_id, id).await { + Ok(Some(directive)) => Json(directive).into_response(), + Ok(None) => ( + StatusCode::NOT_FOUND, + Json(ApiError::new("NOT_FOUND", "Directive not found")), + ) + .into_response(), + Err(e) => { + tracing::error!("Failed to reset directive for new draft: {}", e); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError::new("RESET_FAILED", &e.to_string())), + ) + .into_response() + } + } +} + /// List all per-PR revisions for a directive, newest first. #[utoipa::path( get, diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs index 31052bf..c577904 100644 --- a/makima/src/server/mod.rs +++ b/makima/src/server/mod.rs @@ -254,6 +254,7 @@ pub fn make_router(state: SharedState) -> Router { .route("/directives/{id}/steps/{step_id}/skip", post(directives::skip_step)) .route("/directives/{id}/goal", put(directives::update_goal)) .route("/directives/{id}/revisions", get(directives::list_directive_revisions)) + .route("/directives/{id}/new-draft", post(directives::new_directive_draft)) .route("/directives/{id}/cleanup", post(directives::cleanup_directive)) .route("/directives/{id}/create-pr", post(directives::create_pr)) .route("/directives/{id}/pick-up-orders", post(directives::pick_up_orders)) diff --git a/makima/src/server/openapi.rs b/makima/src/server/openapi.rs index e3ff757..e6d4547 100644 --- a/makima/src/server/openapi.rs +++ b/makima/src/server/openapi.rs @@ -131,6 +131,7 @@ use crate::server::messages::{ApiError, AudioEncoding, StartMessage, StopMessage directives::skip_step, directives::update_goal, directives::list_directive_revisions, + directives::new_directive_draft, directives::cleanup_directive, directives::create_pr, // Order endpoints |
