Files
----/README.md
smolkik-code 9b15f8b09c feat: CMDB full-stack app - FastAPI + PostgreSQL + React
- PostgreSQL schema: 14 tables, JSONB attributes, audit triggers, soft delete
- FastAPI backend: CRUD, search/filter, relationship graph, bulk import, JWT RBAC
- React frontend: CI table, detail card, force-graph, dashboard
- Seed data: homelab scenario (Proxmox, Mikrotik, VMs, services)
- Docker Compose + Kubernetes manifests
- 20 backend tests (pytest + httpx)
2026-06-25 13:01:40 +07:00

9.2 KiB

CMDB — Configuration Management Database

Full-stack CMDB application: FastAPI + PostgreSQL + React (MUI)

Architecture

┌──────────┐     ┌────────────┐     ┌────────────┐
│  React   │────▶│  Nginx     │────▶│  FastAPI   │
│  (MUI)   │     │  (reverse  │     │  (async)   │
│  :3000   │     │  proxy)    │     │  :8000     │
└──────────┘     │  :80       │     └─────┬──────┘
                 └────────────┘           │
                                   ┌──────▼──────┐
                                   │  PostgreSQL  │
                                   │  :5432       │
                                   └─────────────┘

Quick Start (Docker Compose)

# Clone and start
cd cmdb-app
docker-compose up -d

# Apply migrations (if not auto-applied)
docker exec -i cmdb-postgres psql -U cmdb -d cmdb < backend/migrations/001_initial_schema.sql
docker exec -i cmdb-postgres psql -U cmdb -d cmdb < backend/migrations/002_seed_data.sql

# Open
# API docs: http://localhost/api/docs
# Frontend: http://localhost

Local Development

Backend

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# Start PostgreSQL (Docker)
docker run -d --name cmdb-pg -p 5432:5432 \
  -e POSTGRES_DB=cmdb -e POSTGRES_USER=cmdb -e POSTGRES_PASSWORD=cmdb_secret \
  postgres:16-alpine

# Run migrations
psql -h localhost -U cmdb -d cmdb < migrations/001_initial_schema.sql
psql -h localhost -U cmdb -d cmdb < migrations/002_seed_data.sql

# Start backend
uvicorn app.main:app --reload --port 8000

Frontend

cd frontend
npm install
npm run dev
# → http://localhost:5173

API Reference

Authentication

# Login
curl -X POST http://localhost:8000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}'
# → {"access_token":"eyJ...","token_type":"bearer"}

# Get current user
curl -H "Authorization: Bearer <token>" http://localhost:8000/api/auth/me

Configuration Items

# List CIs (paginated, filtered)
curl -H "Authorization: Bearer <token>" \
  "http://localhost:8000/api/ci?page=1&page_size=10&status=active&search=proxmox"

# Get single CI with all details
curl -H "Authorization: Bearer <token>" \
  http://localhost:8000/api/ci/<ci_id>

# Create CI
curl -X POST http://localhost:8000/api/ci \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "new-server",
    "ci_type_id": "<type_uuid>",
    "status": "active",
    "tags": ["new", "production"],
    "attributes": {"cpu": "Xeon", "ram_gb": 32}
  }'

# Update CI
curl -X PATCH http://localhost:8000/api/ci/<ci_id> \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"status": "maintenance"}'

# Delete (soft)
curl -X DELETE -H "Authorization: Bearer <token>" \
  http://localhost:8000/api/ci/<ci_id>

# Export CSV
curl -H "Authorization: Bearer <token>" \
  http://localhost:8000/api/ci/export?format=csv > cmdb_export.csv

Relationships & Graph

# Add relationship
curl -X POST http://localhost:8000/api/ci/<ci_id>/relationships \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "source_ci_id": "<ci_id>",
    "target_ci_id": "<other_ci_id>",
    "relationship": "depends_on",
    "description": "Service depends on server"
  }'

# Get relationship graph
curl -H "Authorization: Bearer <token>" \
  "http://localhost:8000/api/ci/graph/visualize?depth=2"

Bulk Import

curl -X POST http://localhost:8000/api/ci/bulk/import \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"name": "server-1", "ci_type_name": "PhysicalServer", "status": "active"},
      {"name": "vm-web", "ci_type_name": "VirtualMachine", "status": "active"}
    ]
  }'

