> ## Documentation Index
> Fetch the complete documentation index at: https://mint-tsdocs.saulo.engineer/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenDocs File Organization

> How OpenDocs organizes documentation into files and projects

export const FileTree = ({structure, item, title, level = 0, maxDepth = 10, showIcons = true}) => {
  const getFileIcon = (fileName, hasChildren) => {
    if (hasChildren) {
      return 'folder-open';
    }
    return 'file';
  };
  if (structure !== undefined) {
    return <div data-component="tsdocs-filetree" className="code-block mt-5 mb-8 not-prose rounded-2xl relative group
                   text-gray-950 bg-gray-50 dark:bg-white/5 dark:text-gray-50
                   border border-gray-950/10 dark:border-white/10
                   p-0.5">
        {title && <div className="flex text-gray-400 text-xs rounded-t-[14px] leading-6 font-medium pl-4 pr-2.5 py-1">
            <div className="flex-none flex items-center gap-1.5 text-gray-700 dark:text-gray-300">
              {title}
            </div>
          </div>}
        <div className={`prose prose-sm dark:prose-invert w-0 min-w-full max-w-full py-3.5 px-4 bg-white dark:bg-codeblock overflow-x-auto scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-black/15 hover:scrollbar-thumb-black/20 dark:scrollbar-thumb-white/20 dark:hover:scrollbar-thumb-white/25 rounded-xt`} style={{
      fontFamily: 'ui-monospace, SFMono-Regular, monospace',
      fontSize: '0.875rem'
    }}>
          {structure.map((fileItem, index) => {
      if (!fileItem || !fileItem.name) return null;
      return <FileTree key={index} item={fileItem} level={0} maxDepth={maxDepth} showIcons={showIcons} />;
    })}
        </div>
      </div>;
  }
  if (!item) {
    return null;
  }
  if (level >= maxDepth) {
    return <div style={{
      paddingLeft: `${level * 20}px`,
      paddingTop: '4px',
      paddingBottom: '4px',
      color: '#6b7280',
      fontStyle: 'italic'
    }}>
        {showIcons && <Icon icon="AlertTriangle" />} (max depth reached)
      </div>;
  }
  const hasChildren = item.children != null && item.children.length > 0;
  const indent = level * 20;
  if (hasChildren) {
    return <div style={{
      position: 'relative',
      paddingLeft: `${indent}px`
    }}>
        {}
        {level > 0 && <div style={{
      position: 'absolute',
      left: `${indent - 12}px`,
      top: '20px',
      bottom: '0',
      width: '1px',
      backgroundColor: 'rgba(156, 163, 175, 0.2)',
      borderLeft: '1px solid rgba(156, 163, 175, 0.1)'
    }} />}
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '8px',
      paddingTop: '4px',
      paddingBottom: '4px'
    }}>
          {showIcons && <Icon icon={getFileIcon(item.name, true)} />}
          <span style={{
      fontWeight: 500
    }}>
            {item.name}
          </span>
          {item.description && <span style={{
      fontSize: '0.75rem',
      color: '#94a3b8',
      marginLeft: '8px'
    }}>
              {item.description}
            </span>}
          {item.badge && <Badge color={item.badge.color || 'blue'}>
              {item.badge.text}
            </Badge>}
        </div>
        {}
        {item.children && item.children.map((child, i) => {
      const key = child.name ? `${child.name}-${i}` : `child-${i}`;
      return <FileTree key={key} item={child} level={level + 1} maxDepth={maxDepth} showIcons={showIcons} />;
    })}
      </div>;
  }
  return <div style={{
    position: 'relative',
    paddingLeft: `${indent}px`,
    display: 'flex',
    alignItems: 'center',
    gap: '8px',
    paddingTop: '4px',
    paddingBottom: '4px'
  }}>
      {}
      {level > 0 && <div style={{
    position: 'absolute',
    left: `${indent - 12}px`,
    top: '0',
    bottom: '0',
    width: '1px',
    backgroundColor: 'rgba(156, 163, 175, 0.2)',
    borderLeft: '1px solid rgba(156, 163, 175, 0.1)'
  }} />}
      {showIcons && <Icon icon={getFileIcon(item.name, false)} />}
      <span>
        {item.name}
      </span>
      {item.description && <span style={{
    fontSize: '0.75rem',
    color: '#94a3b8',
    marginLeft: '8px'
  }}>
          {item.description}
        </span>}
      {item.badge && <Badge color={item.badge.color || 'blue'}>
          {item.badge.text}
        </Badge>}
    </div>;
};

export const TypeTreeGroup = ({title, children}) => {
  return <div>
      {title && <h3>{title}</h3>}
      {children}
    </div>;
};

