tractatus/docs/api/PROJECTS_API.md
TheFlow 91aea5091c feat: implement Rule Manager and Project Manager admin systems
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>
2025-10-11 17:16:51 +13:00

17 KiB

Projects & Variables API Documentation

Version: 1.0 Base URL: /api/admin Authentication: Required (Bearer token)


Table of Contents

  1. Overview
  2. Authentication
  3. Projects API
  4. Variables API
  5. Variable Substitution
  6. Error Handling
  7. 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: false on 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 configuration
  • config - Application configuration
  • url - URLs and endpoints
  • path - File paths and directories
  • security - Security credentials (use with caution)
  • feature_flag - Feature flags
  • other - Miscellaneous

Data Types:

  • string (default)
  • number
  • boolean
  • json

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 ID
  • variableName (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 ID
  • variableName (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 projectId is not provided: Returns rules with template text only
  • When projectId is 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 security for 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