Docs Contribution Guide
This guide is for anyone who wants to improve the OCUDU documentation: adding a new integration guide, writing a tutorial, fixing an error, or expanding existing content. It covers everything you need to go from a local clone to a submitted merge request.
For contributing code to OCUDU, see the Code Contribution Guide.
Repository Structure
The documentation lives in the ocudu_docs repository. The top-level structure is:
ocudu_docs/
├── .gitlab/ # GitLab project configuration and templates
├── .reuse/ # REUSE licence compliance configuration
├── LICENSES/ # Licence texts referenced by SPDX headers
├── docs/ # All documentation content as Markdown files
│ ├── user_manual/ # Installation, configuration, running, outputs, troubleshooting
│ ├── tutorials/ # Step-by-step tutorials
│ ├── integrations/ # Third-party hardware and core integration guides
│ ├── knowledge_base/ # Background and reference material
│ └── dev_guide/ # Developer and contributor documentation
├── plugins/ # Custom Docusaurus plugins
├── scripts/ # Build scripts
├── src/ # Custom React components and CSS
│ ├── css/ # Custom stylesheets
│ ├── pages/ # Custom React pages
│ └── theme/ # Docusaurus theme component overrides
├── static/ # Static assets served directly
│ ├── doxygen/ # Doxygen HTML output (mounted from the OCUDU source repo)
│ └── img/ # Images used in the documentation
├── .env # Environment variables for docker-compose
├── .gitignore # Git ignore rules
├── .gitlab-ci.yml # GitLab CI/CD pipeline configuration
├── LICENSE # Project licence
├── README.md # Repository overview
├── REUSE.toml # REUSE/SPDX licence compliance configuration
├── docker-compose.yml # Docker services for the documentation site
├── docusaurus.config.js # Site configuration, including the top navbar
├── package-lock.json # Locked dependency versions (auto-generated)
├── package-lock.json.license # SPDX licence sidecar for package-lock.json
├── package.json # Node.js dependencies
├── package.json.license # SPDX licence sidecar for package.json
└── sidebars_extended.js # Sidebar navigation for all sections
The node_modules/ and .docusaurus/ directories are generated automatically and do not need to be committed or modified.
Setting Up a Local Preview
Docker must be installed before running the site. See the Docker installation guide if you have not set it up yet.
Clone the ocudu_docs repository:
git clone https://gitlab.com/ocudu/ocudu_docs.git
If you do not have write access, fork the repository on GitLab first and clone your fork instead. See Submitting Your Contribution for the full workflow.
From the root of the repository, start the preview server:
docker compose -f docker-compose.yml up --build
The --build flag forces Docker to rebuild the container image before starting. Use it the first time you run the site and whenever dependencies change. Without it, Docker reuses a cached image that may be out of date.
The site is available at http://localhost:3001. If port 3001 is already in use, update the port mapping in docker-compose.yml.
Content changes to Markdown files are reflected automatically without restarting the server. If you modify any build files (docusaurus.config.js, sidebars_extended.js, package.json, or the src/ directory), stop the server and run the command again with --build to pick up the changes.
How the site works
Docusaurus renders all .md files in the repository automatically:
- Every Markdown file in
docs/is collected and made accessible by URL. - Files are excluded only if their path matches an exclusion rule in
docusaurus.config.js. README.mdfiles become index pages for their directory.
Static pages such as the Doxygen API reference are served directly and accessible at baseUrl/doxygen/index.html. Doxygen output is only built during deployment and will not be available in the local development server.
Search is powered by @easyops-cn/docusaurus-search-local and indexes all documentation pages locally without any external service. The search index is only built during a production build and will not work in the local development server.
Adding a New Page
1. Create the file
Place the file in the appropriate subdirectory under docs/. Use lowercase with underscores for filenames. For a new tutorial, the file goes in docs/tutorials/<topic>/index.md.
Use a .md extension by default. Use .mdx only if the page requires JSX components or React imports. The JSX pitfall in Common Pitfalls explains what breaks if you mix these up.
2. Add frontmatter
Every page requires a frontmatter block at the top:
---
description: "A short description of this page. Quote the value if it contains a colon."
displayed_sidebar: userDocsSidebar
---
description is used for search results and page metadata. If the value contains a colon followed by a space, wrap it in double quotes. Unquoted colons cause a YAML parse error and break the build.
displayed_sidebar tells Docusaurus which sidebar to show when this page is open. Use userDocsSidebar for user-facing content, devSidebar for developer documentation, and knowledgeBaseSidebar for knowledge base pages. Without this field, the sidebar may not display correctly on pages that are not in an autogenerated directory.
These are the only required frontmatter fields. Other Docusaurus frontmatter keys (title, slug, sidebar_label, id) are supported but optional.
Every page should open with an H1 heading (# Page Title). Docusaurus uses this as the visible page title in the browser and table of contents.
3. Register the page in the sidebar
This step is required. A new file that is not registered in sidebars_extended.js will not appear in the navigation, even though the page itself is accessible by URL.
Open sidebars_extended.js and add an entry in the correct section. For example, to add a new integration guide for a radio unit:
items: [
'integrations/radio_units/benetel',
'integrations/radio_units/your_new_guide', // add this line
'integrations/radio_units/foxconn',
],
Use the file path relative to docs/, without the .md extension. Keep entries in alphabetical order within their section. This is a readability convention, not a build requirement.
Some subdirectories under docs/ are marked as autogenerated in sidebars_extended.js. Files added to those directories appear in the sidebar automatically without a manual entry. Most tutorial subdirectories and user manual sections use this mode. Integration guides and developer documentation do not — entries must be added manually.
4. Check the navbar
Most pages do not require a navbar change. The navbar links to section index pages, not individual documents. Only add a navbar entry if you are creating a new top-level section of the site.
Adding a New Integration Guide
Integration guides are the most common community contribution. The process is:
- Create the file at
docs/integrations/radio_units/<vendor>.md,docs/integrations/5g_cores/<vendor>/index.md, ordocs/integrations/switches_and_timing/<vendor>.mddepending on the type. - Follow the structure of an existing guide in the same category. The Benetel guide is a good reference for a radio unit guide.
- Add the file to
sidebars_extended.jsin alphabetical order within the correct category (see step 3 in Adding a New Page above). - Add any images to
static/img/and include a.licensesidecar alongside each one (see License sidecars below).
Writing Style
Follow these rules when writing documentation:
- Active voice. Write "run the command" not "the command should be run."
- Imperative for instructions. Write "clone the repository" not "you should clone the repository."
- One topic per sentence. Split complex sentences rather than joining them with "and" or "but."
- No em-dashes (—). Use a colon, semicolon, or a new sentence instead.
- Quote all commands and file paths using inline code formatting.
For a full style reference, see the Hitchhiker's Guide to Documentation and the Diataxis framework for guidance on which type of document to write.
Common Pitfalls
Check all of the following before submitting a merge request:
- Missing sidebar entry. The most common mistake. Every new page must be added to
sidebars_extended.jsmanually if its directory is not listed asautogenerated. - Missing
displayed_sidebar. Pages outside an autogenerated directory may show no sidebar at all. Adddisplayed_sidebar: userDocsSidebar(or the appropriate sidebar ID) to the frontmatter of every new page. - Unquoted YAML colons. Any
description:value that contains:must be wrapped in double quotes. - Broken relative links. Links to other
.mdfiles use relative paths. Verify that the target file exists at the path you specify. - Broken anchor links. An anchor like
#section-headingwill silently stop working if the target heading is renamed. Verify all anchors after any heading change. - Missing
.licensesidecar. Every PNG, JPG, GIF, SVG, PDF,.woff, or other binary or generated file instatic/requires a.licensefile alongside it. See License sidecars. - JSX in
.mdfiles. JSX syntax (React components,className=, self-closing tags) is only valid in.mdxfiles. Using JSX in a.mdfile will break the build. If your page includes custom components, rename the file to.mdx. - Conflict markers. Run
git diffbefore committing to confirm no<<<<<<<,=======, or>>>>>>>markers remain in the files.
License sidecars
PNG, JPG, GIF, SVG, PDF, .woff, and other binary or generated files require a .license sidecar. Update the end year to the current year:
SPDX-FileCopyrightText: Copyright (C) 2021-<current year> Software Radio Systems Limited
SPDX-License-Identifier: BSD-3-Clause-Open-MPI
For example, an image at static/img/my_diagram.png requires a file at static/img/my_diagram.png.license with the above content.
Submitting Your Contribution
If you have write access to the repository, clone it directly and start from step 2. If you do not have write access, begin with step 1.
- Fork the ocudu_docs repository on GitLab and clone your fork.
- Create a branch with a descriptive name using underscores, for example
add_<vendor>_integration_guideorfix_<topic>_typos. - Make your changes and verify the local preview looks correct.
- Verify your Git identity is configured before committing. The DCO sign-off will be malformed without it:
Set either with
git config user.name
git config user.emailgit config --global user.name "Your Name"if blank. - Sign your commits with a Developer Certificate of Origin (DCO) sign-off. The DCO certifies that you wrote the change and have the right to contribute it. Use the area of work as the commit scope:
Common scopes:
git commit --signoff -m "<area>: describe what you changed"tutorials,integrations,user_manual,dev_guide,knowledge_base,config,css. - Open a merge request against the
mainbranch. Describe what you changed and why.
When you open the MR, two automated checks run: a REUSE licence header check and a full Docusaurus build, which enforces broken link detection. Both must pass before the MR can be merged. The pipeline also produces a live preview URL, which appears in the CI job output and lets you review the rendered site before merge.
If you are unsure whether your contribution fits the documentation or have questions at any point, open an issue or ask in the community channels.