Conduct

Backend Integration Guide

Framework Examples

Conduct v0.2 backend SDK works with any HTTP framework. Choose your framework below:


Express Integration

Install Dependencies

npm install conduct-backend @superfunctions/db @superfunctions/http-express
npm install drizzle-orm postgres

Setup Database

// src/db.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
 
const connectionString = process.env.DATABASE_URL || 'postgresql://localhost:5432/myapp';
const client = postgres(connectionString);
export const db = drizzle(client);

Initialize Conduct

// src/conduct.ts
import { createConductBackend } from 'conduct-backend';
import { drizzleAdapter } from '@superfunctions/db/adapters';
import { db } from './db.js';
 
// Create database adapter
const adapter = drizzleAdapter({
  db,
  dialect: 'postgres',
});
 
// Create Conduct backend
export const conduct = createConductBackend({
  database: adapter,
  namespace: 'conduct', // Optional: prefix for table names
  auth: {
    apiKeys: async (key) => {
      // Your API key validation logic
      // Example: check against database
      const validKey = await db
        .select()
        .from(apiKeys)
        .where(eq(apiKeys.key, key))
        .limit(1);
      
      if (!validKey.length) return null;
      
      return {
        apiKeyId: validKey[0].id,
        projectIds: validKey[0].projectIds,
      };
    },
  },
});

Mount Router

// src/server.ts
import express from 'express';
import { toExpressRouter } from '@superfunctions/http-express';
import { conduct } from './conduct.js';
 
const app = express();
 
// Parse JSON bodies
app.use(express.json());
 
// Mount Conduct router
app.use('/api/conduct', toExpressRouter(conduct.router));
 
// Your other routes
app.get('/', (req, res) => {
  res.send('My app with Conduct!');
});
 
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Run Migrations

# Generate migrations
npx drizzle-kit generate
 
# Apply migrations
npx drizzle-kit push

Test It

# Start server
npm run dev
 
# Test health endpoint
curl http://localhost:3000/api/conduct/health
 
# Create a spec
curl -X POST http://localhost:3000/api/conduct/specs \
  -H "Authorization: Bearer your_api_key" \
  -H "X-Project-ID: proj_123" \
  -H "Content-Type: application/json" \
  -d '{
    "mdJson": {...},
    "intent": "Test feature",
    "effort": "simple",
    "requirements": []
  }'

Hono Integration

Install Dependencies

npm install conduct-backend @superfunctions/db @superfunctions/http-hono
npm install drizzle-orm postgres
npm install hono

Setup

// src/index.ts
import { Hono } from 'hono';
import { toHonoHandler } from '@superfunctions/http-hono';
import { createConductBackend } from 'conduct-backend';
import { drizzleAdapter } from '@superfunctions/db/adapters';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
 
// Database setup
const client = postgres(process.env.DATABASE_URL!);
const db = drizzle(client);
const adapter = drizzleAdapter({ db, dialect: 'postgres' });
 
// Create Conduct backend
const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key) => {
      // Your validation logic
      if (key === process.env.ADMIN_KEY) {
        return {
          apiKeyId: 'admin',
          projectIds: ['*'], // All projects
        };
      }
      return null;
    },
  },
});
 
// Create Hono app
const app = new Hono();
 
// Mount Conduct routes
app.route('/api/conduct', toHonoHandler(conduct.router));
 
// Your routes
app.get('/', (c) => c.text('My Hono app with Conduct!'));
 
export default app;

For Cloudflare Workers

// worker.ts
import { Hono } from 'hono';
import { toHonoHandler } from '@superfunctions/http-hono';
import { createConductBackend } from 'conduct-backend';
import { d1Adapter } from '@superfunctions/db/adapters';
 
const app = new Hono<{ Bindings: { DB: D1Database } }>();
 
app.route('/api/conduct', toHonoHandler((c) => {
  const adapter = d1Adapter({ db: c.env.DB });
  const conduct = createConductBackend({
    database: adapter,
    auth: {
      apiKeys: async (key) => {
        // Validate against D1
        return { apiKeyId: 'user', projectIds: ['proj_123'] };
      },
    },
  });
  return conduct.router;
}));
 
export default app;

Next.js Integration

Install Dependencies

npm install conduct-backend @superfunctions/db @superfunctions/http-next
npm install drizzle-orm postgres

Setup Database

// lib/db.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
 
const connectionString = process.env.DATABASE_URL!;
const client = postgres(connectionString);
export const db = drizzle(client);

Create Conduct Instance

// lib/conduct.ts
import { createConductBackend } from 'conduct-backend';
import { drizzleAdapter } from '@superfunctions/db/adapters';
import { db } from './db';
 
const adapter = drizzleAdapter({ db, dialect: 'postgres' });
 
export const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key) => {
      // Your validation
      return {
        apiKeyId: 'user',
        projectIds: ['proj_123'],
      };
    },
  },
});
// app/api/conduct/[...path]/route.ts
import { toNextHandlers } from '@superfunctions/http-next';
import { conduct } from '@/lib/conduct';
 
// Export HTTP method handlers
export const { GET, POST, PUT, DELETE, PATCH } = toNextHandlers(conduct.router);

Pages Router

// pages/api/conduct/[...path].ts
import { toNextApiHandler } from '@superfunctions/http-next';
import { conduct } from '@/lib/conduct';
 
export default toNextApiHandler(conduct.router);

Test It

# Start Next.js dev server
npm run dev
 
# Test endpoint
curl http://localhost:3000/api/conduct/health

Fastify Integration

Install Dependencies

