| name | develop |
| description | Expert Hapi.js/TypeScript middleware developer for MMO FES Orchestration. Use when: implementing features, fixing bugs, refactoring code, researching codebase, planning solutions. Covers dual-auth, dual-storage, ownership validation, GOV.UK Notify, PDF generation. |
| license | OGL-UK-3.0 |
| metadata | {"author":"mmo-fes","version":"1.0"} |
Orchestration — Developer Skill
Expert software engineer for the MMO FES Orchestration service. Reads the codebase, researches, plans, reasons, writes production-ready middleware code following project conventions.
When to Use
- Implementing new API endpoints or middleware
- Working with authentication (JWT/Basic dual-auth)
- Adding document ownership validation
- Integrating with Redis sessions or MongoDB persistence
- Working with GOV.UK Notify, PDF generation, or Event Hubs
- Any production code writing task
Workflow
Before Making Changes
- Search codebase for similar route and controller patterns
- Check
defineAuthStrategies() for authentication requirements
- Review Redis key patterns and MongoDB schema for the feature area
- Understand the
acceptsHtml() response handling pattern
During Implementation
- Follow all mandatory rules from the auto-loaded instruction files (
nodejs-hapi.instructions.md, typescript.instructions.md)
- Always validate document ownership with
withDocumentLegitimatelyOwned()
- Support both HTML and JSON responses via
acceptsHtml() checks
After Implementation
- Run build:
npm run build
- Run lint:
npm run lint
- Verify no TypeScript errors in problems panel
- Invoke the
/unit-tests skill to write or update tests
- Review git diff to ensure no accidental changes
Project Conventions
Dual Authentication
{
method: 'GET',
path: '/api/v1/documents/{documentNumber}',
options: {
auth: defineAuthStrategies(),
validate: {
params: Joi.object({
documentNumber: Joi.string().required().uppercase()
})
}
},
handler: async (request, h) => { }
}
Document Ownership Validation
const document = await withDocumentLegitimatelyOwned(request, documentNumber);
if (!document) {
return acceptsHtml(request.headers)
? h.redirect('/forbidden')
: h.response({ error: 'Forbidden' }).code(403);
}
Dual Storage (Redis + MongoDB)
const sessionKey = `${userId}:${documentNumber}:catches`;
await redis.set(sessionKey, JSON.stringify(catchData));
await redis.get(sessionKey);
const doc = await DocumentModel.findOne({ documentNumber }).lean().exec();
User Identity from Request
const userId = request.app.claims.sub;
const contactId = request.app.claims.contactId;
const fesApi = request.app.claims.fesApi;
Response Handling (HTML vs JSON)
if (acceptsHtml(request.headers)) {
return h.redirect(buildRedirectUrlWithError(details, '/error'));
}
return h.response(details).code(400);
GOV.UK Notify Integration
await notifyClient.sendEmail(templateId, emailAddress, {
personalisation: {
documentNumber,
exporterName,
reference: documentNumber,
}
});
Anti-Patterns
Mandatory rules in the instruction files also apply. The items below are additional anti-patterns specific to this skill:
- Skipping
withDocumentLegitimatelyOwned() ownership validation
- Using flat Redis keys instead of colon-delimited convention
- Not handling both HTML and JSON response formats
- Forgetting to
.uppercase() document numbers in routes