Major Features:
- Multi-project governance with Rule Manager web UI
- Project Manager for organizing governance across projects
- Variable substitution system (${VAR_NAME} in rules)
- Claude.md analyzer for instruction extraction
- Rule quality scoring and optimization
Admin UI Components:
- /admin/rule-manager.html - Full-featured rule management interface
- /admin/project-manager.html - Multi-project administration
- /admin/claude-md-migrator.html - Import rules from Claude.md files
- Dashboard enhancements for governance analytics
Backend Implementation:
- Controllers: projects, rules, variables
- Models: Project, VariableValue, enhanced GovernanceRule
- Routes: /api/projects, /api/rules with full CRUD
- Services: ClaudeMdAnalyzer, RuleOptimizer, VariableSubstitution
- Utilities: mongoose helpers
Documentation:
- User guides for Rule Manager and Projects
- Complete API documentation (PROJECTS_API, RULES_API)
- Phase 3 planning and architecture diagrams
- Test results and error analysis
- Coding best practices summary
Testing & Scripts:
- Integration tests for projects API
- Unit tests for variable substitution
- Database migration scripts
- Seed data generation
- Test token generator
Key Capabilities:
✅ UNIVERSAL scope rules apply across all projects
✅ PROJECT_SPECIFIC rules override for individual projects
✅ Variable substitution per-project (e.g., ${DB_PORT} → 27017)
✅ Real-time validation and quality scoring
✅ Advanced filtering and search
✅ Import from existing Claude.md files
Technical Details:
- MongoDB-backed governance persistence
- RESTful API with Express
- JWT authentication for admin endpoints
- CSP-compliant frontend (no inline handlers)
- Responsive Tailwind UI
This implements Phase 3 architecture as documented in planning docs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
17 KiB
Projects & Variables API Documentation
Version: 1.0
Base URL: /api/admin
Authentication: Required (Bearer token)
Table of Contents
- Overview
- Authentication
- Projects API
- Variables API
- Variable Substitution
- Error Handling
- Usage Examples
Overview
The Projects & Variables API provides multi-project governance capabilities, allowing administrators to:
- Manage multiple projects with project-specific configurations
- Define and manage variable values per project
- Substitute variables in governance rules with project-specific values
- Support context-aware rule rendering
Key Concepts:
- Project: A codebase or application with its own configuration (e.g.,
tractatus,family-history) - Variable: A placeholder in governance rules (e.g.,
${DB_NAME},${API_PORT}) - Variable Value: The actual value of a variable for a specific project
- Variable Substitution: Replacing
${VAR_NAME}in rule text with actual values
Authentication
All endpoints require admin authentication.
Headers:
Authorization: Bearer <admin_token>
Content-Type: application/json
Error Response (401):
{
"error": "Unauthorized",
"message": "Invalid or missing authentication token"
}
Projects API
GET /api/admin/projects
Get all projects with optional filtering.
Query Parameters:
active(string, optional): Filter by active status ("true","false", or omit for all)database(string, optional): Filter by database type (e.g.,"MongoDB","PostgreSQL")
Response (200):
{
"success": true,
"projects": [
{
"_id": "507f1f77bcf86cd799439011",
"id": "tractatus",
"name": "Tractatus AI Safety Framework",
"description": "The Tractatus website...",
"techStack": {
"framework": "Express.js",
"database": "MongoDB",
"frontend": "Vanilla JavaScript"
},
"repositoryUrl": "https://github.com/example/tractatus",
"metadata": {
"environment": "production"
},
"active": true,
"variableCount": 7,
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T10:00:00.000Z"
}
],
"total": 1
}
GET /api/admin/projects/:id
Get a single project by ID.
URL Parameters:
id(string, required): Project ID (e.g.,tractatus)
Response (200):
{
"success": true,
"project": {
"_id": "507f1f77bcf86cd799439011",
"id": "tractatus",
"name": "Tractatus AI Safety Framework",
"description": "...",
"techStack": { ... },
"repositoryUrl": "...",
"metadata": { ... },
"active": true,
"variableCount": 7,
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T10:00:00.000Z"
}
}
Error Response (404):
{
"success": false,
"message": "Project not found"
}
POST /api/admin/projects
Create a new project.
Request Body:
{
"id": "new-project",
"name": "New Project Name",
"description": "Optional description",
"techStack": {
"framework": "Express.js",
"database": "MongoDB"
},
"repositoryUrl": "https://github.com/...",
"metadata": {
"environment": "development"
},
"active": true
}
Required Fields:
id(string): Unique project identifier (kebab-case recommended)name(string): Project display name
Response (201):
{
"success": true,
"project": { ... },
"message": "Project created successfully"
}
Error Response (400):
{
"success": false,
"message": "Project with this ID already exists"
}
PUT /api/admin/projects/:id
Update an existing project.
URL Parameters:
id(string, required): Project ID
Request Body (all fields optional):
{
"name": "Updated Name",
"description": "Updated description",
"techStack": {
"framework": "Next.js",
"database": "PostgreSQL"
},
"repositoryUrl": "https://github.com/...",
"metadata": {
"version": "2.0"
},
"active": true
}
Response (200):
{
"success": true,
"project": { ... },
"message": "Project updated successfully"
}
DELETE /api/admin/projects/:id
Delete a project (soft delete by default).
URL Parameters:
id(string, required): Project ID
Query Parameters:
hard(string, optional): Set to"true"for permanent deletion
Behavior:
- Soft Delete (default): Sets
active: falseon project and all its variables - Hard Delete: Permanently removes project and all associated variables from database
Response (200):
{
"success": true,
"message": "Project deleted successfully (soft delete)",
"deletedCount": 1,
"variablesDeactivated": 7
}
Hard Delete Response:
{
"success": true,
"message": "Project permanently deleted",
"deletedCount": 1,
"variablesDeleted": 7
}
GET /api/admin/projects/stats
Get project statistics.
Response (200):
{
"success": true,
"stats": {
"total": 4,
"active": 3,
"inactive": 1,
"byDatabase": {
"MongoDB": 2,
"PostgreSQL": 1,
"MySQL": 1
},
"totalVariables": 26
}
}
Variables API
GET /api/admin/projects/:projectId/variables
Get all variables for a specific project.
URL Parameters:
projectId(string, required): Project ID
Response (200):
{
"success": true,
"variables": [
{
"_id": "507f1f77bcf86cd799439012",
"projectId": "tractatus",
"variableName": "DB_NAME",
"value": "tractatus_prod",
"description": "Production database name",
"category": "database",
"dataType": "string",
"active": true,
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T10:00:00.000Z"
}
],
"total": 7
}
GET /api/admin/projects/variables/global
Get all variables across all projects.
Query Parameters:
active(string, optional): Filter by active status
Response (200):
{
"success": true,
"variables": [
{
"_id": "...",
"projectId": "tractatus",
"variableName": "DB_NAME",
"value": "tractatus_prod",
"projectName": "Tractatus AI Safety Framework",
...
}
],
"total": 26
}
POST /api/admin/projects/:projectId/variables
Create or update a variable (upsert).
URL Parameters:
projectId(string, required): Project ID
Request Body:
{
"variableName": "DB_NAME",
"value": "tractatus_prod",
"description": "Production database name",
"category": "database",
"dataType": "string"
}
Required Fields:
variableName(string): Variable name in UPPER_SNAKE_CASE (e.g.,DB_NAME,API_KEY_2)value(string): Variable value
Variable Name Validation:
- Must match pattern:
/^[A-Z][A-Z0-9_]*$/ - Must start with uppercase letter
- Can only contain uppercase letters, numbers, and underscores
Categories:
database- Database configurationconfig- Application configurationurl- URLs and endpointspath- File paths and directoriessecurity- Security credentials (use with caution)feature_flag- Feature flagsother- Miscellaneous
Data Types:
string(default)numberbooleanjson
Response (201 for create, 200 for update):
{
"success": true,
"variable": { ... },
"message": "Variable created successfully",
"isNew": true
}
Error Response (400):
{
"success": false,
"error": "Invalid variable name",
"message": "Variable name must be UPPER_SNAKE_CASE (e.g., DB_NAME, API_KEY_2)"
}
PUT /api/admin/projects/:projectId/variables/:variableName
Update an existing variable.
URL Parameters:
projectId(string, required): Project IDvariableName(string, required): Variable name
Request Body (all fields optional):
{
"value": "new_value",
"description": "Updated description",
"category": "config",
"dataType": "string"
}
Response (200):
{
"success": true,
"variable": { ... },
"message": "Variable updated successfully"
}
DELETE /api/admin/projects/:projectId/variables/:variableName
Delete a variable (soft delete by default).
URL Parameters:
projectId(string, required): Project IDvariableName(string, required): Variable name
Query Parameters:
hard(string, optional): Set to"true"for permanent deletion
Response (200):
{
"success": true,
"message": "Variable deleted successfully"
}
POST /api/admin/projects/:projectId/variables/validate
Validate variables against governance rules.
URL Parameters:
projectId(string, required): Project ID
Request Body:
{
"variables": ["DB_NAME", "API_PORT", "LOG_LEVEL"]
}
Response (200):
{
"success": true,
"validation": {
"projectId": "tractatus",
"totalVariables": 3,
"found": ["DB_NAME", "API_PORT"],
"missing": ["LOG_LEVEL"],
"missingCount": 1
}
}
POST /api/admin/projects/:projectId/variables/batch
Batch create/update variables.
URL Parameters:
projectId(string, required): Project ID
Request Body:
{
"variables": [
{
"variableName": "DB_NAME",
"value": "tractatus_prod",
"description": "Database name",
"category": "database"
},
{
"variableName": "DB_PORT",
"value": "27017",
"description": "Database port",
"category": "database",
"dataType": "number"
}
]
}
Response (200):
{
"success": true,
"results": {
"created": 1,
"updated": 1,
"failed": 0,
"total": 2
},
"variables": [ ... ],
"message": "Batch operation completed: 1 created, 1 updated"
}
Variable Substitution
GET /api/admin/rules?projectId={projectId}
Get rules with variable substitution.
Query Parameters:
projectId(string, optional): Project ID for variable substitution- All standard rule filters (scope, quadrant, etc.)
Behavior:
- When
projectIdis not provided: Returns rules with template text only - When
projectIdis provided: Returns rules with both template and rendered text
Response WITHOUT projectId:
{
"success": true,
"rules": [
{
"id": "inst_001",
"text": "Connect to database ${DB_NAME} on port ${DB_PORT}",
"scope": "UNIVERSAL",
...
}
]
}
Response WITH projectId:
{
"success": true,
"rules": [
{
"id": "inst_001",
"text": "Connect to database ${DB_NAME} on port ${DB_PORT}",
"renderedText": "Connect to database tractatus_prod on port 27017",
"projectContext": "tractatus",
"substitutions": {
"DB_NAME": "tractatus_prod",
"DB_PORT": "27017"
},
"scope": "UNIVERSAL",
...
}
]
}
Variable Detection:
- Variables are detected using pattern:
/\$\{([A-Z][A-Z0-9_]*)\}/g - Only UPPER_SNAKE_CASE variables are recognized
- Missing variables are left as
${MISSING_VAR}in rendered text - Warning included in response if variables are missing
Error Handling
Standard Error Response Format
{
"success": false,
"error": "ErrorType",
"message": "Human-readable error description"
}
HTTP Status Codes
| Code | Meaning | Common Causes |
|---|---|---|
| 200 | OK | Successful GET/PUT/DELETE |
| 201 | Created | Successful POST |
| 400 | Bad Request | Invalid input, validation errors |
| 401 | Unauthorized | Missing/invalid token |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate ID |
| 500 | Internal Server Error | Server-side error |
Common Error Scenarios
Duplicate Project ID:
{
"success": false,
"message": "Project with ID 'tractatus' already exists"
}
Invalid Variable Name:
{
"success": false,
"error": "Invalid variable name",
"message": "Variable name must be UPPER_SNAKE_CASE (e.g., DB_NAME, API_KEY_2)"
}
Project Not Found:
{
"success": false,
"message": "Project 'invalid-id' not found"
}
Usage Examples
Example 1: Create a New Project with Variables
// Step 1: Create project
const projectResponse = await fetch('/api/admin/projects', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: 'my-app',
name: 'My Application',
description: 'A new application',
techStack: {
framework: 'Express.js',
database: 'MongoDB'
},
active: true
})
});
const project = await projectResponse.json();
console.log(project.project.id); // 'my-app'
// Step 2: Add variables using batch operation
const variablesResponse = await fetch('/api/admin/projects/my-app/variables/batch', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
variables: [
{
variableName: 'DB_NAME',
value: 'my_app_db',
category: 'database'
},
{
variableName: 'APP_PORT',
value: '3000',
category: 'config',
dataType: 'number'
}
]
})
});
const result = await variablesResponse.json();
console.log(result.results); // { created: 2, updated: 0, failed: 0, total: 2 }
Example 2: View Rules with Variable Substitution
// Get rules with variable substitution for 'tractatus' project
const response = await fetch('/api/admin/rules?projectId=tractatus', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
data.rules.forEach(rule => {
console.log('Template:', rule.text);
// "Connect to database ${DB_NAME} on port ${DB_PORT}"
console.log('Rendered:', rule.renderedText);
// "Connect to database tractatus_prod on port 27017"
console.log('Substitutions:', rule.substitutions);
// { DB_NAME: "tractatus_prod", DB_PORT: "27017" }
});
Example 3: Update Variable Value
// Update DB_PORT for tractatus project
const response = await fetch('/api/admin/projects/tractatus/variables/DB_PORT', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
value: '27018', // Updated port
description: 'Updated MongoDB port'
})
});
const result = await response.json();
console.log(result.message); // 'Variable updated successfully'
Example 4: Validate Required Variables
// Check if all required variables exist for a project
const response = await fetch('/api/admin/projects/my-app/variables/validate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
variables: ['DB_NAME', 'DB_PORT', 'API_KEY', 'SECRET_KEY']
})
});
const validation = await response.json();
if (validation.validation.missingCount > 0) {
console.error('Missing variables:', validation.validation.missing);
// Create missing variables...
}
Example 5: Soft Delete vs Hard Delete
// Soft delete (default) - deactivates project and variables
const softDelete = await fetch('/api/admin/projects/old-project', {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
const result1 = await softDelete.json();
console.log(result1.message); // 'Project deleted successfully (soft delete)'
// Hard delete - permanently removes from database
const hardDelete = await fetch('/api/admin/projects/old-project?hard=true', {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
const result2 = await hardDelete.json();
console.log(result2.message); // 'Project permanently deleted'
Best Practices
Variable Naming
- ✅ Use UPPER_SNAKE_CASE:
DB_NAME,API_KEY_2,MAX_CONNECTIONS - ❌ Avoid lowercase or camelCase:
dbName,api_key,maxConnections
Security
- 🔒 Never commit sensitive variable values to version control
- 🔒 Use category
securityfor credentials - 🔒 Consider encrypting sensitive values in database
- 🔒 Rotate API keys regularly
Organization
- 📁 Use categories to group related variables
- 📝 Provide clear descriptions for all variables
- 🏷️ Use consistent naming conventions across projects
- 🔄 Use batch operations for bulk updates
Performance
- ⚡ Cache project data when possible
- ⚡ Use filters to reduce response payload
- ⚡ Batch variable operations instead of individual requests
- ⚡ Only request variable substitution when needed
API Version History
v1.0 (2025-01-15)
- Initial release
- Projects CRUD operations
- Variables CRUD operations
- Variable substitution in rules
- Batch operations
- Validation endpoints
Last Updated: 2025-01-15 Maintained By: Tractatus Framework Team