Merge SERVICE role into AGENT
Build & Push / Test (client) (push) Successful in 31s
Build & Push / Test (server) (push) Successful in 38s
Build & Push / Build Client (push) Successful in 1m17s
Build & Push / Build Server (push) Successful in 1m18s

Every AGENT now gets an auto-generated API key on creation, shown once
in a modal. AGENTs log in with password and authenticate to the API
with X-Api-Key. pre-push.sql defensively migrates any residual SERVICE
rows to AGENT before Prisma rewrites the enum. Goddard is no longer
baked into the seed — create agents via Admin → Users.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-18 22:44:32 -04:00
parent a9ba74f1af
commit d8785a964d
18 changed files with 73 additions and 130 deletions
+9 -6
View File
@@ -41,12 +41,10 @@ export async function getCurrentUser(id: string) {
}
export async function createUser(data: CreateUserInput) {
const passwordHash = data.password
? await bcrypt.hash(data.password, 12)
: await bcrypt.hash(crypto.randomBytes(32).toString('hex'), 12);
const passwordHash = await bcrypt.hash(data.password, 12);
const apiKey =
data.role === 'SERVICE' ? `sk_${crypto.randomBytes(32).toString('hex')}` : undefined;
data.role === 'AGENT' ? `sk_${crypto.randomBytes(32).toString('hex')}` : undefined;
return prisma.user.create({
data: {
@@ -68,8 +66,13 @@ export async function updateUser(id: string, data: UpdateUserInput) {
if (data.password) update.passwordHash = await bcrypt.hash(data.password, 12);
if (data.role) {
update.role = data.role;
if (data.role === 'SERVICE' && !update.apiKey) {
update.apiKey = `sk_${crypto.randomBytes(32).toString('hex')}`;
if (data.role === 'AGENT') {
const existing = await prisma.user.findUnique({ where: { id }, select: { apiKey: true } });
if (!existing?.apiKey) {
update.apiKey = `sk_${crypto.randomBytes(32).toString('hex')}`;
}
} else {
update.apiKey = null;
}
}
if (data.regenerateApiKey) {