diff --git a/docs/build-docs.sh b/docs/build-docs.sh
index dc4c92c014ab21ce6405b7c765bf6fd7aa35b178..6da63d82bed8839ab2e2d068bd8a86b245fe06d6 100755
--- a/docs/build-docs.sh
+++ b/docs/build-docs.sh
@@ -5,7 +5,7 @@ set -o nounset
 export OSS_PARAMS_FILENAME=../gso/oss-params-example.json
 export TESTING=true
 
-pip install pyyaml mkdocstrings-python mkdocs_gen_files mkdocs-material mkdocs-literate-nav mkdocs-redirects
+pip install pyyaml mkdocstrings-python mkdocs_gen_files mkdocs-material mkdocs-literate-nav mkdocs-redirects mkdocs-open-in-new-tab
 pip install -e ..
 python ./scripts/gen_wf_redirects.py
 
diff --git a/docs/includes/glossary.md b/docs/includes/glossary.md
index 4df9f9940521f78574c848c2f49bcfa76dd7899f..a29d245259baa8a8b27cd16feade66bd5fa6c732 100644
--- a/docs/includes/glossary.md
+++ b/docs/includes/glossary.md
@@ -5,6 +5,7 @@
 *[CFS]: Customer Facing Service
 *[CIDR]: Classless Inter-Domain Routing
 *[DCIM]: Datacenter Infrastructure Manager
+*[DCN]: Datacenter Network
 *[DHCP]: Dynamic Host Configuration Protocol
 *[DNS]: Domain Name System
 *[DTAP]: Development, Testing, Acceptance, and Production
diff --git a/docs/scripts/gen_wf_redirects.py b/docs/scripts/gen_wf_redirects.py
index c4c0d8b321566628a83dd7eea861e8b1486301c4..90b84444d2dbebfc339b24a07f4dfb5a011da74c 100644
--- a/docs/scripts/gen_wf_redirects.py
+++ b/docs/scripts/gen_wf_redirects.py
@@ -29,10 +29,11 @@ with Path.open(root / "docs" / "wf_redirects.yaml", "w") as redirect_file:
     file_content = {
         "plugins": [
             "search",
+            {"open-in-new-tab": {"add_icon": True}},
             {"gen-files": {"scripts": ["scripts/gen_ref_pages.py"]}},
             {"redirects": {"redirect_maps": redirect_map}},
             {"literate-nav": {"nav_file": "SUMMARY.md"}},
-            "mkdocstrings",
+            {"mkdocstrings": {"handlers": {"python": {"options": {"filters": [], "members_order": "source"}}}}},
         ]
     }
     yaml.dump(file_content, redirect_file)
diff --git a/docs/source/admin_guide/wfo/overview.md b/docs/source/admin_guide/wfo/overview.md
index d8af9f500a4fc8f6d57d8aba173fc2c67ed1b01b..6ec77a2a7ecdd83cc3b3cf038cd8835f6fe0920f 100644
--- a/docs/source/admin_guide/wfo/overview.md
+++ b/docs/source/admin_guide/wfo/overview.md
@@ -22,7 +22,7 @@ classDiagram
 
 A node consists of one or more routers, a switch, and a terminal server. 
 In general -- as laid out more extensively 