export const TypeTree = ({name, type, description, required = false, deprecated = false, properties = [], defaultValue, level = 0, maxDepth = 10, open = false}) => {
  if (level >= maxDepth) {
    console.warn(`TypeTree: Maximum depth (${maxDepth}) exceeded for ${name}. Preventing infinite recursion.`);
    return <ResponseField name={name} type={type} required={required} deprecated={deprecated} default={defaultValue}>
        {description}
        <div style={{
      fontStyle: 'italic',
      opacity: 0.7
    }}>
          (Maximum nesting depth reached)
        </div>
      </ResponseField>;
  }
  const hasNested = properties && properties.length > 0;
  return <ResponseField name={name} type={type} required={required} deprecated={deprecated} default={defaultValue}>
      {description}
      {hasNested && <Expandable title="props" key={`${name}-${level}`} defaultOpen={open}>
          {properties.map((prop, idx) => {
    const key = prop.name ? `${prop.name}-${idx}` : `prop-${idx}`;
    return <TypeTree open key={key} name={prop.name} type={prop.type} description={prop.description} required={prop.required} deprecated={prop.deprecated} properties={prop.properties} defaultValue={prop.defaultValue} level={level + 1} maxDepth={maxDepth} />;
  })}
        </Expandable>}
    </ResponseField>;
};

## Overview

OpenDocs uses JSON Schema `$ref` to organize documentation, making file structure flexible. Only `opendocs.json` is required—everything else can be referenced via `$ref`.

## Using \$ref

The `$ref` keyword (defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)) allows JSON documents to reference content in other locations using URI references. OpenDocs uses `$ref` to split large documentation sets across multiple files.

**Basic syntax:**

```json theme={null}
{
  "id": "my-docs",
  "name": "My Documentation",
  "projects": [
    { "$ref": "./projects/auth.json" },           // Relative file reference
    { "$ref": "https://example.com/types.json" }  // URL reference
  ]
}
```

The referenced file should contain the complete object that would otherwise be inline. For example, `./projects/auth.json` should contain a complete `Project` object.