Dashboard

curl -H "Authorization: Bearer <token>" \
  http://localhost:8000/api/dashboard/stats

Query Parameters (CI List)

Parameter Type Description
page int Page number (default: 1)
page_size int Items per page (1-100, default: 20)
search string Full-text search on name/desc/serial
status string Filter by status
ci_type_id UUID Filter by CI type
location_id UUID Filter by location
tag string Filter by tag
owner_id UUID Filter by owner
sort_by string Sort field (default: name)
sort_order string asc/desc (default: asc)

Testing

cd backend
pytest tests/ -v

Deployment

Docker Compose (production)

# Set secrets
export JWT_SECRET=$(openssl rand -hex 32)
export POSTGRES_PASSWORD=$(openssl rand -hex 32)

docker-compose -f docker-compose.yml up -d

Kubernetes

# Create namespace
kubectl create namespace cmdb

# Create secrets
kubectl -n cmdb create secret generic cmdb-secrets \
  --from-literal=db-user=cmdb \
  --from-literal=db-password=$(openssl rand -hex 16) \
  --from-literal=jwt-secret=$(openssl rand -hex 32)

# Deploy
kubectl apply -f k8s/postgres.yaml
kubectl apply -f k8s/backend.yaml
kubectl apply -f k8s/frontend.yaml

# Check
kubectl -n cmdb get pods

Security Checklist

  • Change JWT_SECRET in production
  • Change PostgreSQL password
  • Enable SSL/TLS for PostgreSQL (sslmode=require)
  • Run backend as non-root user
  • Configure CORS for production domain only
  • Set up pg_hba.conf to restrict DB access
  • Enable rate limiting (configured: 120 req/min)
  • Run pg_dump backups daily
  • Review audit trail in changelog table

Database Schema

ER Diagram (simplified)

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  ci_classes  │────▶│   ci_types   │────▶│     cis      │
└──────────────┘     └──────────────┘     └──────┬───────┘
                                                  │
                    ┌─────────────────────────────┼───────────────────────┐
                    │             │               │             │         │
              ┌─────▼─────┐ ┌────▼─────┐  ┌──────▼──────┐ ┌───▼────┐ ┌──▼──────────┐
              │ip_addresses│ │  nics    │  │  hw_details │ │sw_inst │ │relationships│
              └───────────┘ └──────────┘  └─────────────┘ └────────┘ └─────────────┘

Key Design Decisions

  1. Soft delete everywheredeleted_at column, never hard delete
  2. JSONB attributes — extensible key-value store for class-specific fields
  3. Audit trailchangelog table + PostgreSQL triggers
  4. Versioning — CI version column incremented on every update
  5. UUID primary keys — safe for distributed/multi-instance
  6. INET type — native PostgreSQL IP address handling

Ansible Integration

# playbooks/cmdb-import.yml
- name: Import Ansible facts into CMDB
  hosts: all
  tasks:
    - name: Get system facts
      set_fact:
        ci_data:
          name: "{{ inventory_hostname }}"
          status: active
          attributes:
            os: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
            cpu_cores: "{{ ansible_processor_vcpus }}"
            ram_gb: "{{ (ansible_memtotal_mb / 1024) | round(1) }}"
            ip: "{{ ansible_default_ipv4.address }}"

    - name: Register in CMDB
      uri:
        url: "http://cmdb-host:8000/api/ci"
        method: POST
        headers:
          Authorization: "Bearer {{ cmdb_token }}"
        body_format: json
        body: "{{ ci_data }}"
        status_code: [201, 409]

Roadmap

  1. Discovery integration — nmap, arp-scan, SNMP polling
  2. CMDB reconciliation — compare discovered vs. recorded state
  3. Change management — RFC workflow, approval chain
  4. Dependency impact analysis — cascade failure simulation
  5. SSO/LDAP — corporate directory integration
  6. Webhook notifications — Slack/Teams alerts on CI changes
  7. API versioning/api/v2/ with backward compatibility
  8. GraphQL — alternative API layer for complex queries
  9. RBAC per CI type — fine-grained access control
  10. Terraform/Pulumi integration — import IaC resources as CIs