feat(12-04): add Plan tRPC procedures
- Import PlanRepository type - Add requirePlanRepository helper - Add createPlan procedure (auto-assigns number if not provided) - Add listPlans procedure (returns plans ordered by number) - Add getPlan procedure (throws NOT_FOUND if not found) - Add updatePlan procedure (name, description, status)
This commit is contained in:
@@ -13,9 +13,10 @@ import type { TaskRepository } from '../db/repositories/task-repository.js';
|
|||||||
import type { MessageRepository } from '../db/repositories/message-repository.js';
|
import type { MessageRepository } from '../db/repositories/message-repository.js';
|
||||||
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
|
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
|
||||||
import type { PhaseRepository } from '../db/repositories/phase-repository.js';
|
import type { PhaseRepository } from '../db/repositories/phase-repository.js';
|
||||||
|
import type { PlanRepository } from '../db/repositories/plan-repository.js';
|
||||||
import type { DispatchManager } from '../dispatch/types.js';
|
import type { DispatchManager } from '../dispatch/types.js';
|
||||||
import type { CoordinationManager } from '../coordination/types.js';
|
import type { CoordinationManager } from '../coordination/types.js';
|
||||||
import type { Phase } from '../db/schema.js';
|
import type { Phase, Plan } from '../db/schema.js';
|
||||||
import { buildDiscussPrompt, buildBreakdownPrompt } from '../agent/prompts.js';
|
import { buildDiscussPrompt, buildBreakdownPrompt } from '../agent/prompts.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -264,6 +265,19 @@ function requirePhaseRepository(ctx: TRPCContext): PhaseRepository {
|
|||||||
return ctx.phaseRepository;
|
return ctx.phaseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to ensure planRepository is available in context.
|
||||||
|
*/
|
||||||
|
function requirePlanRepository(ctx: TRPCContext): PlanRepository {
|
||||||
|
if (!ctx.planRepository) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'INTERNAL_SERVER_ERROR',
|
||||||
|
message: 'Plan repository not available',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return ctx.planRepository;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Application Router with Procedures
|
// Application Router with Procedures
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -841,6 +855,79 @@ export const appRouter = router({
|
|||||||
return created;
|
return created;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// Plan Procedures
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new plan for a phase.
|
||||||
|
* Auto-assigns the next plan number if not provided.
|
||||||
|
*/
|
||||||
|
createPlan: publicProcedure
|
||||||
|
.input(z.object({
|
||||||
|
phaseId: z.string().min(1),
|
||||||
|
number: z.number().int().positive().optional(),
|
||||||
|
name: z.string().min(1),
|
||||||
|
description: z.string().optional(),
|
||||||
|
}))
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePlanRepository(ctx);
|
||||||
|
const number = input.number ?? await repo.getNextNumber(input.phaseId);
|
||||||
|
return repo.create({
|
||||||
|
phaseId: input.phaseId,
|
||||||
|
number,
|
||||||
|
name: input.name,
|
||||||
|
description: input.description ?? null,
|
||||||
|
status: 'pending',
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List plans for a phase.
|
||||||
|
* Returns plans ordered by number.
|
||||||
|
*/
|
||||||
|
listPlans: publicProcedure
|
||||||
|
.input(z.object({ phaseId: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePlanRepository(ctx);
|
||||||
|
return repo.findByPhaseId(input.phaseId);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a plan by ID.
|
||||||
|
* Throws NOT_FOUND if plan doesn't exist.
|
||||||
|
*/
|
||||||
|
getPlan: publicProcedure
|
||||||
|
.input(z.object({ id: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePlanRepository(ctx);
|
||||||
|
const plan = await repo.findById(input.id);
|
||||||
|
if (!plan) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'NOT_FOUND',
|
||||||
|
message: `Plan '${input.id}' not found`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a plan.
|
||||||
|
* Returns the updated plan.
|
||||||
|
*/
|
||||||
|
updatePlan: publicProcedure
|
||||||
|
.input(z.object({
|
||||||
|
id: z.string().min(1),
|
||||||
|
name: z.string().min(1).optional(),
|
||||||
|
description: z.string().optional(),
|
||||||
|
status: z.enum(['pending', 'in_progress', 'completed']).optional(),
|
||||||
|
}))
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePlanRepository(ctx);
|
||||||
|
const { id, ...data } = input;
|
||||||
|
return repo.update(id, data);
|
||||||
|
}),
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Architect Spawn Procedures
|
// Architect Spawn Procedures
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user