-<a href="https://wiki.geant.org/display/NETENG/001+-+Topology+and+physical+layout" target="_blank">here</a> 
+[here](https://wiki.geant.org/display/NETENG/001+-+Topology%2C+physical+layout+and+site+design) 
 (behind login) -- a PoP consists of:
 
 * One or two routers
diff --git a/docs/source/architecture/components/index.md b/docs/source/architecture/components/index.md
index bf0790f34cf09df7efab943a2437df16579319d0..76e837d67ef23a5442bf1a7b869d56cddc801a1b 100644
--- a/docs/source/architecture/components/index.md
+++ b/docs/source/architecture/components/index.md
@@ -1,7 +1,7 @@
 # Components of GAP
 
 As stated before, GAP is a platform and not a monolithic piece of software. GAP interacts with different OSS/BSS
-systems already present in GÉANT and these are tightly integrated with the automation platform.
+systems already present in GÉANT and these are integrated with the automation platform.
 
 From a high level point of view, GAP can be seen as the sum of the following parts:
 
diff --git a/docs/source/architecture/components/lso/index.md b/docs/source/architecture/components/lso/index.md
index a1e1e0d44c7c791b08441e7931bb61ea9137532a..bcfc35f9f6057d3adae25bbe9f8ed958bbf315a6 100644
--- a/docs/source/architecture/components/lso/index.md
+++ b/docs/source/architecture/components/lso/index.md
@@ -18,11 +18,9 @@ library dependencies.
 
 ## Inner workings
 
-LSO uses <a href="https://ansible.readthedocs.io/projects/runner/en/latest/"
-target="_blank">`ansible-runner`</a> for the execution of Ansible playbooks.
-This package fully dictates the way in which GAP interacts with Ansible itself.
-LSO only introduces an API with a single REST endpoint that exposes its
-functionality.
+LSO uses [`ansible-runner`](https://ansible.readthedocs.io/projects/runner/en/latest/) for the execution of Ansible
+playbooks.  This package fully dictates the way in which GAP interacts with Ansible itself. LSO only introduces an API
+with a single REST endpoint that exposes its functionality.
 
 In the case of GAP, all Ansible playbooks operate without an inventory that
 contains all relevant `group_vars` and `host_vars`. The inventory is passed to
@@ -148,15 +146,12 @@ full-fledged API request to LSO, an example call is given.
 
 ## Code documentation
 
-Code documentation for LSO can be found
-<a href="https://workfloworchestrator.org/lso" target="_blank">here</a>.
+Code documentation for LSO can be found [here](https://workfloworchestrator.org/lso).
 
 ## Deployment within GÉANT
 
-For the deployment in GÉANT, LSO runs inside a Docker container. The Dockerfile
-used to build this container is available <a href=
-"https://gitlab.software.geant.org/goat/gap/lso/-/blob/develop/Dockerfile"
-target="_blank">here</a>.
+For the deployment in GÉANT, LSO runs inside a Docker container. A Dockerfile that can be used to build this container
+is available [here](https://github.com/workfloworchestrator/lso/blob/main/Dockerfile.example).
 
 When building the Docker image, some Ansible roles and collections are installed
 that are required for interacting with Juniper and Nokia equipment. For another
diff --git a/docs/source/architecture/index.md b/docs/source/architecture/index.md
index 7f53acba3a6d6229d0dbe743fc907b0c1d4f00a9..da9f309c04eb4c4c409b4d4a28c894c5de95bf81 100644
--- a/docs/source/architecture/index.md
+++ b/docs/source/architecture/index.md
@@ -57,16 +57,12 @@ configuration backups of routers, switches, and any other network devices that a
 More detailed information about this integration is available in the
 [LibreNMS integration module](../admin_guide/oss_bss/librenms.md).
 
-### Kentik (planned)
+### Kentik
 
 Kentik is a Network Observability tool which collects various data points from deployed PE routers.
 For this reason it is not in scope for PHASE1.
 
-### Inventory provider (planned)
+### Inventory provider
 
 At the time of writing, the Inventory Provider gets the list of routers from the network engineering SOT servers.
 This will change and Inventory Provider is then able to directly query CoreDB.
-
-## Interaction with a technical domain: IP/MPLS
-
-TBA
diff --git a/docs/vale/.vale.ini b/docs/vale/.vale.ini
index 06742e1a587711316b5140adf0c4bb7a86099bab..a5a4c9cc53200bdab311a353d7fc2ac9233674c9 100644
--- a/docs/vale/.vale.ini
+++ b/docs/vale/.vale.ini
@@ -33,10 +33,10 @@ Microsoft.SentenceLength = NO
 
 ; This statement ignores the names of parameters in docstrings, the four spaces that prepend it and the one following it
 ; are necessary.
-TokenIgnores =     \S+:
+TokenIgnores = (?: *\S+: ), (?:`\S+`)
 
 [*.md]
 BasedOnStyles = Vale, proselint, Microsoft
 
 [formats]
-py = rst
+py = md
diff --git a/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt b/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
index 6373503d95c7d4af174b0bb9a34cb988ec00a402..aeb0c40d8ae8adc250f8ab38c568ad95d4855393 100644
--- a/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
+++ b/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
@@ -11,6 +11,7 @@ CIDR
 CFS
 CNAME
 DCIM
+DCN
 DDI
 DHCP
 DNS
@@ -90,3 +91,4 @@ WFO
 dry_run
 eBGP
 iBGP
+disable?[sd]
diff --git a/gso/auth/oidc.py b/gso/auth/oidc.py
index 02720fe170e55250218f5bdc2f722add2b88d3ad..ccbbe16382de30d092fd3d90c534d7499757cfc7 100644
--- a/gso/auth/oidc.py
+++ b/gso/auth/oidc.py
@@ -43,7 +43,7 @@ def ensure_openid_config_loaded(func: Callable) -> Callable:
 
 
 class OIDCAuthentication(OIDCAuth):
-    """OIDCUser class extends the ``HTTPBearer`` class to do extra verification.
+    """OIDCUser class extends the `HTTPBearer` class to do extra verification.
 
     The class will act as follows: Validate the Credentials at the AAI proxy by calling the UserInfo endpoint.
     """
diff --git a/gso/cli/imports.py b/gso/cli/imports.py
index fad9d1e14328b4319d60ed066cbc79b188c7b584..fc81b03b3f3c45c54f95db64a872c91cbeee1be6 100644
--- a/gso/cli/imports.py
+++ b/gso/cli/imports.py
@@ -64,11 +64,11 @@ class CreatePartner(BaseModel):
 
 
 class SiteImportModel(BaseSiteValidatorModel):
-    """The required input for importing an existing ``gso.products.product_types.site``."""
+    """The required input for importing an existing `gso.products.product_types.site`."""
 
 
 class RouterImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.product.product_types.router``."""
+    """Required fields for importing an existing `gso.product.product_types.router`."""
 
     partner: str
     router_site: str
@@ -82,7 +82,7 @@ class RouterImportModel(BaseModel):
 
 
 class SwitchImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.product.product_types.switch``."""
+    """Required fields for importing an existing `gso.product.product_types.switch`."""
 
     fqdn: str
     ts_port: PortNumber
@@ -92,7 +92,7 @@ class SwitchImportModel(BaseModel):
 
 
 class SuperPopSwitchImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.product.product_types.super_pop_switch``."""
+    """Required fields for importing an existing `gso.product.product_types.super_pop_switch`."""
 
     partner: str
     super_pop_switch_site: str
@@ -102,7 +102,7 @@ class SuperPopSwitchImportModel(BaseModel):
 
 
 class OfficeRouterImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.product.product_types.office_router``."""
+    """Required fields for importing an existing `gso.product.product_types.office_router`."""
 
     partner: str
     office_router_site: str
@@ -113,7 +113,7 @@ class OfficeRouterImportModel(BaseModel):
 
 
 class IptrunkImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.products.product_types.iptrunk``."""
+    """Required fields for importing an existing `gso.products.product_types.iptrunk`."""
 
     partner: str
     gs_id: IMPORTED_GS_ID | None
@@ -178,7 +178,7 @@ class IptrunkImportModel(BaseModel):
 
 
 class OpenGearImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.products.product_types.opengear``."""
+    """Required fields for importing an existing `gso.products.product_types.opengear`."""
 
     partner: str
     opengear_site: str
@@ -189,7 +189,7 @@ class OpenGearImportModel(BaseModel):
 
 
 class EdgePortImportModel(BaseModel):
-    """Required fields for importing an existing ``gso.products.product_types.edge_port``."""
+    """Required fields for importing an existing `gso.products.product_types.edge_port`."""
 
     node: str
     service_type: EdgePortType
diff --git a/gso/products/__init__.py b/gso/products/__init__.py
index 88552bc719940b2a95aaed3421c86d1f322566b6..f614447707e9180b18e74d1e3e530c8fd0c04c57 100644
--- a/gso/products/__init__.py
+++ b/gso/products/__init__.py
@@ -1,8 +1,8 @@
 """Module that updates the domain model of GSO. Should contain all types of subscriptions.
 
-.. warning::
-   Whenever a new product is added, this should be reflected in the `ProductType` enumerator.
-   This does not hold for adding a new type of already existing product.
+!!! warning
+    Whenever a new product is added, this should be reflected in the `ProductType` enumerator.
+    This does not hold for adding a new type of already existing product.
 """
 
 from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY
diff --git a/gso/products/product_blocks/bgp_session.py b/gso/products/product_blocks/bgp_session.py
index 8113654ae2304be9ee1d265630925508b8eb1be3..863a2da0ac904a5522b58fb15e048c9ee013173b 100644
--- a/gso/products/product_blocks/bgp_session.py
+++ b/gso/products/product_blocks/bgp_session.py
@@ -14,9 +14,13 @@ class IPFamily(strEnum):
     """Possible IP families of a BGP peering."""
 
     V4UNICAST = "ipv4"
+    """Unicast IPv4"""
     V6UNICAST = "ipv6"
+    """Unicast IPv6"""
     V4MULTICAST = "mcast-ipv4"
+    """Multicast IPv4"""
     V6MULTICAST = "mcast-ipv6"
+    """Multicast IPv6"""
 
 
 @strawberry.enum
@@ -24,11 +28,13 @@ class IPTypes(strEnum):
     """Possible IP types of a BGP peering."""
 
     IPV4 = "ipv4"
+    """IPv4"""
     IPV6 = "ipv6"
+    """IPv6"""
 
 
 class BGPSessionInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="BGPSession"):
-    """A BGP session that is currently inactive. See ``BGPSession``."""
+    """A BGP session that is currently inactive. See `BGPSession`."""
 
     peer_address: IPAddress | None = None
     families: list[IPFamily] = Field(default_factory=list)
@@ -45,7 +51,7 @@ class BGPSessionInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INI
 
 
 class BGPSessionProvisioning(BGPSessionInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A BGP session that is currently being provisioned. See ``BGPSession``."""
+    """A BGP session that is currently being provisioned. See `BGPSession`."""
 
     peer_address: IPAddress
     families: list[IPFamily]
@@ -62,29 +68,32 @@ class BGPSessionProvisioning(BGPSessionInactive, lifecycle=[SubscriptionLifecycl
 
 
 class BGPSession(BGPSessionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A BGP session that is currently deployed in the network."""
+    """A BGP session that is currently deployed in the network.
+
+    Attributes:
+        peer_address: The peering address of the session.
+        families: The list of IP families enabled for this session.
+        has_custom_policies: Whether any custom policies exist for this session.
+        authentication_key: The authentication key of the BGP session.
+        multipath_enabled: Whether multi-path is enabled.
+        send_default_route: Whether we send a last resort route.
+        is_multi_hop: Whether this session is multi-hop or not. Defaults to no.
+        is_passive: Whether this is a passive session.
+        rtbh_enabled: Whether Remote Triggered Blackhole is enabled.
+        bfd_enabled: Settings for BFD.
+        ip_type: The IP type of the session.
+        prefix_limit: A prefix limit, if required.
+    """
 
-    #: The peering address of the session.
     peer_address: IPAddress
-    #: The list of IP families enabled for this session.
     families: list[IPFamily]
-    #: Whether any custom policies exist for this session.
     has_custom_policies: bool
-    #: The authentication key of the BGP session.
     authentication_key: str | None
-    #: Whether multi-path is enabled.
     multipath_enabled: bool
-    #: Whether we send a last resort route.
     send_default_route: bool
-    #: Whether this session is multi-hop or not. Defaults to no.
     is_multi_hop: bool
-    #: Whether this is a passive session.
     is_passive: bool
-    #: Whether Remote Triggered Blackhole is enabled
     rtbh_enabled: bool
-    #: Settings for BFD.
     bfd_enabled: bool
-    #: The IP type of the session.
     ip_type: IPTypes
-    #: A prefix limit, if required
     prefix_limit: NonNegativeInt | None
diff --git a/gso/products/product_blocks/edge_port.py b/gso/products/product_blocks/edge_port.py
index 8f5c4bb1b32926639688b48e853d670de4a0734c..d7249d34bbfa6410834a28b0770ce6b1e3c6a08d 100644
--- a/gso/products/product_blocks/edge_port.py
+++ b/gso/products/product_blocks/edge_port.py
@@ -12,16 +12,14 @@ from gso.utils.types.interfaces import LAGMemberList, PhysicalPortCapacity
 
 
 class EncapsulationType(strEnum):
-    """Types of encapsulation for edge ports.
-
-    Null supports a single service on the port.
-    Dot1Q supports multiple services for one customer or services for multiple customers.
-    QinQ expands VLAN space by double-tagging frames.
-    """
+    """Types of encapsulation for edge ports."""
 
     DOT1Q = "dot1q"
+    """Dot1Q supports multiple services for one customer or services for multiple customers."""
     QINQ = "qinq"
+    """QinQ expands VLAN space by double-tagging frames."""
     NULL = "null"
+    """Null supports a single service on the port."""
 
 
 class EdgePortType(strEnum):
@@ -94,29 +92,32 @@ class EdgePortBlockProvisioning(EdgePortBlockInactive, lifecycle=[SubscriptionLi
 
 
 class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An edge port that's currently deployed in the network."""
+    """An edge port that's currently deployed in the network.
+
+    Attributes:
+        node: The router that this Edge Port is connected to.
+        edge_port_name: The name of the edge port, in our case, corresponds to the name of the LAG interface.
+        edge_port_description: A description of the edge port.
+        enable_lacp: Indicates whether LACP is enabled for this edge port.
+        encapsulation: The type of encapsulation used on this edge port, by default DOT1Q.
+        mac_address: The MAC address assigned to this edge port, if applicable.
+        member_speed: The speed capacity of each member in the physical port.
+        minimum_links: The minimum number of links required for this edge port.
+        edge_port_type: The type of edge port (e.g., customer, private, public).
+        ignore_if_down: If set to True, the edge port will be ignored if it is down.
+        ga_id: The GEANT GA ID associated with this edge port, if any.
+        edge_port_ae_members: A list of LAG members associated with this edge port.
+    """
 
-    #: The router that this edge port is connected to.
     node: RouterBlock
-    #: The name of the edge port, in our case, corresponds to the name of the LAG interface.
     edge_port_name: str
-    #: A description of the edge port.
     edge_port_description: str | None = None
-    #: Indicates whether LACP is enabled for this edge port.
     enable_lacp: bool
-    #: The type of encapsulation used on this edge port, by default DOT1Q.
     encapsulation: EncapsulationType = EncapsulationType.DOT1Q
-    #: The MAC address assigned to this edge port, if applicable.
     mac_address: str | None = None
-    #: The speed capacity of each member in the physical port.
     member_speed: PhysicalPortCapacity
-    #: The minimum number of links required for this edge port.
     minimum_links: int | None = None
-    #: The type of edge port (e.g., customer, private, public).
     edge_port_type: EdgePortType
-    #: If set to True, the edge port will be ignored if it is down.
     ignore_if_down: bool = False
-    #: The GEANT GA ID associated with this edge port, if any.
     ga_id: str | None = None
-    #: A list of LAG members associated with this edge port.
     edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlock]  # type: ignore[assignment]
diff --git a/gso/products/product_blocks/iptrunk.py b/gso/products/product_blocks/iptrunk.py
index 9ffaa7881826325950d2cd0a08b2ed03bcc9c4a0..785d0550a009e71d13cdaa013a224c774b4be0c7 100644
--- a/gso/products/product_blocks/iptrunk.py
+++ b/gso/products/product_blocks/iptrunk.py
@@ -94,7 +94,7 @@ class IptrunkBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="IptrunkBlock",
 ):
-    """A trunk that's currently inactive, see ``IptrunkBlock``."""
+    """A trunk that's currently inactive, see `IptrunkBlock`."""
 
     gs_id: str | None = None
     iptrunk_description: str | None = None
@@ -108,7 +108,7 @@ class IptrunkBlockInactive(
 
 
 class IptrunkBlockProvisioning(IptrunkBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A trunk that's currently being provisioned, see ``IptrunkBlock``."""
+    """A trunk that's currently being provisioned, see `IptrunkBlock`."""
 
     gs_id: str | None = None
     iptrunk_description: str | None = None
@@ -122,23 +122,26 @@ class IptrunkBlockProvisioning(IptrunkBlockInactive, lifecycle=[SubscriptionLife
 
 
 class IptrunkBlock(IptrunkBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A trunk that's currently deployed in the network."""
+    """A trunk that's currently deployed in the network.
+
+    Attributes:
+        gs_id: GÉANT service ID associated with this trunk.
+        iptrunk_description: A human-readable description of this trunk.
+        iptrunk_type: The type of trunk, can be either dark fibre or leased capacity.
+        iptrunk_speed: The speed of the trunk, measured per interface associated with it.
+        iptrunk_minimum_links: The minimum amount of links the trunk should consist of.
+        iptrunk_isis_metric: The ISIS metric of this link.
+        iptrunk_ipv4_network: The IPv4 network used for this trunk.
+        iptrunk_ipv6_network: The IPv6 network used for this trunk.
+        iptrunk_sides: The two sides that the trunk is connected to.
+    """
 
-    #:  GÉANT service ID associated with this trunk.
     gs_id: str | None = None
-    #:  A human-readable description of this trunk.
     iptrunk_description: str | None = None
-    #:  The type of trunk, can be either dark fibre or leased capacity.
     iptrunk_type: IptrunkType
-    #:  The speed of the trunk, measured per interface associated with it.
     iptrunk_speed: PhysicalPortCapacity
-    #:  The minimum amount of links the trunk should consist of.
     iptrunk_minimum_links: int
-    #:  The ISIS metric of this link
     iptrunk_isis_metric: int
-    #:  The IPv4 network used for this trunk.
     iptrunk_ipv4_network: ipaddress.IPv4Network
-    #:  The IPv6 network used for this trunk.
     iptrunk_ipv6_network: ipaddress.IPv6Network
-    #:  The two sides that the trunk is connected to.
     iptrunk_sides: IptrunkSides[IptrunkSideBlock]  # type: ignore[assignment]
diff --git a/gso/products/product_blocks/l3_core_service.py b/gso/products/product_blocks/l3_core_service.py
index 129b94778d5a170e6869099aa4434629e82ce335..ce2db1782410311e8d37f34d4b92cd27abed8d01 100644
--- a/gso/products/product_blocks/l3_core_service.py
+++ b/gso/products/product_blocks/l3_core_service.py
@@ -27,11 +27,14 @@ class AccessPortProvisioning(AccessPortInactive, lifecycle=[SubscriptionLifecycl
 
 
 class AccessPort(AccessPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An access port for an R&E service."""
+    """An access port for an R&E service.
+
+    Attributes:
+        ap_type: The type of Access Port
+        sbp: The corresponding SBP of this Access Port.
+    """
 
-    #: The type of Access Port
     ap_type: APType
-    #: The corresponding SBP of this Access Port.
     sbp: ServiceBindingPort
 
 
@@ -50,7 +53,10 @@ class L3CoreServiceBlockProvisioning(L3CoreServiceBlockInactive, lifecycle=[Subs
 
 
 class L3CoreServiceBlock(L3CoreServiceBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An active L3 Core Service subscription block."""
+    """An active L3 Core Service subscription block.
+
+    Attributes:
+        ap_list: The list of Access Points where this service is present.
+    """
 
-    #: The list of Access Points where this service is present.
     ap_list: list[AccessPort]  # type: ignore[assignment]
diff --git a/gso/products/product_blocks/lan_switch_interconnect.py b/gso/products/product_blocks/lan_switch_interconnect.py
index b62156afb2fea7bea50651173e8cb85b8380e534..624f40152f747c61911e06a57cdbb50ef26dcc75 100644
--- a/gso/products/product_blocks/lan_switch_interconnect.py
+++ b/gso/products/product_blocks/lan_switch_interconnect.py
@@ -131,17 +131,21 @@ class LanSwitchInterconnectBlockProvisioning(
 
 
 class LanSwitchInterconnectBlock(LanSwitchInterconnectBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A LAN Switch Interconnect that's currently deployed in the network."""
+    """A LAN Switch Interconnect that's currently deployed in the network.
+
+    Attributes:
+        lan_switch_interconnect_description: A human-readable description of this LAN Switch Interconnect.
+        minimum_links: The minimum amount of links the LAN Switch Interconnect should consist of.
+        switch_management_vlan_id: VLAN ID for the switch management network.
+        dcn_management_vlan_id: VLAN ID for the DCN management network, if the site of this product contains optical
+            equipment.
+        router_side: The router side of the LAN Switch Interconnect.
+        switch_side: The switch side of the LAN Switch Interconnect.
+    """
 
-    #: A human-readable description of this LAN Switch Interconnect.
     lan_switch_interconnect_description: str
-    #: The minimum amount of links the LAN Switch Interconnect should consist of.
     minimum_links: int
-    #: VLAN ID for the switch management network.
     switch_management_vlan_id: VLAN_ID
-    #: VLAN ID for the DCN management network, if the site of this product contains optical equipment.
     dcn_management_vlan_id: VLAN_ID | None
-    #: The router side of the LAN Switch Interconnect.
     router_side: LanSwitchInterconnectRouterSideBlock
-    #: The switch side of the LAN Switch Interconnect.
     switch_side: LanSwitchInterconnectSwitchSideBlock
diff --git a/gso/products/product_blocks/layer_2_circuit.py b/gso/products/product_blocks/layer_2_circuit.py
index 40968dfea10be3dc5ab4204fe7dd258c3a8f2194..2e1a7c53b7a995efedc6c09377ef19f4d2ee158b 100644
--- a/gso/products/product_blocks/layer_2_circuit.py
+++ b/gso/products/product_blocks/layer_2_circuit.py
@@ -95,21 +95,24 @@ class Layer2CircuitBlockProvisioning(Layer2CircuitBlockInactive, lifecycle=[Subs
 
 
 class Layer2CircuitBlock(Layer2CircuitBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An active Layer 2 Circuit."""
+    """An active Layer 2 Circuit.
+
+    Attributes:
+        layer_2_circuit_sides: The two sides that the Layer 2 Circuit is connected to.
+        virtual_circuit_id: Virtual Circuit ID of this Layer 2 Circuit.
+        layer_2_circuit_type: The type of circuit, can be tagged or untagged.
+        vlan_range_lower_bound: If tagged, the lower and upper bounds will set the VLAN range.
+        vlan_range_upper_bound: Lower and Upper bounds are including.
+        policer_enabled: Whether this Layer 2 Circuit is policed.
+        policer_burst_rate: If policed, the burst rate of the policer.
+        bandwidth: If policed, the bandwidth of the policer is stored.
+    """
 
-    #: The two sides that the Layer 2 Circuit is connected to.
     layer_2_circuit_sides: Layer2CircuitSides[Layer2CircuitSideBlock]
-    #: Virtual Circuit ID of this Layer 2 Circuit.
     virtual_circuit_id: VC_ID
-    #: The type of circuit, can be tagged or untagged.
     layer_2_circuit_type: Layer2CircuitType
-    #: If tagged, the lower and upper bounds will set the VLAN range.
     vlan_range_lower_bound: VLAN_ID | None
-    #: Lower and Upper bounds are including.
     vlan_range_upper_bound: VLAN_ID | None
-    #: Whether this Layer 2 Circuit is policed.
     policer_enabled: bool
-    #: If policed, the burst rate of the policer
     policer_burst_rate: BandwidthString | None
-    #: If policed, the bandwidth of the policer is stored.
     bandwidth: BandwidthString | None
diff --git a/gso/products/product_blocks/office_router.py b/gso/products/product_blocks/office_router.py
index 0a16b4f43a27b385b9b3dc051feaf4fcf626ad78..8afb980971849a40619ac5a357e2e05f0bbf4673 100644
--- a/gso/products/product_blocks/office_router.py
+++ b/gso/products/product_blocks/office_router.py
@@ -17,39 +17,43 @@ class OfficeRouterBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="OfficeRouterBlock",
 ):
-    """An office router that's being currently inactive. See ``OfficeRouterBlock``."""
+    """An office router that's being currently inactive. See `OfficeRouterBlock`."""
 
     office_router_fqdn: str | None = None
     office_router_ts_port: PortNumber | None = None
     office_router_lo_ipv4_address: IPv4AddressType | None = None
     office_router_lo_ipv6_address: IPv6AddressType | None = None
     office_router_site: SiteBlockInactive | None
-    vendor: Vendor | None = None
+    vendor: Vendor | None = Vendor.JUNIPER
 
 
 class OfficeRouterBlockProvisioning(OfficeRouterBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """An office router that's being provisioned. See ``RouterBlock``."""
+    """An office router that's being provisioned. See `RouterBlock`."""
 
-    office_router_fqdn: str | None = None
-    office_router_ts_port: PortNumber | None = None
-    office_router_lo_ipv4_address: IPv4AddressType | None = None
-    office_router_lo_ipv6_address: IPv6AddressType | None = None
+    office_router_fqdn: str | None
+    office_router_ts_port: PortNumber | None
+    office_router_lo_ipv4_address: IPv4AddressType | None
+    office_router_lo_ipv6_address: IPv6AddressType | None
     office_router_site: SiteBlockProvisioning | None
-    vendor: Vendor | None = None
+    vendor: Vendor
 
 
 class OfficeRouterBlock(OfficeRouterBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An office router that's currently deployed in the network."""
+    """An office router that's currently deployed in the network.
+
+    Attributes:
+        office_router_fqdn: Office router FQDN.
+        office_router_ts_port: The port of the terminal server that this office router is connected to. Used to offer
+            out of band access.
+        office_router_lo_ipv4_address: The IPv4 loopback address of the office router.
+        office_router_lo_ipv6_address: The IPv6 loopback address of the office router.
+        office_router_site: The `Site` that this office router resides in. Both physically and computationally.
+        vendor: The vendor of an office router. Defaults to Juniper.
+    """
 
-    #:  Office router FQDN.
     office_router_fqdn: str
-    #:  The port of the terminal server that this office router is connected to. Used to offer out of band access.
     office_router_ts_port: PortNumber
-    #:  The IPv4 loopback address of the office router.
     office_router_lo_ipv4_address: IPv4AddressType
-    #:  The IPv6 loopback address of the office router.
     office_router_lo_ipv6_address: IPv6AddressType
-    #:  The ``Site`` that this office router resides in. Both physically and computationally.
     office_router_site: SiteBlock
-    #:  The vendor of an office router. Defaults to Juniper.
-    vendor: Vendor = Vendor.JUNIPER
+    vendor: Vendor
diff --git a/gso/products/product_blocks/opengear.py b/gso/products/product_blocks/opengear.py
index 8fd88b31718c5cf255462a3af45be586ca0e6497..0daca4899edda40c51fe39a926284e83d007c918 100644
--- a/gso/products/product_blocks/opengear.py
+++ b/gso/products/product_blocks/opengear.py
@@ -1,4 +1,4 @@
-"""Product block for ``Opengear`` products."""
+"""Product block for `Opengear` products."""
 
 import ipaddress
 
@@ -17,7 +17,7 @@ class OpengearBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="OpengearBlock",
 ):
-    """An Opengear that's being currently inactive. See ``OpengearBlock``."""
+    """An Opengear that's being currently inactive. See `OpengearBlock`."""
 
     opengear_hostname: str | None = None
     opengear_site: SiteBlockInactive | None = None
@@ -27,25 +27,28 @@ class OpengearBlockInactive(
 
 
 class OpengearBlockProvisioning(OpengearBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """An Opengear that's being provisioned. See ``OpengearBlock``."""
+    """An Opengear that's being provisioned. See `OpengearBlock`."""
 
     opengear_hostname: str
     opengear_site: SiteBlockProvisioning
-    opengear_wan_address: ipaddress.IPv4Address | None = None
-    opengear_wan_netmask: ipaddress.IPv4Address | None = None
-    opengear_wan_gateway: ipaddress.IPv4Address | None = None
+    opengear_wan_address: ipaddress.IPv4Address | None
+    opengear_wan_netmask: ipaddress.IPv4Address | None
+    opengear_wan_gateway: ipaddress.IPv4Address | None
 
 
 class OpengearBlock(OpengearBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """An Opengear that's currently deployed in the network."""
+    """An Opengear that's currently deployed in the network.
+
+    Attributes:
+        opengear_hostname: The hostname of the Opengear device.
+        opengear_site: The site where the Opengear device is located.
+        opengear_wan_address: The WAN address of the Opengear device.
+        opengear_wan_netmask: The WAN netmask of the Opengear device.
+        opengear_wan_gateway: The WAN gateway of the Opengear device.
+    """
 
-    #: The hostname of the Opengear device.
     opengear_hostname: str
-    #: The site where the Opengear device is located.
     opengear_site: SiteBlock
-    #: The WAN address of the Opengear device.
     opengear_wan_address: ipaddress.IPv4Address
-    #: The WAN netmask of the Opengear device.
     opengear_wan_netmask: ipaddress.IPv4Address
-    #: The WAN gateway of the Opengear device.
     opengear_wan_gateway: ipaddress.IPv4Address
diff --git a/gso/products/product_blocks/pop_vlan.py b/gso/products/product_blocks/pop_vlan.py
index f4ee9c4030171932fef89e2c1c0d7e2a3511de25..a26e072d11089a0ecadbcfbc7b7cb75cdedffde7 100644
--- a/gso/products/product_blocks/pop_vlan.py
+++ b/gso/products/product_blocks/pop_vlan.py
@@ -60,7 +60,7 @@ class PopVlanBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="PopVlanBlock",
 ):
-    """A PoP VLAN that's currently inactive, see ``PopVlanBlock``."""
+    """A PoP VLAN that's currently inactive, see `PopVlanBlock`."""
 
     vlan_id: int
     pop_vlan_description: str | None = None
@@ -72,7 +72,7 @@ class PopVlanBlockInactive(
 
 
 class PopVlanBlockProvisioning(PopVlanBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A Pop VLAN that's currently being provisioned, see ``PopVlanBlock``."""
+    """A Pop VLAN that's currently being provisioned, see `PopVlanBlock`."""
 
     vlan_id: int
     pop_vlan_description: str | None
@@ -84,19 +84,22 @@ class PopVlanBlockProvisioning(PopVlanBlockInactive, lifecycle=[SubscriptionLife
 
 
 class PopVlanBlock(PopVlanBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A Pop VLAN that's currently deployed in the network."""
+    """A Pop VLAN that's currently deployed in the network.
+
+    Attributes:
+        vlan_id: The VLAN ID of the Pop VLAN.
+        pop_vlan_description: The description of the Pop VLAN.
+        lan_switch_interconnect: The LAN Switch Interconnect that this Pop VLAN is connected to.
+        ports: The ports of the Pop VLAN.
+        layer_preference: The level of the layer preference for the Pop VLAN (L2 or L3).
+        ipv4_network: IPv4 network for the Pop VLAN if layer preference is L3.
+        ipv6_network: IPv6 network for the Pop VLAN if layer preference is L3.
+    """
 
-    #: The VLAN ID of the Pop VLAN.
     vlan_id: int
-    #: The description of the Pop VLAN.
     pop_vlan_description: str
-    #: The LAN Switch Interconnect that this Pop VLAN is connected to.
     lan_switch_interconnect: LanSwitchInterconnectBlock
-    #: The ports of the Pop VLAN.
     ports: PortList[PopVlanPortBlock]  # type: ignore[assignment]
-    #: The level of the layer preference for the Pop VLAN (L2 or L3).
     layer_preference: LayerPreference
-    #: IPv4 network for the Pop VLAN if layer preference is L3.
     ipv4_network: IPv4Network | None
-    #: IPv6 network for the Pop VLAN if layer preference is L3.
     ipv6_network: IPv6Network | None
diff --git a/gso/products/product_blocks/router.py b/gso/products/product_blocks/router.py
index 5ffc2ef98cb1a10f22e27b9d52d61e941fb2715a..d31d2109aae8b2bc95c876777faa53c46c668d83 100644
--- a/gso/products/product_blocks/router.py
+++ b/gso/products/product_blocks/router.py
@@ -1,4 +1,4 @@
-"""Product block for ``Router`` products."""
+"""Product block for `Router` products."""
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle, strEnum
@@ -25,7 +25,7 @@ class RouterBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="RouterBlock",
 ):
-    """A router that's being currently inactive. See ``RouterBlock``."""
+    """A router that's being currently inactive. See `RouterBlock`."""
 
     router_fqdn: str | None = None
     router_ts_port: PortNumber | None = None
@@ -39,7 +39,7 @@ class RouterBlockInactive(
 
 
 class RouterBlockProvisioning(RouterBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A router that's being provisioned. See ``RouterBlock``."""
+    """A router that's being provisioned. See `RouterBlock`."""
 
     router_fqdn: str
     router_ts_port: PortNumber
@@ -53,23 +53,28 @@ class RouterBlockProvisioning(RouterBlockInactive, lifecycle=[SubscriptionLifecy
 
 
 class RouterBlock(RouterBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A router that's currently deployed in the network."""
+    """A router that's currently deployed in the network.
+
+    Attributes:
+        router_fqdn: FQDN of a router.
+        router_ts_port: The port of the terminal server that this router is connected to. Used to offer out of band
+            access.
+        router_access_via_ts: Whether this router should be accessed through the terminal server, or through its
+            loopback address.
+        router_lo_ipv4_address: The IPv4 loopback address of the router.
+        router_lo_ipv6_address: The IPv6 loopback address of the router.
+        router_lo_iso_address: The ISO NET of the router, used for ISIS support.
+        router_role: The role of the router, which can be any of the values defined in `RouterRole`.
+        router_site: The site that this router resides in. Both physically and computationally.
+        vendor: The vendor of a router.
+    """
 
-    #:  FQDN of a router.
     router_fqdn: str
-    #:  The port of the terminal server that this router is connected to. Used to offer out of band access.
     router_ts_port: PortNumber
-    #:  Whether this router should be accessed through the terminal server, or through its loopback address.
     router_access_via_ts: bool
-    #:  The IPv4 loopback address of the router.
     router_lo_ipv4_address: IPv4AddressType
-    #:  The IPv6 loopback address of the router.
     router_lo_ipv6_address: IPv6AddressType
-    #:  The ISO NET of the router, used for ISIS support.
     router_lo_iso_address: str
-    #:  The role of the router, which can be any of the values defined in ``RouterRole``.
     router_role: RouterRole
-    #:  The ``Site`` that this router resides in. Both physically and computationally.
     router_site: SiteBlock
-    #:  The vendor of a router.
     vendor: Vendor
diff --git a/gso/products/product_blocks/service_binding_port.py b/gso/products/product_blocks/service_binding_port.py
index 6d736f56b29919190122f67155823d0b3bfdad0a..5eaec9af013f851496d3c473a81cac5331013511 100644
--- a/gso/products/product_blocks/service_binding_port.py
+++ b/gso/products/product_blocks/service_binding_port.py
@@ -21,7 +21,7 @@ from gso.utils.types.virtual_identifiers import VLAN_ID
 class BFDSettingsInactive(
     ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="BFDSettings"
 ):
-    """Settings for BFD, see ``BFDSettings``."""
+    """Settings for BFD, see `BFDSettings`."""
 
     bfd_enabled: bool = False
     bfd_interval_rx: int | None = None
@@ -30,7 +30,7 @@ class BFDSettingsInactive(
 
 
 class BFDSettingsProvisioning(BFDSettingsInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """Settings for BFD, see ``BFDSettings``."""
+    """Settings for BFD, see `BFDSettings`."""
 
     bfd_enabled: bool
     bfd_interval_rx: int | None = None
@@ -39,22 +39,25 @@ class BFDSettingsProvisioning(BFDSettingsInactive, lifecycle=[SubscriptionLifecy
 
 
 class BFDSettings(BFDSettingsProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A set of settings for BFD."""
+    """A set of settings for BFD.
+
+    Attributes:
+        bfd_enabled: Whether BFD is enabled.
+        bfd_interval_rx: The BFD interval RX, if enabled.
+        bfd_interval_tx: The BFD interval TX, if enabled.
+        bfd_multiplier: The BFD multiplier, if enabled.
+    """
 
-    #: Whether BFD is enabled.
     bfd_enabled: bool
-    #: The BFD interval RX, if enabled.
     bfd_interval_rx: int | None
-    #: The BFD interval TX, if enabled.
     bfd_interval_tx: int | None
-    #: The BFD multiplier, if enabled.
     bfd_multiplier: int | None
 
 
 class ServiceBindingPortInactive(
     ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="ServiceBindingPort"
 ):
-    """A Service Binding Port that's currently inactive. See ``ServiceBindingPort``."""
+    """A Service Binding Port that's currently inactive. See `ServiceBindingPort`."""
 
     is_tagged: bool | None = None
     vlan_id: VLAN_ID | None = None
@@ -72,7 +75,7 @@ class ServiceBindingPortInactive(
 
 
 class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A Service Binding Port that's currently being provisioned. See ``ServiceBindingPort``."""
+    """A Service Binding Port that's currently being provisioned. See `ServiceBindingPort`."""
 
     is_tagged: bool
     vlan_id: VLAN_ID | None = None
@@ -90,31 +93,34 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs
 
 
 class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A service binding port that is actively used in the network."""
+    """A service binding port that is actively used in the network.
+
+    Attributes:
+        is_tagged: Whether this VLAN is tagged or not.
+        vlan_id: The VLAN ID.
+        sbp_type: Is this service binding port layer 2 or 3?
+        ipv4_address: If layer 3, IPv4 resources.
+        ipv4_mask: IPv4 subnet mask.
+        ipv6_address: If layer 3, IPv6 resources.
+        ipv6_mask: IPv6 subnet mask.
+        custom_firewall_filters: Any custom firewall filters that the partner may require.
+        gs_id: The GÉANT service ID of this binding port.
+        bgp_session_list: The BGP sessions associated with this service binding port.
+        edge_port: The Edge Port on which this SBP resides.
+        v4_bfd_settings: BFD settings for IPv4.
+        v6_bfd_settings: BFD settings for IPv6.
+    """
 
-    #: Whether this VLAN is tagged or not.
     is_tagged: bool
-    #: The VLAN ID.
     vlan_id: VLAN_ID | None = None
-    #: Is this service binding port layer 2 or 3?
     sbp_type: SBPType
-    #: If layer 3, IPv4 resources.
     ipv4_address: IPv4AddressType | None = None
-    #: IPV4 subnet mask.
     ipv4_mask: IPv4Netmask | None = None
-    #: If layer 3, IPv6 resources.
     ipv6_address: IPv6AddressType | None = None
-    #: IPV6 subnet mask.
     ipv6_mask: IPv6Netmask | None = None
-    #: Any custom firewall filters that the partner may require.
     custom_firewall_filters: bool
-    #: The GÉANT service ID of this binding port.
     gs_id: str
-    #: The BGP sessions associated with this service binding port.
     bgp_session_list: list[BGPSession]  # type: ignore[assignment]
-    #: The Edge Port on which this SBP resides.
     edge_port: EdgePortBlock
-    #: BFD settings for IPv4
     v4_bfd_settings: BFDSettings
-    #: BFD settings for IPv6
     v6_bfd_settings: BFDSettings
diff --git a/gso/products/product_blocks/site.py b/gso/products/product_blocks/site.py
index 871707b4dc806b8a534fb003edd28e34946b79bc..22cc4940094ca50d494bc90507466a57b125e299 100644
--- a/gso/products/product_blocks/site.py
+++ b/gso/products/product_blocks/site.py
@@ -26,7 +26,7 @@ class SiteBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="SiteBlock",
 ):
-    """A site that's currently inactive, see ``SiteBlock``."""
+    """A site that's currently inactive, see `SiteBlock`."""
 
     site_name: SiteName | None = None
     site_city: str | None = None
@@ -42,7 +42,7 @@ class SiteBlockInactive(
 
 
 class SiteBlockProvisioning(SiteBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A site that's currently being provisioned, see ``SiteBlock``."""
+    """A site that's currently being provisioned, see `SiteBlock`."""
 
     site_name: SiteName
     site_city: str
@@ -58,31 +58,35 @@ class SiteBlockProvisioning(SiteBlockInactive, lifecycle=[SubscriptionLifecycle.
 
 
 class SiteBlock(SiteBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A site that's currently available for routers and services to be hosted at."""
+    """A site that's currently available for routers and services to be hosted at.
+
+    Attributes:
+        site_name: The name of the site, that will dictate part of the FQDN of routers that are hosted at this site. For
+            example: `router.X.Y.geant.net`, where X denotes the name of the site.
+        site_city: The city at which the site is located.
+        site_country: The country in which the site is located.
+        site_country_code: The code of the corresponding country. This is also used for the FQDN, following the example
+            given for the site name, the country code would end up in the Y position.
+        site_latitude: The latitude of the site, used for SNMP purposes.
+        site_longitude: Similar to the latitude, the longitude of a site.
+        site_internal_id: The internal ID used within GÉANT to denote a site.
+        site_bgp_community_id: The BGP community ID of a site, used to advertise routes learned at this site.
+        site_tier: The tier of a site, as described in `SiteTier`.
+        site_ts_address: The address of the terminal server that this router is connected to. The terminal server
+            provides out of band access. This is required in case a link goes down, or when a router is initially added
+            to the network, and it does not have any IP trunks connected to it.
+        site_contains_optical_equipment: Whether this site contains optical equipment, which dictates the need for a DCN
+            management VLAN.
+    """
 
-    #:  The name of the site, that will dictate part of the FQDN of routers that are hosted at this site. For
-    #:  example: ``router.X.Y.geant.net``, where X denotes the name of the site.
     site_name: SiteName
-    #:  The city at which the site is located.
     site_city: str
-    #:  The country in which the site is located.
     site_country: str
-    #:  The code of the corresponding country. This is also used for the FQDN, following the example given for
-    #:  the site name, the country code would end up in the Y position.
     site_country_code: str
-    #:  The latitude of the site, used for SNMP purposes.
     site_latitude: LatitudeCoordinate
-    #:  Similar to the latitude, the longitude of a site.
     site_longitude: LongitudeCoordinate
-    #:  The internal ID used within GÉANT to denote a site.
     site_internal_id: int
-    #:  The BGP community ID of a site, used to advertise routes learned at this site.
     site_bgp_community_id: int
-    #:  The tier of a site, as described in ``SiteTier``.
     site_tier: SiteTier
-    #:  The address of the terminal server that this router is connected to. The terminal server provides out of band
-    #:  access. This is required in case a link goes down, or when a router is initially added to the network and it
-    #:  does not have any IP trunks connected to it.
     site_ts_address: IPAddress
-    #:  Whether this site contains optical equipment, which dictates the need for a DCN management VLAN
     site_contains_optical_equipment: bool
diff --git a/gso/products/product_blocks/super_pop_switch.py b/gso/products/product_blocks/super_pop_switch.py
index 63f161921a030a8787d881ac4a02b2032b9c342a..3c436e071b0d0f86d6f5264be637e733532a1b25 100644
--- a/gso/products/product_blocks/super_pop_switch.py
+++ b/gso/products/product_blocks/super_pop_switch.py
@@ -17,35 +17,39 @@ class SuperPopSwitchBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="SuperPopSwitchBlock",
 ):
-    """A Super PoP switch that's being currently inactive. See ``SuperPoPSwitchBlock``."""
+    """A Super PoP switch that's being currently inactive. See `SuperPoPSwitchBlock`."""
 
     super_pop_switch_fqdn: str | None = None
     super_pop_switch_ts_port: PortNumber | None = None
     super_pop_switch_mgmt_ipv4_address: IPv4AddressType | None = None
     super_pop_switch_site: SiteBlockInactive | None
-    vendor: Vendor | None = None
+    vendor: Vendor | None = Vendor.JUNIPER
 
 
 class SuperPopSwitchBlockProvisioning(SuperPopSwitchBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A Super PoP switch that's being provisioned. See ``SuperPoPSwitchBlock``."""
+    """A Super PoP switch that's being provisioned. See `SuperPoPSwitchBlock`."""
 
-    super_pop_switch_fqdn: str | None = None
-    super_pop_switch_ts_port: PortNumber | None = None
-    super_pop_switch_mgmt_ipv4_address: IPv4AddressType | None = None
+    super_pop_switch_fqdn: str | None
+    super_pop_switch_ts_port: PortNumber | None
+    super_pop_switch_mgmt_ipv4_address: IPv4AddressType | None
     super_pop_switch_site: SiteBlockProvisioning | None
-    vendor: Vendor | None = None
+    vendor: Vendor | None
 
 
 class SuperPopSwitchBlock(SuperPopSwitchBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A Super PoP switch that's currently deployed in the network."""
+    """A Super PoP switch that's currently deployed in the network.
+
+    Attributes:
+        super_pop_switch_fqdn: Super PoP switch FQDN.
+        super_pop_switch_ts_port: The port of the terminal server that this Super PoP switch is connected to. Used to
+            offer out of band access.
+        super_pop_switch_mgmt_ipv4_address: The IPv4 management address of the Super PoP switch.
+        super_pop_switch_site: The `Site` that this Super PoP switch resides in. Both physically and computationally.
+        vendor: The vendor of a Super PoP switch. Defaults to Juniper.
+    """
 
-    #:  Super PoP switch FQDN.
     super_pop_switch_fqdn: str
-    #:  The port of the terminal server that this Super PoP switch is connected to. Used to offer out of band access.
     super_pop_switch_ts_port: PortNumber
-    #:  The IPv4 management address of the Super PoP switch.
     super_pop_switch_mgmt_ipv4_address: IPv4AddressType
-    #:  The ``Site`` that this Super PoP switch resides in. Both physically and computationally.
     super_pop_switch_site: SiteBlock
-    #:  The vendor of a Super PoP switch. Defaults to Juniper.
-    vendor: Vendor = Vendor.JUNIPER
+    vendor: Vendor
diff --git a/gso/products/product_blocks/switch.py b/gso/products/product_blocks/switch.py
index abf4a797dc83d83ae77a5237e5f713736aa25897..918773269954e9850c314fea88ff8efb2fa1b452 100644
--- a/gso/products/product_blocks/switch.py
+++ b/gso/products/product_blocks/switch.py
@@ -1,4 +1,4 @@
-"""Product block for ``Switch`` products."""
+"""Product block for `Switch` products."""
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle
@@ -26,7 +26,7 @@ class SwitchBlockInactive(
     lifecycle=[SubscriptionLifecycle.INITIAL],
     product_block_name="SwitchBlock",
 ):
-    """A switch that's being currently inactive. See ``SwitchBlock``."""
+    """A switch that's being currently inactive. See `SwitchBlock`."""
 
     fqdn: str | None = None
     ts_port: PortNumber | None = None
@@ -36,7 +36,7 @@ class SwitchBlockInactive(
 
 
 class SwitchBlockProvisioning(SwitchBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A switch that's being provisioned. See ``SwitchBlock``."""
+    """A switch that's being provisioned. See `SwitchBlock`."""
 
     fqdn: str
     ts_port: PortNumber
@@ -46,15 +46,18 @@ class SwitchBlockProvisioning(SwitchBlockInactive, lifecycle=[SubscriptionLifecy
 
 
 class SwitchBlock(SwitchBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A switch that's currently deployed in the network."""
+    """A switch that's currently deployed in the network.
+
+    Attributes:
+        fqdn: The FQDN of the switch.
+        ts_port: The port of the terminal server that this switch is connected to. Used to offer out of band access.
+        site: The site that this switch resides in. Both physically and computationally.
+        switch_vendor: The vendor of the switch.
+        switch_model: The model of the switch.
+    """
 
-    #: The FQDN of the switch.
     fqdn: str
-    #:  The port of the terminal server that this switch is connected to. Used to offer out of band access.
     ts_port: PortNumber
-    #:  The ``Site`` that this switch resides in. Both physically and computationally.
     site: SiteBlock
-    #: The vendor of the switch.
     switch_vendor: Vendor
-    #: The model of the switch.
     switch_model: SwitchModel
diff --git a/gso/products/product_blocks/vrf.py b/gso/products/product_blocks/vrf.py
index 5070c48a2f0e5f35e0db64c8d4e47f8447aac19d..d53803af4960e07c006f80e65f4411c8767639c7 100644
--- a/gso/products/product_blocks/vrf.py
+++ b/gso/products/product_blocks/vrf.py
@@ -1,4 +1,4 @@
-"""Product blocks for :term:`VRF` Virtual Routing and Forwarding."""
+"""Product blocks for VRF Virtual Routing and Forwarding."""
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle
@@ -7,7 +7,7 @@ from gso.products.product_blocks.router import RouterBlock, RouterBlockInactive,
 
 
 class VRFBlockInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="VRFBlock"):
-    """An inactive :term:`VRF` subscription. See :class:`VRFBlock`."""
+    """An inactive VRF subscription. See `VRFBlock`."""
 
     vrf_router_list: list[RouterBlockInactive]
     vrf_name: str | None = None
@@ -17,7 +17,7 @@ class VRFBlockInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITI
 
 
 class VRFBlockProvisioning(VRFBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A provisioning :term:`VRF` subscription. See :class:`VRFBlock`."""
+    """A provisioning VRF subscription. See `VRFBlock`."""
 
     vrf_router_list: list[RouterBlockProvisioning]  # type: ignore[assignment]
     vrf_name: str
@@ -27,15 +27,18 @@ class VRFBlockProvisioning(VRFBlockInactive, lifecycle=[SubscriptionLifecycle.PR
 
 
 class VRFBlock(VRFBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """Represents an active :term:`VRF` subscription block."""
+    """Represents an active VRF subscription block.
+
+    Attributes:
+        vrf_router_list: List of VRF routers.
+        vrf_name: Unique name identifying this VRF.
+        route_distinguisher: Route Distinguisher ensuring unique route identification within this VRF.
+        route_target: Route Target defining routing policies for importing/exporting routes.
+        vrf_as_number: AS number of the VRF.
+    """
 
-    #: List of VRF routers
     vrf_router_list: list[RouterBlock]  # type: ignore[assignment]
-    #: Unique name identifying this VRF.
     vrf_name: str
-    #: Route Distinguisher (RD) ensuring unique route identification within this VRF.
     route_distinguisher: str
-    #: Route Target (RT) defining routing policies for importing/exporting routes.
     route_target: str
-    #: AS number of the VRF
     vrf_as_number: int | None = None
diff --git a/gso/products/product_types/vrf.py b/gso/products/product_types/vrf.py
index 348d6b922aed7d4be9936bd3749b9b7be280ee6d..653e461a3cbd7a23b93645ed5c9f7f6206e4fbc2 100644
--- a/gso/products/product_types/vrf.py
+++ b/gso/products/product_types/vrf.py
@@ -1,4 +1,4 @@
-"""A :term:`VRF` product type."""
+"""A VRF product type."""
 
 from orchestrator.domain.base import SubscriptionModel
 from orchestrator.types import SubscriptionLifecycle
@@ -7,18 +7,18 @@ from gso.products.product_blocks.vrf import VRFBlock, VRFBlockInactive, VRFBlock
 
 
 class VRFInactive(SubscriptionModel, is_base=True):
-    """An inactive :term:`VRF`."""
+    """An inactive VRF."""
 
     vrf: VRFBlockInactive
 
 
 class VRFProvisioning(VRFInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
-    """A provisioning :term:`VRF`."""
+    """A provisioning VRF."""
 
     vrf: VRFBlockProvisioning
 
 
 class VRF(VRFProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
-    """A :term:`VRF` that is currently active."""
+    """A VRF that is currently active."""
 
     vrf: VRFBlock
diff --git a/gso/schedules/scheduling.py b/gso/schedules/scheduling.py
index 508af69ec81c7c53cbfd9abe09724b8eb154d837..1f99f582ffb7f80ad1f0d497a89fe4fa85f281fa 100644
--- a/gso/schedules/scheduling.py
+++ b/gso/schedules/scheduling.py
@@ -25,11 +25,11 @@ def scheduler(cron_scheduler_config: CronScheduleConfig) -> Callable[[Callable],
     """Schedule a Celery task using crontab-like timing.
 
     Examples:
-        - ``minute='*/15'``: Run every 15 minutes.
-        - ``hour='*/3'``: Run every 3 hours.
-        - ``day_of_week='mon-fri'``: Run on weekdays only.
-        - ``day_of_month='1-7,15-21'``: Run on the first and third weeks of the month.
-        - ``month_of_year='*/3'``: Run on the first month of each quarter.
+        - `minute='*/15'`: Run every 15 minutes.
+        - `hour='*/3'`: Run every 3 hours.
+        - `day_of_week='mon-fri'`: Run on weekdays only.
+        - `day_of_month='1-7,15-21'`: Run on the first and third weeks of the month.
+        - `month_of_year='*/3'`: Run on the first month of each quarter.
 
     All time units can be specified with lists of numbers or crontab pattern strings for advanced scheduling.
     All specified time parts (minute, hour, day, etc.) must align for a task to run.
diff --git a/gso/services/infoblox.py b/gso/services/infoblox.py
index a0f5df25907aec7f248d898dfb1035078c5c1716..49ca5d3ec25e78d3b12287d24e3b62bbbdaf1116 100644
--- a/gso/services/infoblox.py
+++ b/gso/services/infoblox.py
@@ -86,7 +86,7 @@ def create_v4_network_by_ip(
     """Register an IPv4 network at the given location.
 
     Raises:
-        AllocationError on failure.
+        AllocationError: on failure.
     """
     conn, _ = _setup_connection()
     created_net = objects.NetworkV4.create(
@@ -105,7 +105,7 @@ def create_v6_network_by_ip(
     """Register an IPv6 network at the given location.
 
     Raises:
-        AllocationError on failure.
+        AllocationError: on failure.
     """
     conn, _ = _setup_connection()
     created_net = objects.NetworkV6.create(
@@ -123,9 +123,9 @@ def hostname_available(hostname: str) -> bool:
 
     Check whether Infoblox already has a ``infoblox_client.objects.HostRecord`` that matches the given hostname.
 
-    .. warning::
-       This method only checks within the Infoblox instance, and not the rest of the internet. The hostname could
-       therefore still be taken elsewhere.
+    !!! danger
+        This method only checks within the Infoblox instance, and not the rest of the internet. The hostname could
+        therefore still be taken elsewhere.
 
     Args:
         hostname: The hostname to be checked.
diff --git a/gso/services/kentik_client.py b/gso/services/kentik_client.py
index cb9c30932c271489974d5facf795e09e362352e0..86e81a0c418d251e9c385b8273706388f1f9efc6 100644
--- a/gso/services/kentik_client.py
+++ b/gso/services/kentik_client.py
@@ -62,7 +62,7 @@ class KentikClient:
         """List all devices in Kentik.
 
         Returns:
-        a list of shape ``[{**device_1}, {**device_2}, ..., {**device_n}]}``.
+        a list of shape `[{**device_1}, {**device_2}, ..., {**device_n}]}`.
         """
         return self._send_request("GET", "v5/devices")["devices"]
 
@@ -101,10 +101,8 @@ class KentikClient:
 
         If the site is not found, return an empty dict.
 
-        .. vale off
-
         Args:
-            site_slug: The name of the site, should be a three-letter slug like COR or POZ.
+            site_slug: The name of the site, should be a three-letter slug like `COR` or `POZ`.
         """
         sites = self.get_sites()
         for site in sites:
@@ -116,40 +114,42 @@ class KentikClient:
     def get_plans(self) -> list[dict[str, Any]]:
         """Get all Kentik plans available.
 
+        Returns a list of `plan` objects that each have the following shape:
+
+        <!-- vale off -->
+        ```py
+        "plan": {
+            "active": true,
+            "bgp_enabled": true,
+            "cdate" "1970-01-01T01:01:01.000Z",
+            "company_id": 111111,
+            "description": "A description of this plan",
+            "deviceTypes": [
+                {"device_type": "router"},
+                {"device_type": "host-nprobe-dns-www"}
+            ],
+            "devices": [
+                {
+                    "id": "111111",
+                    "device_name": "rt0.city.tld.internal",
+                    "device_type": "router"
+                },
+            ],
+            "edate": "2999-01-01T09:09:09.000Z",
+            "fast_retention": 10,
+            "full_retention": 5,
+            "id": 11111,
+            "max_bigdata_fps": 100,
+            "max_devices": 9001,
+            "max_fps": 200,
+            "name": "KENTIK-PLAN-01",
+            "metadata": {},
+        }
+        ```
+        <!-- vale on -->
+
         Returns:
-            a list of ``plans`` that each have the following shape:
-
-            .. vale off
-            .. code-block:: json
-
-                "plan": {
-                    "active": true,
-                    "bgp_enabled": true,
-                    "cdate" "1970-01-01T01:01:01.000Z",
-                    "company_id": 111111,
-                    "description": "A description of this plan",
-                    "deviceTypes": [
-                        {"device_type": "router"},
-                        {"device_type": "host-nprobe-dns-www"}
-                    ],
-                    "devices": [
-                        {
-                            "id": "111111",
-                            "device_name": "rt0.city.tld.internal",
-                            "device_type": "router"
-                        },
-                    ],
-                    "edate": "2999-01-01T09:09:09.000Z",
-                    "fast_retention": 10,
-                    "full_retention": 5,
-                    "id": 11111,
-                    "max_bigdata_fps": 100,
-                    "max_devices": 9001,
-                    "max_fps": 200,
-                    "name": "KENTIK-PLAN-01",
-                    "metadata": {},
-                }
-            .. vale on
+            A list of plans configured in Kentik.
         """
         return self._send_request("GET", "v5/plans")["plans"]
 
diff --git a/gso/services/lso_client.py b/gso/services/lso_client.py
index 6f5d8599822c7bf1a94b5274db55ab09e102ac92..7c6e49a28ca5d83e985037174aa0e31d0b4a5822 100644
--- a/gso/services/lso_client.py
+++ b/gso/services/lso_client.py
@@ -73,37 +73,37 @@ def _execute_playbook(
     For example, an inventory consisting of two hosts, which each a unique host variable assigned to them looks as
     follows:
 
-    .. vale off
-    .. code-block:: json
-
-        "inventory": {
-            "all": {
-                "hosts": {
-                    "host1.local": {
-                        "foo": "bar"
-                    },
-                    "host2.local": {
-                        "key": "value"
-                    },
-                    "host3.local": None
-                }
+    ```py
+    "inventory": {
+        "all": {
+            "hosts": {
+                "host1.local": {
+                    "foo": "bar"
+                },
+                "host2.local": {
+                    "key": "value"
+                },
+                "host3.local": None
             }
         }
-    .. vale on
+    }
+    ```
 
-    .. warning::
-       Note the fact that the collection of all hosts is a dictionary, and not a list of strings. Ansible expects each
-       host to be a key-value pair. The key is the FQDN of a host, and the value always ``null``.
+    !!! danger
+        Note the fact that the collection of all hosts is a dictionary, and not a list of strings. Ansible expects each
+        host to be a key-value pair. The key is the FQDN of a host, and the value always `null`.
 
     The extra vars can be a simple dict consisting of key-value pairs, for example:
 
-    .. code-block:: json
-
-        "extra_vars": {
-            "dry_run": true,
-            "commit_comment": "I am a robot!",
-            "verb": "deploy"
-        }
+    <!-- vale off -->
+    ```py
+    "extra_vars": {
+        "dry_run": true,
+        "commit_comment": "I am a robot!",
+        "verb": "deploy"
+    }
+    ```
+    <!-- vale on -->
 
     Args:
         playbook_name: Filename of the playbook that is to be executed. It must be present on the remote system running
@@ -111,7 +111,7 @@ def _execute_playbook(
         callback_route: The endpoint at which GSO expects a callback to continue the workflow executing this step.
         inventory: An inventory of machines at which the playbook is targeted. Must be in YAML-compatible format.
         extra_vars: Any extra variables that the playbook relies on. This can include a subscription object, a boolean
-            value indicating a dry run, a commit comment, etc.  All unicode character values are decoded to prevent
+            value indicating a dry run, a commit comment, etc. All unicode character values are decoded to prevent
             sending special characters to remote machines that don't support this.
     """
     parameters = {
@@ -169,7 +169,7 @@ def _clean_state() -> State:
     }
 
 
-def _inventory_is_set(state: State) -> bool:
+def validate_inventory_is_set(state: State) -> bool:
     """Validate whether the passed Ansible inventory is empty.
 
     If the inventory is empty, which can happen in select cases, there should be no playbook run. This conditional will
@@ -186,7 +186,7 @@ def _inventory_is_set(state: State) -> bool:
     return state["inventory"]["all"]["hosts"]
 
 
-_inventory_is_not_empty = conditional(_inventory_is_set)
+_inventory_is_not_empty = conditional(validate_inventory_is_set)
 
 
 def lso_interaction(provisioning_step: Step) -> StepList:
@@ -196,7 +196,7 @@ def lso_interaction(provisioning_step: Step) -> StepList:
     to provision service subscriptions. If the playbook fails, this step will also fail, allowing for the user to retry
     provisioning from the UI.
 
-    Optionally, the keys ``lso_result_title`` and ``lso_result_extra_label`` can be added to the state before running
+    Optionally, the keys `lso_result_title` and `lso_result_extra_label` can be added to the state before running
     this interaction. They will be used to customise the input step that shows the outcome of the LSO
     interaction.
 
@@ -224,13 +224,13 @@ def lso_interaction(provisioning_step: Step) -> StepList:
 def indifferent_lso_interaction(provisioning_step: Step) -> StepList:
     """Interact with the provisioning proxy LSO using a callback step.
 
-    This interaction is identical from the one described in ``lso_interaction()``, with one functional difference.
-    Whereas the ``lso_interaction()`` will make the workflow step fail on unsuccessful interaction, this step will not.
+    This interaction is identical from the one described in `lso_interaction()`, with one functional difference.
+    Whereas the `lso_interaction()` will make the workflow step fail on unsuccessful interaction, this step will not.
     It is therefore indifferent about the outcome of the Ansible playbook that is executed.
 
-    .. warning::
-       Using this interaction requires the operator to carefully evaluate the outcome of a playbook themselves. If a
-       playbook fails, this will not cause the workflow to fail.
+    !!! danger
+        Using this interaction requires the operator to manually evaluate the outcome of a playbook. If a playbook
+        fails, this will not cause the workflow to fail.
 
     Args:
         provisioning_step: A workflow step that performs an operation remotely using the provisioning proxy.
@@ -258,7 +258,7 @@ def anonymous_lso_interaction(provisioning_step: Step, validation_step: Step = _
 
     Similar to the indifferent LSO interaction, there also is the anonymous interaction. Output is not ignored
     but no input step is created to display the results.
-    A custom validation step may be given as input. This validation step should look inside the ``callback_result`` key
+    A custom validation step may be given as input. This validation step should look inside the `callback_result` key
     in the current state. By default, only the return code of the playbook execution is evaluated.
 
     Args:
diff --git a/gso/services/netbox_client.py b/gso/services/netbox_client.py
index 4b6560b9cf78fb07ffde0e5b2604620c35844990..2928263c920da52e0993fbb43ddc4dbfa2d20283 100644
--- a/gso/services/netbox_client.py
+++ b/gso/services/netbox_client.py
@@ -319,7 +319,7 @@ class NetboxClient:
 
     @staticmethod
     def calculate_speed_bits_per_sec(speed: str) -> int:
-        """Extract the numeric part from the speed."""
+        """Calculate the numeric part from the speed."""
         numeric_part = int("".join(filter(str.isdigit, speed)))
         # Convert to bits per second
         return numeric_part * 1000000
diff --git a/gso/services/subscriptions.py b/gso/services/subscriptions.py
index 83d88751984a66a5eed4522b55077734ceda303f..c42b4a71fa2c0af63e0307ba791e2cba5db32dde 100644
--- a/gso/services/subscriptions.py
+++ b/gso/services/subscriptions.py
@@ -45,7 +45,7 @@ def get_subscriptions(
         partner_id: The customer id of subscriptions.
 
     Returns:
-        A list of ``SubscriptionType`` objects that match the query.
+        A list of `SubscriptionType` objects that match the query.
     """
     if not includes:
         includes = [col.name for col in SubscriptionTable.__table__.columns]
@@ -161,9 +161,9 @@ def get_non_terminated_iptrunk_subscriptions(includes: list[str] | None = None)
 def get_trunks_that_terminate_on_router(
     subscription_id: UUIDstr, lifecycle_state: SubscriptionLifecycle
 ) -> list[SubscriptionTable]:
-    """Get all IP trunk subscriptions that terminate on the given ``subscription_id`` of a Router.
+    """Get all IP trunk subscriptions that terminate on the given `subscription_id` of a Router.
 
-    Given a ``subscription_id`` of a Router subscription, this method gives a list of all IP trunk subscriptions that
+    Given a `subscription_id` of a Router subscription, this method gives a list of all IP trunk subscriptions that
     terminate on this Router. The given lifecycle state dictates the state of trunk subscriptions that are counted as
     terminating on this router.
 
diff --git a/gso/settings.py b/gso/settings.py
index 5b3beefd963591541845255ddef67a6a1e0234ab..d65ead42c5c43e1aacac30f3c44616194fc819ad 100644
--- a/gso/settings.py
+++ b/gso/settings.py
@@ -129,9 +129,12 @@ class SNMPParams(BaseSettings):
     """Parameters for SNMP in LibreNMS."""
 
     v2c: MonitoringSNMPV2Params
-    #: .. versionadded :: 2.0
-    #:    Support for SNMP v3 will get added in a later version of GSO. Parameters are optional for now.
     v3: MonitoringSNMPV3Params | None = None
+    """
+    !!! example "Optional parameter"
+
+        Support for SNMP v3 will get added in a later version of GSO. Parameters are optional for now.
+    """
 
 
 class MonitoringParams(BaseSettings):
@@ -157,7 +160,12 @@ class NetBoxParams(BaseSettings):
 
 
 class EmailParams(BaseSettings):
-    """Parameters for the email service."""
+    """Parameters for the email service.
+
+    Attributes:
+        notification_email_destinations: List of email addresses that should receive notifications when validation of a
+            subscription fails. Can be a comma-separated list of multiple addresses.
+    """
 
     from_address: EmailStr
     smtp_host: str
@@ -165,8 +173,6 @@ class EmailParams(BaseSettings):
     starttls_enabled: bool
     smtp_username: str | None = None
     smtp_password: str | None = None
-    #: List of email addresses that should receive notifications when validation of a subscription fails.
-    #: Can be a comma-separated list of multiple addresses.
     notification_email_destinations: str
 
 
diff --git a/gso/utils/helpers.py b/gso/utils/helpers.py
index aca141073931b72c3c2831a7fefbd68160f7564d..20d66cab639db87252278ad1cc70310740c65812 100644
--- a/gso/utils/helpers.py
+++ b/gso/utils/helpers.py
@@ -74,7 +74,7 @@ def available_lags_choices(router_id: UUID) -> Choice | None:
     """Return a list of available lags for a given router.
 
     For Nokia routers, return a list of available lags.
-    For Juniper routers, return ``None``.
+    For Juniper routers, return `None`.
     """
     if get_router_vendor(router_id) != Vendor.NOKIA:
         return None
@@ -86,7 +86,7 @@ def available_service_lags_choices(router_id: UUID) -> Choice | None:
     """Return a list of available lags for a given router for services.
 
     For Nokia routers, return a list of available lags.
-    For Juniper routers, return ``None``.
+    For Juniper routers, return `None`.
     """
     if get_router_vendor(router_id) != Vendor.NOKIA:
         return None
@@ -164,7 +164,7 @@ def generate_inventory_for_routers(
         router_role: The role of the routers to include in the inventory.
         exclude_routers: List of routers to exclude from the inventory.
         router_vendor: The vendor of the routers to include in the inventory.
-        include_provisioning_routers: Include routers that are in a ``PROVISIONING`` state.
+        include_provisioning_routers: Include routers that are in a `PROVISIONING` state.
 
     Returns:
         A dictionary representing the inventory of active routers.
@@ -262,7 +262,7 @@ def active_edge_port_selector(*, partner_id: UUIDstr | None = None) -> Choice:
     )
 
     if partner_id:
-        # ``partner_id`` is set, so we will filter accordingly.
+        # `partner_id` is set, so we will filter accordingly.
         edge_port_subscriptions = list(
             filter(lambda subscription: bool(subscription["customer_id"] == partner_id), edge_port_subscriptions)
         )
diff --git a/gso/utils/types/interfaces.py b/gso/utils/types/interfaces.py
index f76cd8de373ac4eb916d67d3370193de0210db51..16f69f3aebcd75be9db7cbf9dde59114c6d86fce 100644
--- a/gso/utils/types/interfaces.py
+++ b/gso/utils/types/interfaces.py
@@ -25,7 +25,7 @@ class LAGMember(BaseModel):
 def validate_interface_names_are_unique(interfaces: list[LAGMember]) -> list[LAGMember]:
     """Verify if interfaces are unique.
 
-    Raises a ``ValueError`` if the interfaces are not unique.
+    Raises a `ValueError` if the interfaces are not unique.
 
     Args:
         interfaces: The list of interfaces.
diff --git a/gso/workflows/router/validate_router.py b/gso/workflows/router/validate_router.py
index b029db47ab9233f1f3624628852f2692abbf5aec..89a05004d48742ebdecff943b95f2914a651edba 100644
--- a/gso/workflows/router/validate_router.py
+++ b/gso/workflows/router/validate_router.py
@@ -55,7 +55,7 @@ def check_netbox_entry_exists(subscription: Router) -> None:
 
 @step("Verify P BGP P-ONLY neighbors")
 def verify_p_ibgp(subscription: dict[str, Any]) -> LSOState:
-    """Verify PE neighbors in P-ONLY group on a P router."""
+    """Verify PE neighbors in `P-ONLY` group on a P router."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
@@ -100,7 +100,7 @@ def verify_pe_mesh_in_pe(subscription: dict[str, Any]) -> LSOState:
 
 @step("Verify PE BGP P-ONLY neighbors")
 def verify_all_p_in_pe(subscription: dict[str, Any]) -> LSOState:
-    """Verify P neighbors in P-ONLY group on a PE router."""
+    """Verify P neighbors in `P-ONLY` group on a PE router."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
diff --git a/gso/workflows/site/terminate_site.py b/gso/workflows/site/terminate_site.py
index 8f13e3589f2c9b04737567448fb8265587fd97a1..92da5ccae5479a50211e7cf89958991a1c9ceadb 100644
--- a/gso/workflows/site/terminate_site.py
+++ b/gso/workflows/site/terminate_site.py
@@ -1,8 +1,8 @@
 """A workflow for terminating a site subscription.
 
 The `terminate_site` workflow will take an existing and active site subscription from an `ACTIVE` to a `TERMINATED`
-state. This requires all dependant subscription instances to already be terminated. If this is not the case, the
-workflow will be unavailable for an operator to run, accompanied by an error message explaining this fact.
+state. This requires all dependant subscription instances to already be terminated. If not, the workflow will be
+unavailable for an operator to run, accompanied by an error message explaining this fact.
 """
 
 from orchestrator.forms import FormPage
diff --git a/gso/workflows/tasks/validate_geant_products.py b/gso/workflows/tasks/validate_geant_products.py
index a7bfcdaaaaca2a1b7d3b84766629829716530e3b..8fe39f61b762f46683336f802af1885d447ab339 100644
--- a/gso/workflows/tasks/validate_geant_products.py
+++ b/gso/workflows/tasks/validate_geant_products.py
@@ -1,6 +1,6 @@
 """A task that checks for all products in the database to be well-kept."""
 
-# .. vale off
+# <!-- vale off -->
 # Copyright 2019-2020 SURF.
 # Copyright 2024 GÉANT Vereniging.
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-# .. vale on
+# <!-- vale on -->
 
 from orchestrator.targets import Target
 from orchestrator.workflow import StepList, done, init, workflow
diff --git a/gso/workflows/vrf/__init__.py b/gso/workflows/vrf/__init__.py
index 0fc8180f6bd9547693b518647a82b21fe636b1db..68a1b462970d258956f93a8b45e4823528928136 100644
--- a/gso/workflows/vrf/__init__.py
+++ b/gso/workflows/vrf/__init__.py
@@ -1 +1 @@
-""":term:`VRF` Virtual Routing and Forwarding."""
+"""VRF Virtual Routing and Forwarding."""
diff --git a/gso/workflows/vrf/create_vrf.py b/gso/workflows/vrf/create_vrf.py
index 9ca01d1e81b3f9babd27a024b827c26df41ba2cb..8da4f2d91a9584090a3d2b1fd5b53489a1dc1438 100644
--- a/gso/workflows/vrf/create_vrf.py
+++ b/gso/workflows/vrf/create_vrf.py
@@ -1,4 +1,4 @@
-"""A creation workflow for adding a new virtual routing and forwarding (:term:`VRF`) service."""
+"""A creation workflow for adding a new virtual routing and forwarding (VRF) service."""
 
 from orchestrator.forms import FormPage
 from orchestrator.targets import Target
@@ -39,7 +39,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
 
 @step("Create subscription")
 def create_subscription(product: UUIDstr, partner: str) -> State:
-    """Create a new :term:`VRF` subscription."""
+    """Create a new VRF subscription."""
     subscription = VRFInactive.from_product_id(product, get_partner_by_name(partner)["partner_id"])
 
     return {
@@ -72,7 +72,7 @@ def initialize_subscription(
     target=Target.CREATE,
 )
 def create_vrf() -> StepList:
-    """Create a virtual routing and forwarding (:term:`VRF`) service."""
+    """Create a virtual routing and forwarding (VRF) service."""
     return (
         begin
         >> create_subscription
diff --git a/gso/workflows/vrf/modify_vrf_router_list.py b/gso/workflows/vrf/modify_vrf_router_list.py
index b0618d95237be5ff3455953033edea3377fa0346..d198d8f9738d6e9ea9d0160c9af74a4e94676018 100644
--- a/gso/workflows/vrf/modify_vrf_router_list.py
+++ b/gso/workflows/vrf/modify_vrf_router_list.py
@@ -1,4 +1,4 @@
-"""Modify :term:`VRF` to add or remove routers."""
+"""Modify VRF to add or remove routers."""
 
 from typing import Annotated
 
@@ -17,7 +17,7 @@ from gso.utils.helpers import active_router_selector
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
-    """Modify :term:`VRF` to add or remove routers."""
+    """Modify VRF to add or remove routers."""
     subscription = VRF.from_subscription(subscription_id)
 
     class RouterSelection(BaseModel):
@@ -57,5 +57,5 @@ def update_subscription_model(subscription: VRF, router_list: list[dict[str, UUI
     target=Target.MODIFY,
 )
 def modify_vrf_router_list() -> StepList:
-    """Modify the :term:`VRF` router list."""
+    """Modify the VRF router list."""
     return begin >> store_process_subscription(Target.MODIFY) >> unsync >> update_subscription_model >> resync >> done
diff --git a/test/fixtures/site_fixtures.py b/test/fixtures/site_fixtures.py
index c6a884b1eb8fe54e482057c7e5f0fd452b23e3bd..2467bd89067602cfd8b99270b81a4a350efe93e5 100644
--- a/test/fixtures/site_fixtures.py
+++ b/test/fixtures/site_fixtures.py
@@ -52,7 +52,7 @@ def site_subscription_factory(faker, geant_partner):
         site_subscription.site.site_latitude = site_latitude or str(faker.latitude())
         site_subscription.site.site_longitude = site_longitude or str(faker.longitude())
         site_subscription.site.site_bgp_community_id = site_bgp_community_id or faker.pyint()
-        site_subscription.site.site_internal_id = site_internal_id or faker.pyint(max_value=254)
+        site_subscription.site.site_internal_id = site_internal_id or faker.pyint(min_value=1, max_value=254)
         site_subscription.site.site_tier = site_tier or SiteTier.TIER1
         site_subscription.site.site_ts_address = site_ts_address or faker.ipv4()
         site_subscription.site.site_contains_optical_equipment = site_contains_optical_equipment