Phase 02: First Spoke Repository
Phase 2: Create the First Spoke Repository
A spoke is a self-contained documentation component. It has its own antora.yml, its own pages, partials, examples, and its own attribute inventory. The critical design principle: spokes are independently deployable — you can clone a single spoke and build it without the hub or any other spoke. This means every attribute a spoke uses must be defined in its own antora.yml, even if other spokes define the same value.
Architecture Decision: docs/asciidoc Start Path
Technical spokes use docs/asciidoc/ as the Antora start path. This gives the repo room for non-Antora content (scripts, CI/CD, README) in docs/ without polluting the Antora module structure.
infra-docs/
├── docs/
│ ├── asciidoc/ ← Antora starts HERE (start_path in playbook)
│ │ ├── antora.yml ← Component descriptor
│ │ └── modules/ROOT/ ← Content lives here
│ └── other/ ← Non-Antora docs, scripts, etc.
├── scripts/ ← Operational scripts
├── README.adoc
└── .gitignore
Step 1: Initialize the Spoke
mkdir infra-docs && cd infra-docs
git init
mkdir -p docs/asciidoc/modules/ROOT/{pages,partials,examples,images}
mkdir -p docs/asciidoc/modules/ROOT/pages/{runbooks,architecture,reference}
mkdir -p docs/asciidoc/modules/ROOT/partials/{runbooks,common}
mkdir -p docs/asciidoc/modules/ROOT/examples/{scripts,configs}
Step 2: Create the Component Descriptor
This is the spoke’s identity. The attribute section is the most important part — it defines every mutable value the documentation references.
File: docs/asciidoc/antora.yml
name: infra-ops
title: Infrastructure Operations
version: ~
start_page: ROOT:index.adoc
nav:
- modules/ROOT/nav.adoc
asciidoc:
attributes:
# ================================================================
# NAVIGATION & METADATA
# ================================================================
nav_order: '10'
category: Infrastructure
doc-id: PRJ-INFRA-OPS
author: Your Name
icons: font
source-highlighter: highlight.js
experimental: ''
# ================================================================
# DOMAIN CONFIGURATION
# ================================================================
domain: corp.example.com
# ================================================================
# INFRASTRUCTURE HOSTS — HOSTNAMES
# ================================================================
# Naming convention: <device>-hostname
sw-core-01-hostname: sw-core-01.corp.example.com
sw-core-02-hostname: sw-core-02.corp.example.com
sw-dist-01-hostname: sw-dist-01.corp.example.com
fw-01-hostname: fw-01.corp.example.com
wlc-01-hostname: wlc-01.corp.example.com
ise-01-hostname: ise-01.corp.example.com
ise-02-hostname: ise-02.corp.example.com
dc-01-hostname: dc-01.corp.example.com
# ================================================================
# INFRASTRUCTURE HOSTS — IP ADDRESSES
# ================================================================
# Naming convention: <device>-ip
sw-core-01-ip: 10.1.1.1
sw-core-02-ip: 10.1.1.2
sw-dist-01-ip: 10.1.1.10
fw-01-ip: 10.1.1.20
wlc-01-ip: 10.1.1.30
ise-01-ip: 10.1.10.20
ise-02-ip: 10.1.10.21
dc-01-ip: 10.1.10.50
# ================================================================
# NETWORK — VLANs
# ================================================================
# Naming convention: vlan-<name>
vlan-mgmt: 10
vlan-data: 20
vlan-voice: 30
vlan-iot: 40
vlan-guest: 50
vlan-quarantine: 999
# ================================================================
# NETWORK — SUBNETS & GATEWAYS
# ================================================================
subnet-mgmt: 10.1.10.0/24
subnet-data: 10.1.20.0/24
subnet-voice: 10.1.30.0/24
subnet-iot: 10.1.40.0/24
gateway-mgmt: 10.1.10.1
gateway-data: 10.1.20.1
# ================================================================
# PROTOCOLS & PORTS
# ================================================================
port-radius-auth: 1812
port-radius-acct: 1813
port-tacacs: 49
port-snmp: 161
port-syslog: 514
port-ntp: 123
port-ssh: 22
port-https: 443
port-dns: 53
# ================================================================
# FILESYSTEM PATHS
# ================================================================
cert-dir: /etc/ssl/certs
key-dir: /etc/ssl/private
backup-dir: /opt/backups
# ================================================================
# ISE CONFIGURATION (if applicable)
# ================================================================
# policy-set-wired: Wired_802.1X
# authz-profile-corp: PermitAccess
# dacl-quarantine: ACL-QUARANTINE
# ================================================================
# PERSONNEL
# ================================================================
person-lead: NetworkLead
team-name: Network Engineering
Why duplicate attributes across spokes? Each spoke is independently buildable. If nac-docs also references ise-01-ip, it defines it in its own antora.yml. When the IP changes, you update every spoke — but each spoke can be built, tested, and deployed independently. This is the same pattern used across the domus-digitalis 15-spoke federation.
Step 3: Create the Navigation
File: docs/asciidoc/modules/ROOT/nav.adoc
* xref:index.adoc[Overview]
* Runbooks
** xref:runbooks/switch-upgrade.adoc[Switch Upgrade]
** xref:runbooks/firewall-change.adoc[Firewall Change]
* Architecture
** xref:architecture/network-topology.adoc[Network Topology]
** xref:architecture/vlan-design.adoc[VLAN Design]
* Reference
** xref:reference/vlan-table.adoc[VLAN Table]
** xref:reference/ip-allocation.adoc[IP Allocation]
As the spoke grows beyond 50 pages, switch to the modular nav partial pattern (see Phase 8 and Appendix: Nav Patterns).
Step 4: Create the Landing Page
File: docs/asciidoc/modules/ROOT/pages/index.adoc
= Infrastructure Operations
:description: Runbooks, architecture, and reference for network infrastructure
:icons: font
Operations documentation for the {team-name} team.
== Quick Links
* xref:runbooks/switch-upgrade.adoc[Switch Upgrade Procedure]
* xref:architecture/network-topology.adoc[Network Topology]
* xref:reference/vlan-table.adoc[VLAN Reference Table]
== Infrastructure Summary
[cols="2,2,2"]
|===
| System | IP | Status
| Core Switch 1
| {sw-core-01-ip}
| Production
| Core Switch 2
| {sw-core-02-ip}
| Production
| ISE Primary
| {ise-01-ip}
| Production
| ISE Secondary
| {ise-02-ip}
| Production
|===
Note: every IP comes from an attribute. No hardcoded values.
Step 5: Create a Reusable Partial
File: docs/asciidoc/modules/ROOT/partials/common/change-control-note.adoc
[IMPORTANT]
====
All production changes require a Change Request (CR) with:
* Pre-verification commands and expected output
* Change commands (copy-paste ready)
* Post-verification commands and expected output
* Rollback procedure
Follow the change control process before modifying production systems.
====
Use in any page:
include::partial$common/change-control-note.adoc[]
Step 6: Create a Sample Runbook with Attributes
File: docs/asciidoc/modules/ROOT/pages/runbooks/switch-upgrade.adoc
= Switch Upgrade Procedure
:description: IOS-XE upgrade procedure for Catalyst switches
:icons: font
include::partial$common/change-control-note.adoc[]
== Pre-Verification
[source,bash,subs=attributes+]
....
ssh admin@{sw-core-01-ip}
show version | include System image
show boot
show flash: | include .bin
....
== Upgrade Steps
[source,bash,subs=attributes+]
....
ssh admin@{sw-core-01-ip}
copy tftp://{fw-01-ip}/cat9k_iosxe.17.09.05.SPA.bin flash:
install add file flash:cat9k_iosxe.17.09.05.SPA.bin activate commit
....
== Post-Verification
[source,bash,subs=attributes+]
....
ssh admin@{sw-core-01-ip}
show version | include System image
show ip interface brief | include up
show spanning-tree summary
....
== Rollback
[source,bash,subs=attributes+]
....
ssh admin@{sw-core-01-ip}
install rollback to committed
....
Every command block uses subs=attributes+ so that {sw-core-01-ip} renders as the actual IP. Change the IP in antora.yml once — every runbook updates.
Step 7: Register in the Hub Playbook
In team-docs/antora-playbook.yml:
# Infrastructure Operations
- url: https://github.com/your-org/infra-docs
branches: main
start_path: docs/asciidoc
edit_url: false
For local development:
- url: ../infra-docs
branches: HEAD
start_path: docs/asciidoc
Step 8: Build and Verify
cd ../team-docs
make check
make serve
# Navigate to http://localhost:8080/infra-ops/
Directory Structure After Phase 2
infra-docs/
├── docs/
│ └── asciidoc/ ← start_path
│ ├── antora.yml # 80+ attributes
│ └── modules/ROOT/
│ ├── nav.adoc # Component navigation
│ ├── pages/
│ │ ├── index.adoc # Landing page (uses attributes)
│ │ ├── runbooks/
│ │ │ ├── switch-upgrade.adoc # Uses {sw-core-01-ip}
│ │ │ └── firewall-change.adoc
│ │ ├── architecture/
│ │ │ ├── network-topology.adoc
│ │ │ └── vlan-design.adoc
│ │ └── reference/
│ │ ├── vlan-table.adoc # Uses {vlan-data}, {vlan-voice}
│ │ └── ip-allocation.adoc
│ ├── partials/
│ │ ├── common/
│ │ │ └── change-control-note.adoc
│ │ └── runbooks/
│ ├── examples/
│ │ ├── scripts/
│ │ └── configs/
│ └── images/
│ └── diagrams/
└── .gitignore