npm install conduct-backend @superfunctions/db @superfunctions/http-fastify
npm install drizzle-orm postgres fastify

Setup

// server.ts
import Fastify from 'fastify';
import { toFastifyPlugin } from '@superfunctions/http-fastify';
import { createConductBackend } from 'conduct-backend';
import { drizzleAdapter } from '@superfunctions/db/adapters';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
 
const fastify = Fastify({ logger: true });
 
// Database setup
const client = postgres(process.env.DATABASE_URL!);
const db = drizzle(client);
const adapter = drizzleAdapter({ db, dialect: 'postgres' });
 
// Create Conduct backend
const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key) => {
      return { apiKeyId: 'user', projectIds: ['proj_123'] };
    },
  },
});
 
// Register Conduct plugin
fastify.register(toFastifyPlugin(conduct.router), {
  prefix: '/api/conduct',
});
 
// Start server
fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
});

Database Adapter Examples

Drizzle Adapter

import { drizzleAdapter } from '@superfunctions/db/adapters';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
 
const client = postgres(process.env.DATABASE_URL!);
const db = drizzle(client);
 
const adapter = drizzleAdapter({
  db,
  dialect: 'postgres', // or 'mysql', 'sqlite'
});

Prisma Adapter

import { prismaAdapter } from '@superfunctions/db/adapters';
import { PrismaClient } from '@prisma/client';
 
const prisma = new PrismaClient();
 
const adapter = prismaAdapter({
  prisma,
  // Map Conduct models to your Prisma models
  modelMap: {
    projects: 'project',
    specs: 'specification',
    requirements: 'requirement',
    tasks: 'task',
    tasksRequirements: 'taskRequirement',
    runs: 'run',
  },
});

Kysely Adapter

import { kyselyAdapter } from '@superfunctions/db/adapters';
import { Kysely, PostgresDialect } from 'kysely';
import { Pool } from 'pg';
 
const db = new Kysely({
  dialect: new PostgresDialect({
    pool: new Pool({
      connectionString: process.env.DATABASE_URL,
    }),
  }),
});
 
const adapter = kyselyAdapter({
  db,
  dialect: 'postgres',
});

Memory Adapter (Testing)

import { memoryAdapter } from '@superfunctions/db/adapters';
 
const adapter = memoryAdapter({
  namespace: { enabled: true },
});

Authentication Setup

Simple API Key Validation

const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key) => {
      // Hardcoded for development
      if (key === process.env.ADMIN_KEY) {
        return {
          apiKeyId: 'admin',
          projectIds: ['proj_123'],
        };
      }
      return null;
    },
  },
});

Database-Based Validation

import { eq } from 'drizzle-orm';
import { apiKeys } from './schema';
 
const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key) => {
      const result = await db
        .select({
          id: apiKeys.id,
          projectIds: apiKeys.projectIds,
        })
        .from(apiKeys)
        .where(eq(apiKeys.key, key))
        .limit(1);
      
      if (!result.length) return null;
      
      return {
        apiKeyId: result[0].id,
        projectIds: result[0].projectIds,
      };
    },
  },
});

Integration with Auth.js / NextAuth

import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
 
const conduct = createConductBackend({
  database: adapter,
  auth: {
    apiKeys: async (key, req) => {
      // Support both API keys and session auth
      if (key) {
        // Validate API key
        return validateApiKey(key);
      }
      
      // Check for session
      const session = await getServerSession(authOptions);
      if (session?.user) {
        return {
          apiKeyId: session.user.id,
          projectIds: session.user.projectIds,
        };
      }
      
      return null;
    },
  },
});

Environment Variables

Create .env file:

# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
 
# Conduct
CONDUCT_NAMESPACE=conduct
ADMIN_API_KEY=ck_admin_xxx
 
# Your app
PORT=3000
NODE_ENV=development

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  }
}

Running Migrations

With Drizzle

# Generate migrations
npx drizzle-kit generate
 
# Apply migrations
npx drizzle-kit push
 
# Or use migration files
npx drizzle-kit migrate

With @superfunctions/cli

# Install CLI
npm install -g @superfunctions/cli
 
# Generate migrations
superfunctions generate
 
# Apply with your ORM
npx drizzle-kit push

Production Deployment

Environment Setup

# Production database
DATABASE_URL=postgresql://prod-user:pass@prod-host:5432/prod-db
 
# Secure API keys
ADMIN_API_KEY=ck_prod_xxx
 
# Logging
LOG_LEVEL=warn

Docker Example

FROM node:20-alpine
 
WORKDIR /app
 
COPY package*.json ./
RUN npm ci --production
 
COPY . .
RUN npm run build
 
EXPOSE 3000
 
CMD ["node", "dist/server.js"]

Deployment Checklist

  • Set production DATABASE_URL
  • Generate secure API keys
  • Run migrations
  • Test all endpoints
  • Configure CORS properly
  • Set up monitoring
  • Configure rate limiting
  • Enable HTTPS

Troubleshooting

"Module not found" Errors

Ensure all packages are installed:

npm install conduct-backend @superfunctions/db @superfunctions/http
npm install @superfunctions/http-express  # Your framework
npm install drizzle-orm postgres          # Your ORM

Database Connection Issues

Check connection string:

console.log('DATABASE_URL:', process.env.DATABASE_URL);

Test connection:

psql $DATABASE_URL -c "SELECT 1"

Type Errors

Ensure TypeScript is configured:

npm install -D @types/node typescript
npx tsc --init

401 Unauthorized

Check API key validation:

auth: {
  apiKeys: async (key) => {
    console.log('Validating key:', key);
    // Your validation
  }
}

Next Steps