feat(#94): implement spoke configuration UI
Implements the final piece of M7-Federation - the spoke configuration UI that allows administrators to configure their local instance's federation capabilities and settings. Backend Changes: - Add UpdateInstanceDto with validation for name, capabilities, and metadata - Implement FederationService.updateInstanceConfiguration() method - Add PATCH /api/v1/federation/instance endpoint to FederationController - Add audit logging for configuration updates - Add tests for updateInstanceConfiguration (5 new tests, all passing) Frontend Changes: - Create SpokeConfigurationForm component with PDA-friendly design - Create /federation/settings page with configuration management - Add regenerate keypair functionality with confirmation dialog - Extend federation API client with updateInstanceConfiguration and regenerateInstanceKeys - Add comprehensive tests (10 tests, all passing) Design Decisions: - Admin-only access via AdminGuard - Never expose private key in API responses (security) - PDA-friendly language throughout (no demanding terms) - Clear visual hierarchy with read-only and editable fields - Truncated public key with copy button for usability - Confirmation dialog for destructive key regeneration All tests passing: - Backend: 13/13 federation service tests passing - Frontend: 10/10 SpokeConfigurationForm tests passing - TypeScript compilation: passing - Linting: passing - PDA-friendliness: verified This completes M7-Federation. All federation features are now implemented. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -104,6 +104,46 @@ export class FederationService {
|
||||
return publicIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update instance configuration
|
||||
* Allows updating name, capabilities, and metadata
|
||||
* Returns public identity only (no private key exposure)
|
||||
*/
|
||||
async updateInstanceConfiguration(updates: {
|
||||
name?: string;
|
||||
capabilities?: FederationCapabilities;
|
||||
metadata?: Record<string, unknown>;
|
||||
}): Promise<PublicInstanceIdentity> {
|
||||
const instance = await this.getInstanceIdentity();
|
||||
|
||||
// Build update data object
|
||||
const data: Prisma.InstanceUpdateInput = {};
|
||||
|
||||
if (updates.name !== undefined) {
|
||||
data.name = updates.name;
|
||||
}
|
||||
|
||||
if (updates.capabilities !== undefined) {
|
||||
data.capabilities = updates.capabilities as Prisma.JsonObject;
|
||||
}
|
||||
|
||||
if (updates.metadata !== undefined) {
|
||||
data.metadata = updates.metadata as Prisma.JsonObject;
|
||||
}
|
||||
|
||||
const updatedInstance = await this.prisma.instance.update({
|
||||
where: { id: instance.id },
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.log(`Instance configuration updated: ${JSON.stringify(updates)}`);
|
||||
|
||||
// Return public identity only (security fix)
|
||||
const identity = this.mapToInstanceIdentity(updatedInstance);
|
||||
const { privateKey: _privateKey, ...publicIdentity } = identity;
|
||||
return publicIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance identity
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user