For a comprehensive guide on `$ref` usage, see the [Swagger \$ref documentation](https://swagger.io/docs/specification/v3_0/using-ref/).

## Key Principle: File Organization is Flexible

Since OpenDocs relies on JSON Schema `$ref`, the physical directory structure and file naming conventions are **completely flexible**. You can organize your documentation files however you prefer:

* All content can be embedded in `opendocs.json`
* Content can be split across multiple files using `$ref`
* Files can be named and organized in any directory structure
* The only requirement is that `opendocs.json` must exist as the entry point

### Example: Using \$ref for Flexibility

```json theme={null}
{
  "documentationSet": { "id": "my-docs", "name": "My Documentation" },
  "projects": [
    { "$ref": "./projects/auth.json" },
    { "$ref": "./deeply/nested/path/to/sdk.json" },
    { "$ref": "https://example.com/shared/types.json" }
  ]
}
```

The same documentation set could be organized with all content in a single file, or split across any number of files in any directory structure.

## File Structure

### Documentation Set Layout

Since OpenDocs uses JSON Schema `$ref`, the physical file organization is irrelevant. The only required file is `opendocs.json`:

<FileTree
  title="Minimal Documentation Set"
  structure={[
{
  name: "opendocs.json",
  description: "Required entry point with project organization"
}
]}
/>

## Organization Strategies

You can organize your Documentation Set in two main ways:

1. **Monolithic** - All content embedded in `opendocs.json`
2. **Distributed** - Content split across multiple files using `$ref`

The choice depends on your preferences and project size. Both are valid approaches.

## Example: Monorepo Documentation Set

This example shows a monorepo with multiple projects. We'll show both the monolithic approach (everything embedded) and the distributed approach (split using `$ref`).

### Monolithic Approach

Everything in a single `opendocs.json` file:

```json theme={null}
{
  "id": "acme-platform",
  "name": "ACME Platform",
  "version": "1.0.0",
  "projects": [
    {
      "id": "auth-service",
      "name": "Authentication Service",
      "language": "go",
      "version": "1.5.0",
      "dependencies": ["shared-types"],
      "items": [
        {
          "id": "auth-service#AuthController",
          "name": "AuthController",
          "kind": "struct",
          "language": "go",
          "docBlock": {
            "description": "Handles authentication requests"
          },
          "items": [
            {
              "id": "auth-service#AuthController#Login",
              "name": "Login",
              "kind": "method",
              "language": "go",
              "docBlock": {
                "description": "Authenticates a user",
                "tags": {
                  "param": [
                    {
                      "name": "param",
                      "content": "User credentials",
                      "parameters": { "name": "credentials", "type": "Credentials" }
                    }
                  ],
                  "returns": ["Authentication token"]
                }
              }
            }
          ]
        }
      ]
    },
    {
      "id": "web-sdk",
      "name": "Web SDK",
      "language": "typescript",
      "version": "2.0.0",
      "dependencies": ["shared-types"],
      "items": [
        {
          "id": "web-sdk#ApiClient",
          "name": "ApiClient",
          "kind": "class",
          "language": "typescript",
          "docBlock": {
            "description": "Main API client for the platform"
          }
        }
      ]
    },
    {
      "id": "shared-types",
      "name": "Shared Types",
      "language": "typescript",
      "version": "1.0.0",
      "items": [
        {
          "id": "shared-types#User",
          "name": "User",
          "kind": "interface",
          "language": "typescript",
          "docBlock": {
            "description": "User entity"
          }
        }
      ]
    }
  ]
}
```

### Distributed Approach

The same documentation split across multiple files using `$ref`:

**opendocs.json:**

```json theme={null}
{
  "id": "acme-platform",
  "name": "ACME Platform",
  "version": "1.0.0",
  "projects": [
    { "$ref": "./projects/auth-service.json" },
    { "$ref": "./projects/web-sdk.json" },
    { "$ref": "./projects/shared-types.json" }
  ]
}
```

**projects/auth-service.json:**

```json theme={null}
{
  "id": "auth-service",
  "name": "Authentication Service",
  "language": "go",
  "version": "1.5.0",
  "dependencies": ["shared-types"],
  "items": [
    {
      "id": "auth-service#AuthController",
      "name": "AuthController",
      "kind": "struct",
      "language": "go",
      "docBlock": {
        "description": "Handles authentication requests"
      },
      "items": [
        {
          "id": "auth-service#AuthController#Login",
          "name": "Login",
          "kind": "method",
          "language": "go",
          "docBlock": {
            "description": "Authenticates a user",
            "tags": {
              "param": [
                {
                  "name": "param",
                  "content": "User credentials",
                  "parameters": { "name": "credentials", "type": "Credentials" }
                }
              ],
              "returns": ["Authentication token"]
            }
          }
        }
      ]
    }
  ]
}
```

**projects/web-sdk.json:**

```json theme={null}
{
  "id": "web-sdk",
  "name": "Web SDK",
  "language": "typescript",
  "version": "2.0.0",
  "dependencies": ["shared-types"],
  "items": [
    {
      "id": "web-sdk#ApiClient",
      "name": "ApiClient",
      "kind": "class",
      "language": "typescript",
      "docBlock": {
        "description": "Main API client for the platform"
      }
    }
  ]
}
```

**projects/shared-types.json:**

```json theme={null}
{
  "id": "shared-types",
  "name": "Shared Types",
  "language": "typescript",
  "version": "1.0.0",
  "items": [
    {
      "id": "shared-types#User",
      "name": "User",
      "kind": "interface",
      "language": "typescript",
      "docBlock": {
        "description": "User entity"
      }
    }
  ]
}
```

Both approaches produce identical documentation. The distributed approach is easier to manage for large projects with many items.

## File and Directory Naming

Since OpenDocs uses `$ref`, file names and directory structure are completely flexible. Use whatever organization makes sense for your project:

```
opendocs.json
projects/
  ├── auth-service.json
  ├── web-sdk.json
  └── shared-types.json
```

Or:

```
my-docs.json
api/
  auth.json
  sdk.json
  types.json
```

Both are equally valid.

## Best Practices

### ID Conventions

Use consistent, predictable naming for IDs:

**Documentation Set IDs:** `lowercase-with-hyphens`

* Example: `acme-platform-docs`

**Project IDs:** `lowercase-with-hyphens`

* Example: `auth-service`, `web-sdk`, `shared-types`

**DocItem IDs:** `project-id#item-path`

* Top-level: `auth-service#AuthController`
* Nested: `auth-service#AuthController#Login`
* Deep nesting: `auth-service#api#v2#AuthController#Login`

**Language-Specific Delimiters:**

* Use `#` to separate OpenDocs components
* Use `::` for namespace-style IDs (Rust): `serde::de::Deserialize`
* Use `.` for package-style IDs (TypeScript): `@acme/utils.StringHelper`

### Project Organization

1. **Use meaningful IDs** - `auth-service` not `proj1`
2. **Declare dependencies** - Help tools understand relationships between projects
3. **Include versions** - Track documentation evolution over time

## Next Steps

* Learn about the [OpenDocs Model](/opendocs/opendocs-model) to understand Projects, DocItems, and DocBlocks
* Explore the [Design Principles](/opendocs/design-principles) behind OpenDocs

## RFC Feedback

This file organization specification is part of the OpenDocs RFC. Please provide feedback on:

* File organization patterns and use cases
* `$ref` usage and resolution strategies
* ID naming conventions and best practices
* Any confusion or unclear aspects

Submit feedback via [GitHub Issues](https://github.com/svallory/mintlify-tsdocs/issues) or [Discussions](https://github.com/svallory/mintlify-tsdocs/discussions).
