Installation

This guide covers local development setup, database configuration, and production deployment to Vercel with an optional Azure Functions API proxy.

Local development

1. Clone and install

git clone https://github.com/JuanNephrota/UrNammu-community.git
cd UrNammu-community
npm install

Node.js 22 or later is required (the app declares engines.node >= 22).

2. Start PostgreSQL

On macOS with Homebrew:

brew install postgresql@16
brew services start postgresql@16
createdb urnammu

3. Configure environment

cp .env.example .env

Set at minimum:

DATABASE_URL=postgresql://localhost:5432/urnammu
NEXTAUTH_SECRET=your-random-secret
NEXTAUTH_URL=http://localhost:3000
SETTINGS_ENCRYPTION_KEY=$(openssl rand -base64 32)   # encrypts API keys stored in Settings
ENABLE_DEV_LOGIN=true

4. Set up the database

npx prisma migrate dev    # Apply all migrations (also seeds the framework control catalog and built-in rules)
npm run db:seed            # Load demo data

5. Start the dev server

npm run dev

Open http://localhost:3000 and sign in with the dev login using admin@example.com.

Production deployment (Vercel)

1. Connect your repo

Link your GitHub repository to Vercel. The default build settings work out of the box. The ai-proxy/ directory is excluded from the Next.js build via tsconfig.json.

2. Set environment variables

In Vercel project settings, configure:

DATABASE_URL=postgresql://...         # Any managed Postgres
NEXTAUTH_SECRET=your-production-secret
NEXTAUTH_URL=https://your-app.vercel.app
SETTINGS_ENCRYPTION_KEY=...            # Long random secret; rotating it invalidates stored credentials
GOOGLE_CLIENT_ID=...                   # Google OAuth (or MICROSOFT_* for Entra ID)
GOOGLE_CLIENT_SECRET=...
CRON_SECRET=...                        # Protects every /api/cron/* route
PROMPT_HASH_SALT=...                   # Must match the Azure proxy; falls back to NEXTAUTH_SECRET
ENABLE_DEV_LOGIN=false                 # Must be false in production

3. Migrate, then deploy

Apply migrations before the new build goes live. Merging to a Vercel-connected branch deploys the app but does not run migrations.

npx prisma migrate deploy
vercel --prod --yes

4. Scheduled jobs

vercel.json ships one cron entry per background job — one per telemetry provider (/api/cron/provider-sync/<provider>), one per shadow AI source (/api/cron/discovery-scan/<source>), one per directory source (/api/cron/directory-sync/<source>), plus governance-automation, key-usage-rules, run-report-schedules, proxy-health, sensitive-scan, provider-security-scan, and the three prune jobs. They are staggered so the hourly ones do not all fire at minute zero, and each one checks its own enable flag and interval before doing work.

Vercel's Hobby tier caps both cron frequency and the number of entries, well below what ships here. Either use Pro, or drive the routes from any external scheduler:

curl -H "Authorization: Bearer $CRON_SECRET" \
  https://your-app.vercel.app/api/cron/provider-sync/anthropic

The response reports whether the job was due and, if not, why and when it next will be. Skipping the prune jobs is the one omission that degrades over time rather than immediately.

API proxy (Azure Functions)

The API proxy sits in front of Claude, OpenAI, Azure OpenAI, Gemini, and Amazon Bedrock API calls, logs usage to PostgreSQL, enforces policy-as-code rules and per-agent MCP allowlists, runs dangerous-prompt and inline DLP detection, and supports streaming (SSE) for long-running requests.

Setup

cd ai-proxy
npm install
cp .env.example .env   # Configure DATABASE_URL and PROXY_SECRET

Set PROMPT_HASH_SALT to the same value the app uses, otherwise the salted prompt hashes written by the proxy will not line up with the ones from Claude Code and Cursor telemetry and dangerous-prompt alerts will not fold across surfaces. The proxy reads the prompt_hash_salt setting from the shared database first, then this variable, then NEXTAUTH_SECRET. Azure OpenAI additionally needs AZURE_OPENAI_ENDPOINT and the AZURE_OPENAI_DEPLOYMENTS deployment→model map (or their azure_openai_endpoint / azure_openai_deployments settings, which take precedence) before requests are accepted.

Deploy to Azure

func azure functionapp publish your-function-app --build remote

Deploy order for an upgrade is migrations, then the app, then the proxy. The proxy has a 10-minute function timeout configured for long-running streaming requests. A Vercel-based fallback proxy also exists at /api/proxy/.

Pointing clients at the proxy

Every route is path-based, so the SDK appends its own paths — set the base URL and leave everything else alone. The same paths exist on the Vercel fallback under /api/proxy/.... Clients authenticate with x-proxy-key, and the provider credential header is forwarded verbatim.

  • /api/proxy/anthropic — Claude Messages API, streaming and non-streaming (x-api-key)
  • /api/proxy/openai/v1 — Every OpenAI /v1 path. Chat Completions, Completions, Responses, and Embeddings are logged with tokens and cost; other endpoints pass through as a zero-token row with the endpoint in metadata
  • /api/proxy/azure-openai — The same endpoints on your Azure resource (api-key or Entra bearer). Requests name a deployment, which prices through the deployment→model map
  • /api/proxy/gemini — generateContent and streamGenerateContent (x-goog-api-key)
  • /api/proxy/bedrock — invoke and invoke-with-response-stream for Anthropic models. Log-only: the proxy forwards the client's own Bedrock API key or SigV4 signature and never injects AWS credentials

Send x-ai-system-id (and x-agent-id for agents) on each call so usage, policy decisions, and MCP tool activity are attributed to the right registry entry; x-user-email and x-department attribute per person and cost center. Policy-as-code, MCP allowlists, prompt-risk detection, and response DLP apply identically on all five upstreams. The headers, base URLs, and ready-to-paste snippets are documented in Settings → Proxy Setup.

Upgrading from a release before the proxy-coverage change means redeploying the function app and re-pointing OpenAI clients at /api/proxy/openai/v1: the single chat-completions route was replaced by the path-based one, and the Azure OpenAI, Gemini, and Bedrock routes are new.

Database management

# Create a new migration after schema changes
npx prisma migrate dev --name describe-your-change

# Regenerate the Prisma client
npx prisma generate

# Reset database (destructive!)
npm run db:reset