Skip to content

Architecture overview

The 5-minute mental model.

Layers

┌──────────────────────────────────────────┐
│  Server-rendered Django templates        │  ← UI today (Tailwind via CDN)
│  Will be replaced by React in Phase 3    │
├──────────────────────────────────────────┤
│  Django views (CBV + FBV mix)            │
│  Forms (ModelForm) · Filters · Pagination│
├──────────────────────────────────────────┤
│  ORM models · custom managers            │
│  Tenant/VRF scoping · JSONB custom_fields│
├──────────────────────────────────────────┤
│  PostgreSQL 18                           │
└──────────────────────────────────────────┘

┌─────────────┐   ┌─────────────┐
│ Redis 7     │   │ RQ workers  │  ← async jobs (compliance, import)
└─────────────┘   └─────────────┘     not yet wired in MVP

Two organising principles

1. Zero pre-filled data

Danbyte ships models, never data. There are no canned device types, no default tags, no shipped compliance frameworks, no default VLAN list. Every domain object exposes custom_fields (JSONB) for user-defined attributes and tags for user-defined categorisation.

Before adding any seed value, default choice list, or hardcoded field, the check is: can this be custom_fields or a user-created object instead? The answer is almost always yes.

2. Hard isolation by Tenant + VRF

Boundary Purpose Strictness
Organization The Danbyte install owner (SaaS account) Loose — used for billing/admin
Tenant The customer / business unit Hard — never shown together in the UI
VRF The routing context inside a tenant Hard — uniqueness is (tenant, vrf, cidr)
Site The location Soft — multiple sites within a VRF, optionally documented as Site.vrfs

See Tenant + VRF for details.

Request lifecycle (prefix list)

GET /prefixes/?vrf=<uuid>&status=active
prefixes_list(request)         # api/views.py
    ├─ _get_active_tenant(request)
    │    └─ session['current_tenant_id'] OR Tenant.objects.first()
    ├─ Prefix.objects.filter(tenant=tenant)   # tenant scoping
    ├─ _apply_filters(qs, request.GET)        # status, family, q
    ├─ Q(vrf=...) | Q(vrf__isnull=True)       # VRF facet filter
    ├─ if sort=cidr:
    │    bucket by (vrf, family)
    │    stack-walk depth per bucket
    │    build sections                       # one per VRF
    └─ render prefixes.html

File layout

danbyte/
  api/                       # the main Django app
    models.py                # VRF + Site + Prefix + IPAddress + Device + …
    forms.py                 # PrefixForm + IPAddressForm
    views.py                 # all the server-rendered views
    urls.py                  # /prefixes/* routing
    templates/api/
      _shell.html            # sidebar + topbar shell (extended by every page)
      _prefix_row.html       # row partial used by the list table
      prefixes.html
      prefix_detail.html
      prefix_form.html
      ip_form.html
    management/commands/
      seed_demo.py           # opt-in demo data
  core/
    models.py                # Organization · Tenant · Tag · TaggedItem
  design/                    # static mockups (the design source of truth)
  docs/                      # this documentation
  services/                  # systemd user units
  Makefile                   # dev shortcuts
  zensical.toml              # docs config
  CLAUDE.md                  # design standard + project notes