feat(directory): Add agent directory schema fields

Add url_key, description, specialties, and chain_of_command fields to
agents table for enriched directory API. Migration is backward
compatible - existing agents get url_key populated from name.

- Migration: drizzle/0002_add_agent_directory_fields.sql
- Schema update: src/db/schema.ts with new fields and constraints
- url_key: unique, URL-safe identifier for profile URLs
- description: 1-2048 chars agent bio
- specialties: jsonb array of skill tags
- chain_of_command: jsonb for manager/reports hierarchy

Related to BARAAA-91

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Paperclip FoundingEngineer 2026-05-02 22:15:58 +00:00
parent 2044e85f54
commit c1b0391e3f
2 changed files with 36 additions and 0 deletions

View file

@ -0,0 +1,21 @@
-- Migration: Add directory fields to agents table
-- Adds: urlKey, description, specialties, chainOfCommand for agent directory feature
ALTER TABLE agents ADD COLUMN url_key text;
ALTER TABLE agents ADD COLUMN description text;
ALTER TABLE agents ADD COLUMN specialties jsonb DEFAULT '[]'::jsonb;
ALTER TABLE agents ADD COLUMN chain_of_command jsonb;
-- url_key should match name pattern and be unique (nullable for backward compat)
ALTER TABLE agents ADD CONSTRAINT agents_url_key_check
CHECK (url_key IS NULL OR url_key ~ '^[a-z0-9][a-z0-9-]{0,63}$');
-- Create unique index on url_key (partial index to allow NULLs)
CREATE UNIQUE INDEX agents_url_key_idx ON agents(url_key) WHERE url_key IS NOT NULL;
-- Description max length
ALTER TABLE agents ADD CONSTRAINT agents_description_check
CHECK (description IS NULL OR length(description) BETWEEN 1 AND 2048);
-- Update existing agents to use name as url_key
UPDATE agents SET url_key = name WHERE url_key IS NULL;

View file

@ -40,6 +40,10 @@ export const agents = pgTable(
name: text('name').notNull().unique(),
displayName: text('display_name').notNull(),
role: text('role').notNull(),
urlKey: text('url_key'),
description: text('description'),
specialties: jsonb('specialties').default(sql`'[]'::jsonb`),
chainOfCommand: jsonb('chain_of_command'),
createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
},
@ -50,7 +54,18 @@ export const agents = pgTable(
sql`length(${table.displayName}) BETWEEN 1 AND 128`,
),
roleCheck: check('agents_role_check', sql`${table.role} IN ('admin', 'agent')`),
urlKeyCheck: check(
'agents_url_key_check',
sql`${table.urlKey} IS NULL OR ${table.urlKey} ~ '^[a-z0-9][a-z0-9-]{0,63}$'`,
),
descriptionCheck: check(
'agents_description_check',
sql`${table.description} IS NULL OR length(${table.description}) BETWEEN 1 AND 2048`,
),
roleIdx: index('agents_role_idx').on(table.role),
urlKeyIdx: index('agents_url_key_idx')
.on(table.urlKey)
.where(sql`${table.urlKey} IS NOT NULL`),
}),
);