feat(11-04): add initiative tRPC procedures
- Add requireInitiativeRepository helper function - Add createInitiative mutation procedure - Add listInitiatives query with optional status filter - Add getInitiative query with NOT_FOUND error handling - Add updateInitiative mutation procedure
This commit is contained in:
@@ -11,8 +11,11 @@ import type { TRPCContext } from './context.js';
|
||||
import type { AgentInfo, AgentResult } from '../agent/types.js';
|
||||
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||
import type { MessageRepository } from '../db/repositories/message-repository.js';
|
||||
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
|
||||
import type { PhaseRepository } from '../db/repositories/phase-repository.js';
|
||||
import type { DispatchManager } from '../dispatch/types.js';
|
||||
import type { CoordinationManager } from '../coordination/types.js';
|
||||
import type { Phase } from '../db/schema.js';
|
||||
|
||||
/**
|
||||
* Initialize tRPC with our context type.
|
||||
@@ -232,6 +235,32 @@ function requireCoordinationManager(ctx: TRPCContext): CoordinationManager {
|
||||
return ctx.coordinationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to ensure initiativeRepository is available in context.
|
||||
*/
|
||||
function requireInitiativeRepository(ctx: TRPCContext): InitiativeRepository {
|
||||
if (!ctx.initiativeRepository) {
|
||||
throw new TRPCError({
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: 'Initiative repository not available',
|
||||
});
|
||||
}
|
||||
return ctx.initiativeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to ensure phaseRepository is available in context.
|
||||
*/
|
||||
function requirePhaseRepository(ctx: TRPCContext): PhaseRepository {
|
||||
if (!ctx.phaseRepository) {
|
||||
throw new TRPCError({
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: 'Phase repository not available',
|
||||
});
|
||||
}
|
||||
return ctx.phaseRepository;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Application Router with Procedures
|
||||
// =============================================================================
|
||||
@@ -633,6 +662,79 @@ export const appRouter = router({
|
||||
const coordinationManager = requireCoordinationManager(ctx);
|
||||
return coordinationManager.getNextMergeable();
|
||||
}),
|
||||
|
||||
// ===========================================================================
|
||||
// Initiative Procedures
|
||||
// ===========================================================================
|
||||
|
||||
/**
|
||||
* Create a new initiative.
|
||||
* Returns the created initiative with generated ID.
|
||||
*/
|
||||
createInitiative: publicProcedure
|
||||
.input(z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const repo = requireInitiativeRepository(ctx);
|
||||
return repo.create({
|
||||
name: input.name,
|
||||
description: input.description ?? null,
|
||||
status: 'active',
|
||||
});
|
||||
}),
|
||||
|
||||
/**
|
||||
* List all initiatives with optional status filter.
|
||||
* Returns initiatives ordered by creation time.
|
||||
*/
|
||||
listInitiatives: publicProcedure
|
||||
.input(z.object({
|
||||
status: z.enum(['active', 'completed', 'archived']).optional(),
|
||||
}).optional())
|
||||
.query(async ({ ctx, input }) => {
|
||||
const repo = requireInitiativeRepository(ctx);
|
||||
if (input?.status) {
|
||||
return repo.findByStatus(input.status);
|
||||
}
|
||||
return repo.findAll();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get an initiative by ID.
|
||||
* Throws NOT_FOUND if initiative doesn't exist.
|
||||
*/
|
||||
getInitiative: publicProcedure
|
||||
.input(z.object({ id: z.string().min(1) }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const repo = requireInitiativeRepository(ctx);
|
||||
const initiative = await repo.findById(input.id);
|
||||
if (!initiative) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: `Initiative '${input.id}' not found`,
|
||||
});
|
||||
}
|
||||
return initiative;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Update an initiative.
|
||||
* Returns the updated initiative.
|
||||
*/
|
||||
updateInitiative: publicProcedure
|
||||
.input(z.object({
|
||||
id: z.string().min(1),
|
||||
name: z.string().min(1).optional(),
|
||||
description: z.string().optional(),
|
||||
status: z.enum(['active', 'completed', 'archived']).optional(),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const repo = requireInitiativeRepository(ctx);
|
||||
const { id, ...data } = input;
|
||||
return repo.update(id, data);
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user