feat(11-04): add phase tRPC procedures
- Add requirePhaseRepository helper function - Add createPhase mutation with auto-numbering - Add listPhases query by initiative ID - Add getPhase query with NOT_FOUND error handling - Add updatePhase mutation procedure - Add createPhasesFromBreakdown bulk create mutation
This commit is contained in:
@@ -735,6 +735,107 @@ export const appRouter = router({
|
|||||||
const { id, ...data } = input;
|
const { id, ...data } = input;
|
||||||
return repo.update(id, data);
|
return repo.update(id, data);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// Phase Procedures
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new phase for an initiative.
|
||||||
|
* Auto-assigns the next phase number.
|
||||||
|
*/
|
||||||
|
createPhase: publicProcedure
|
||||||
|
.input(z.object({
|
||||||
|
initiativeId: z.string().min(1),
|
||||||
|
name: z.string().min(1),
|
||||||
|
description: z.string().optional(),
|
||||||
|
}))
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePhaseRepository(ctx);
|
||||||
|
const nextNumber = await repo.getNextNumber(input.initiativeId);
|
||||||
|
return repo.create({
|
||||||
|
initiativeId: input.initiativeId,
|
||||||
|
number: nextNumber,
|
||||||
|
name: input.name,
|
||||||
|
description: input.description ?? null,
|
||||||
|
status: 'pending',
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List phases for an initiative.
|
||||||
|
* Returns phases ordered by number.
|
||||||
|
*/
|
||||||
|
listPhases: publicProcedure
|
||||||
|
.input(z.object({ initiativeId: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePhaseRepository(ctx);
|
||||||
|
return repo.findByInitiativeId(input.initiativeId);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a phase by ID.
|
||||||
|
* Throws NOT_FOUND if phase doesn't exist.
|
||||||
|
*/
|
||||||
|
getPhase: publicProcedure
|
||||||
|
.input(z.object({ id: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePhaseRepository(ctx);
|
||||||
|
const phase = await repo.findById(input.id);
|
||||||
|
if (!phase) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'NOT_FOUND',
|
||||||
|
message: `Phase '${input.id}' not found`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return phase;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a phase.
|
||||||
|
* Returns the updated phase.
|
||||||
|
*/
|
||||||
|
updatePhase: 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 = requirePhaseRepository(ctx);
|
||||||
|
const { id, ...data } = input;
|
||||||
|
return repo.update(id, data);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create multiple phases from Architect breakdown output.
|
||||||
|
* Accepts pre-numbered phases and creates them in bulk.
|
||||||
|
*/
|
||||||
|
createPhasesFromBreakdown: publicProcedure
|
||||||
|
.input(z.object({
|
||||||
|
initiativeId: z.string().min(1),
|
||||||
|
phases: z.array(z.object({
|
||||||
|
number: z.number(),
|
||||||
|
name: z.string().min(1),
|
||||||
|
description: z.string(),
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const repo = requirePhaseRepository(ctx);
|
||||||
|
const created: Phase[] = [];
|
||||||
|
for (const p of input.phases) {
|
||||||
|
const phase = await repo.create({
|
||||||
|
initiativeId: input.initiativeId,
|
||||||
|
number: p.number,
|
||||||
|
name: p.name,
|
||||||
|
description: p.description,
|
||||||
|
status: 'pending',
|
||||||
|
});
|
||||||
|
created.push(phase);
|
||||||
|
}
|
||||||
|
return created;
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user