chore: initial project setup with backend, frontend, CI/CD, and documentation
CI / backend (push) Failing after 15s
CI / frontend (push) Failing after 39s

Add complete NexaFabric project structure including:
- FastAPI backend with SQLAlchemy models, JWT auth, RBAC, audit logging, and provider interfaces
- React + TypeScript frontend with Vite, Tailwind CSS, TanStack Query, and Zustand
- Docker Compose configuration for PostgreSQL, Redis, API, worker, frontend, and nginx
- GitHub Actions and GitLab CI workflows for testing, linting, building, and security scanning
- Environment
This commit is contained in:
2026-07-09 12:10:35 +02:00
commit 14e7710120
83 changed files with 2887 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.core.config import get_settings
from app.core.security import hash_password
from app.models.domain import (
AuditLog,
Cluster,
IpAddress,
Network,
Node,
Policy,
Project,
Role,
SecurityGroup,
ServiceCatalogItem,
Subnet,
Tenant,
User,
Workload,
)
SERVICES = [
("SSH", "tcp", "22"),
("HTTP", "tcp", "80"),
("HTTPS", "tcp", "443"),
("DNS", "tcp/udp", "53"),
("LDAP", "tcp", "389"),
("LDAPS", "tcp", "636"),
("RDP", "tcp", "3389"),
("PostgreSQL", "tcp", "5432"),
("MySQL/MariaDB", "tcp", "3306"),
("MSSQL", "tcp", "1433"),
("Redis", "tcp", "6379"),
("SMB", "tcp", "445"),
("SMTP", "tcp", "25"),
("SMTPS", "tcp", "465"),
("IMAPS", "tcp", "993"),
("POP3S", "tcp", "995"),
("Proxmox API", "tcp", "8006"),
("Proxmox SPICE", "tcp", "3128"),
]
def seed_demo_data(db: Session) -> None:
if db.scalar(select(User).where(User.email == "admin@nexafabric.local")):
return
super_admin = Role(name="Super Admin", permissions=["*"])
roles = [
super_admin,
Role(name="Network Admin", permissions=["networks:*", "ipam:*", "clusters:read"]),
Role(name="Security Admin", permissions=["policies:*", "firewall:*", "security-groups:*"]),
Role(name="Tenant Admin", permissions=["tenants:read", "projects:*"]),
Role(name="Auditor", permissions=["audit:read", "clusters:read", "policies:read"]),
Role(name="Read Only User", permissions=["*:read"]),
]
user = User(
email="admin@nexafabric.local",
display_name="NexaFabric Administrator",
password_hash=hash_password(get_settings().demo_admin_password),
roles=[super_admin],
)
db.add_all(roles + [user])
tenants = [
Tenant(name="Platform", description="Shared infrastructure and platform services"),
Tenant(name="Finance", description="Finance applications"),
Tenant(name="Research", description="Lab and engineering workloads"),
]
db.add_all(tenants)
db.flush()
projects = [
Project(tenant_id=tenants[0].id, name="Core Services", description="DNS, auth, monitoring"),
Project(tenant_id=tenants[1].id, name="ERP", description="Finance ERP workloads"),
Project(tenant_id=tenants[2].id, name="Lab", description="Research lab systems"),
]
db.add_all(projects)
db.flush()
cluster = Cluster(
name="Demo Proxmox Cluster",
api_url="https://pve-demo.local:8006",
token_ref="demo-token-reference",
last_sync_status="success",
)
db.add(cluster)
db.flush()
nodes = [
Node(cluster_id=cluster.id, name="pve-01", status="online", cpu_count=32, memory_mb=131072),
Node(cluster_id=cluster.id, name="pve-02", status="online", cpu_count=32, memory_mb=131072),
Node(cluster_id=cluster.id, name="pve-03", status="warning", cpu_count=24, memory_mb=98304),
]
db.add_all(nodes)
db.flush()
networks = [
Network(cluster_id=cluster.id, project_id=projects[0].id, name="mgmt", kind="bridge", vlan_id=10, gateway="10.10.10.1", dns=["10.10.10.10"], tags=["management"], description="Management bridge"),
Network(cluster_id=cluster.id, project_id=projects[0].id, name="services", kind="vlan", vlan_id=20, gateway="10.20.0.1", dns=["10.20.0.10"], tags=["shared"], description="Shared services"),
Network(cluster_id=cluster.id, project_id=projects[1].id, name="finance-app", kind="vxlan", vlan_id=120, gateway="10.120.0.1", dns=["10.20.0.10"], tags=["finance"], description="Finance application tier"),
Network(cluster_id=cluster.id, project_id=projects[2].id, name="research-lab", kind="vnet", vlan_id=220, gateway="10.220.0.1", dns=["10.20.0.10"], tags=["lab"], description="Research tenant network"),
]
db.add_all(networks)
db.flush()
subnets = [
Subnet(network_id=networks[0].id, cidr="10.10.10.0/24", gateway="10.10.10.1", dns=["10.10.10.10"]),
Subnet(network_id=networks[1].id, cidr="10.20.0.0/24", gateway="10.20.0.1", dns=["10.20.0.10"]),
Subnet(network_id=networks[2].id, cidr="10.120.0.0/24", gateway="10.120.0.1", dns=["10.20.0.10"]),
]
db.add_all(subnets)
db.flush()
workloads = []
for idx in range(10):
project = projects[idx % len(projects)]
workloads.append(
Workload(
cluster_id=cluster.id,
node_id=nodes[idx % len(nodes)].id,
project_id=project.id,
external_id=str(100 + idx),
name=f"{project.name.lower().replace(' ', '-')}-{idx + 1}",
kind="qemu" if idx % 3 else "lxc",
status="running" if idx != 7 else "stopped",
tags=["web"] if idx % 2 else ["db"],
)
)
db.add_all(workloads)
db.flush()
db.add_all(
[
IpAddress(subnet_id=subnets[0].id, address="10.10.10.20", status="assigned", workload_id=workloads[0].id),
IpAddress(subnet_id=subnets[1].id, address="10.20.0.50", status="reserved", note="Load balancer VIP"),
IpAddress(subnet_id=subnets[2].id, address="10.120.0.99", status="conflict", note="Duplicate detected during import"),
]
)
groups = [
SecurityGroup(project_id=projects[0].id, name="Management", description="Administrative access"),
SecurityGroup(project_id=projects[1].id, name="Finance Web", description="Finance web tier"),
SecurityGroup(project_id=projects[1].id, name="Finance DB", description="Finance database tier"),
]
db.add_all(groups)
db.add_all(
[
Policy(
project_id=projects[1].id,
name="Finance web to database",
definition={
"source": "sg:Finance Web",
"destination": "sg:Finance DB",
"service": {"protocol": "tcp", "ports": "5432"},
"action": "allow",
"direction": "egress",
"logging": True,
"description": "Allow PostgreSQL from finance web tier to database tier.",
},
),
Policy(
project_id=projects[0].id,
name="Management SSH",
definition={
"source": "network:mgmt",
"destination": "any",
"service": {"protocol": "tcp", "ports": "22"},
"action": "allow",
"direction": "ingress",
},
),
]
)
db.add_all([ServiceCatalogItem(name=name, protocol=proto, ports=ports, editable=True) for name, proto, ports in SERVICES])
db.add(AuditLog(user_id=user.id, action="seed.created", object_type="system", result="success"))
db.commit()