## Documentation (20 files) - DAARION Ontology Core v1 (Agent → MicroDAO → Node → District) - User Onboarding & Identity Layer (DAIS) - Data Model UPDATE, Event Catalog, Governance & Permissions - Rooms Layer, City/MicroDAO/Agents/Nodes Interface Architecture - Helper files: ontology-summary, lifecycles, event-schemas ## Database Migration (027) - DAIS tables: dais_identities, dais_emails, dais_wallets, dais_keys - agent_assignments table for Assignment Layer - rooms table for Rooms Layer - event_outbox for NATS event delivery - New enums: agent_role, microdao_type, node_kind, node_status, etc. - Updated agents, microdaos, nodes tables with ontology fields ## Backend - DAIS service & routes (/api/v1/dais/*) - Assignment service & routes (/api/v1/assignments/*) - Domain types for DAIS and Ontology ## Frontend - Ontology types (Agent, MicroDAO, Node, DAIS, Assignments) - API clients for DAIS and Assignments - UI components: DaisProfileCard, AssignmentsPanel, OntologyBadge Non-breaking update - all existing functionality preserved.
279 lines
7.3 KiB
TypeScript
279 lines
7.3 KiB
TypeScript
/**
|
|
* DAIS Service - DAARION Autonomous Identity System
|
|
* Based on: docs/foundation/DAARION_Identity_And_Access_Draft_v1.md
|
|
*/
|
|
|
|
import { db } from '../../infra/db/client';
|
|
import { logger } from '../../infra/logger/logger';
|
|
import type {
|
|
DaisIdentity,
|
|
DaisProfile,
|
|
DaisEmail,
|
|
DaisWallet,
|
|
CreateDaisRequest,
|
|
DaisCreationResult,
|
|
DaisTrustLevel,
|
|
} from '../../domain/dais/types';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
export class DaisService {
|
|
/**
|
|
* Create a new DAIS identity
|
|
*/
|
|
async createIdentity(request: CreateDaisRequest): Promise<DaisCreationResult> {
|
|
const id = `dais-${uuidv4()}`;
|
|
const did = `did:daarion:${uuidv4()}`;
|
|
|
|
try {
|
|
// Create DAIS identity
|
|
const identity = await db.query<DaisIdentity>(
|
|
`INSERT INTO dais_identities (id, did, default_email, default_wallet, trust_level)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING *`,
|
|
[id, did, request.email || null, request.walletAddress || null, 'agent']
|
|
);
|
|
|
|
// Add email if provided
|
|
if (request.email) {
|
|
await db.query(
|
|
`INSERT INTO dais_emails (dais_id, email, verified)
|
|
VALUES ($1, $2, false)`,
|
|
[id, request.email]
|
|
);
|
|
}
|
|
|
|
// Add wallet if provided
|
|
if (request.walletAddress) {
|
|
await db.query(
|
|
`INSERT INTO dais_wallets (dais_id, wallet_address, network, verified)
|
|
VALUES ($1, $2, $3, false)`,
|
|
[id, request.walletAddress, request.network || 'evm']
|
|
);
|
|
}
|
|
|
|
// Create agent linked to DAIS
|
|
const agentId = `agent-${uuidv4()}`;
|
|
const matrixHandle = `@${agentId}:matrix.daarion.city`;
|
|
|
|
await db.query(
|
|
`INSERT INTO agents (id, name, kind, dais_identity_id, agent_role, home_microdao_id)
|
|
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
[agentId, 'New Agent', 'personal', id, 'regular', 'daarion']
|
|
);
|
|
|
|
// Update DAIS with matrix handle
|
|
await db.query(
|
|
`UPDATE dais_identities SET matrix_handle = $1 WHERE id = $2`,
|
|
[matrixHandle, id]
|
|
);
|
|
|
|
logger.info(`Created DAIS identity: ${id}, agent: ${agentId}`);
|
|
|
|
return {
|
|
identity: identity.rows[0],
|
|
agentId,
|
|
matrixHandle,
|
|
};
|
|
} catch (error) {
|
|
logger.error('Failed to create DAIS identity', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get DAIS profile with all linked identities
|
|
*/
|
|
async getProfile(daisId: string): Promise<DaisProfile | null> {
|
|
try {
|
|
const identity = await db.query<DaisIdentity>(
|
|
`SELECT * FROM dais_identities WHERE id = $1`,
|
|
[daisId]
|
|
);
|
|
|
|
if (identity.rows.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const emails = await db.query<DaisEmail>(
|
|
`SELECT * FROM dais_emails WHERE dais_id = $1`,
|
|
[daisId]
|
|
);
|
|
|
|
const wallets = await db.query<DaisWallet>(
|
|
`SELECT * FROM dais_wallets WHERE dais_id = $1`,
|
|
[daisId]
|
|
);
|
|
|
|
const keys = await db.query(
|
|
`SELECT * FROM dais_keys WHERE dais_id = $1 AND revoked_at IS NULL`,
|
|
[daisId]
|
|
);
|
|
|
|
return {
|
|
identity: identity.rows[0],
|
|
emails: emails.rows,
|
|
wallets: wallets.rows,
|
|
keys: keys.rows,
|
|
};
|
|
} catch (error) {
|
|
logger.error(`Failed to get DAIS profile: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get DAIS by agent ID
|
|
*/
|
|
async getByAgentId(agentId: string): Promise<DaisProfile | null> {
|
|
try {
|
|
const agent = await db.query(
|
|
`SELECT dais_identity_id FROM agents WHERE id = $1`,
|
|
[agentId]
|
|
);
|
|
|
|
if (agent.rows.length === 0 || !agent.rows[0].dais_identity_id) {
|
|
return null;
|
|
}
|
|
|
|
return this.getProfile(agent.rows[0].dais_identity_id);
|
|
} catch (error) {
|
|
logger.error(`Failed to get DAIS by agent: ${agentId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add email to DAIS
|
|
*/
|
|
async addEmail(daisId: string, email: string): Promise<DaisEmail> {
|
|
try {
|
|
const result = await db.query<DaisEmail>(
|
|
`INSERT INTO dais_emails (dais_id, email, verified)
|
|
VALUES ($1, $2, false)
|
|
RETURNING *`,
|
|
[daisId, email]
|
|
);
|
|
|
|
logger.info(`Added email to DAIS ${daisId}: ${email}`);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
logger.error(`Failed to add email to DAIS: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify email
|
|
*/
|
|
async verifyEmail(daisId: string, email: string): Promise<void> {
|
|
try {
|
|
await db.query(
|
|
`UPDATE dais_emails
|
|
SET verified = true, verified_at = now()
|
|
WHERE dais_id = $1 AND email = $2`,
|
|
[daisId, email]
|
|
);
|
|
|
|
// Update trust level if this is first verified email
|
|
await this.updateTrustLevel(daisId);
|
|
|
|
logger.info(`Verified email for DAIS ${daisId}: ${email}`);
|
|
} catch (error) {
|
|
logger.error(`Failed to verify email: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add wallet to DAIS
|
|
*/
|
|
async addWallet(
|
|
daisId: string,
|
|
walletAddress: string,
|
|
network: 'evm' | 'ton' | 'solana' = 'evm'
|
|
): Promise<DaisWallet> {
|
|
try {
|
|
const result = await db.query<DaisWallet>(
|
|
`INSERT INTO dais_wallets (dais_id, wallet_address, network, verified)
|
|
VALUES ($1, $2, $3, false)
|
|
RETURNING *`,
|
|
[daisId, walletAddress, network]
|
|
);
|
|
|
|
logger.info(`Added wallet to DAIS ${daisId}: ${walletAddress}`);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
logger.error(`Failed to add wallet to DAIS: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify wallet (after SIWE signature)
|
|
*/
|
|
async verifyWallet(daisId: string, walletAddress: string): Promise<void> {
|
|
try {
|
|
await db.query(
|
|
`UPDATE dais_wallets
|
|
SET verified = true, verified_at = now()
|
|
WHERE dais_id = $1 AND wallet_address = $2`,
|
|
[daisId, walletAddress]
|
|
);
|
|
|
|
// Update trust level
|
|
await this.updateTrustLevel(daisId);
|
|
|
|
logger.info(`Verified wallet for DAIS ${daisId}: ${walletAddress}`);
|
|
} catch (error) {
|
|
logger.error(`Failed to verify wallet: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update trust level based on verified identities
|
|
*/
|
|
private async updateTrustLevel(daisId: string): Promise<void> {
|
|
const profile = await this.getProfile(daisId);
|
|
if (!profile) return;
|
|
|
|
const hasVerifiedEmail = profile.emails.some(e => e.verified);
|
|
const hasVerifiedWallet = profile.wallets.some(w => w.verified);
|
|
|
|
let newLevel: DaisTrustLevel = 'guest';
|
|
|
|
if (hasVerifiedEmail && hasVerifiedWallet) {
|
|
newLevel = 'verified';
|
|
} else if (hasVerifiedEmail) {
|
|
newLevel = 'agent';
|
|
}
|
|
|
|
await db.query(
|
|
`UPDATE dais_identities SET trust_level = $1, updated_at = now() WHERE id = $2`,
|
|
[newLevel, daisId]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Promote agent to orchestrator (updates DAIS trust level)
|
|
*/
|
|
async promoteToOrchestrator(daisId: string): Promise<void> {
|
|
try {
|
|
await db.query(
|
|
`UPDATE dais_identities
|
|
SET trust_level = 'orchestrator', updated_at = now()
|
|
WHERE id = $1`,
|
|
[daisId]
|
|
);
|
|
|
|
logger.info(`Promoted DAIS to orchestrator: ${daisId}`);
|
|
} catch (error) {
|
|
logger.error(`Failed to promote to orchestrator: ${daisId}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const daisService = new DaisService();
|
|
|