SDODS
Guides

Organizations, workspaces, projects and modules

The four-level hierarchy SDODS uses to organise automation across teams and applications.

What you'll learn

How organizations, workspaces, projects and modules nest, which file declares each level, what a module adds on top of a features folder, and how the demo project is modelled.

The hierarchy

LevelDeclared inHolds
Organizationsdods.workspace.yaml → organizationa company or product line; membership roles member, admin, owner
Workspacesdods.workspace.yaml → workspaces[]a team or product area; an organization holds many, and defaultWorkspace names the one projects join unless they set workspace:; defaults for browsers, suites, test-id attribute and shared processes; membership roles viewer, editor, admin
Projectprojects/<slug>/sdods.project.yamlone application: layers, browsers, environments, data, auth, screenshots, modules, processes
Modulemodules: inside the project YAMLone functional area: a folder under features/, its testing types, expected tags, owner, Jira component, routes and endpoints

The workspace file

sdods.workspace.yaml
organization:
  slug: sdods
  name: SDODS
  url: https://example.com/sdods
workspaces:
  - slug: default
    name: Default workspace
    organization: sdods
  - slug: platform-qa
    name: Platform QA
    organization: sdods
defaultWorkspace: default
defaults:
  browsers: [chromium, firefox, webkit]
  suites: [smoke, regression, sanity]
  testIdAttribute: data-testid
  processes:
    - {
        name: pr-check,
        trigger: pr,
        tags: '@smoke',
        browsers: [chromium],
        harMode: replay,
        gates: { minPassRate: 100 },
      }

Projects inherit defaults and may override any of them. A project joins a workspace with workspace: <slug> (one of workspaces[]); when omitted it joins defaultWorkspace. organization: must match the file's organization. sdods workspace tree prints the result, and sdods db sync mirrors it into the database so the web UI can show workspaces with each user's effective role. Creating a workspace on the web UI's Workspaces page (organization owners and admins) appends it to workspaces[] in this file and then syncs, so projects can join it straight away; commit the file change to keep it.

Modules

projects/demo-shop/sdods.project.yaml
organization: sdods
workspace: default
modules:
  - name: auth
    title: Authentication
    path: auth # features/auth/ (default: the module name)
    layers: [ui]
    testingTypes: [functional, smoke, regression, data-driven]
    tags: ['@auth']
    routes: [login]
  - name: inventory
    title: Inventory
    path: inventory
    layers: [ui]
    testingTypes: [functional, regression, visual, accessibility]
    tags: ['@inventory']
    routes: [inventory]
  - name: cart
    title: Cart
    path: cart
    layers: [ui]
    testingTypes: [functional, regression]
    tags: ['@cart']
    routes: [cart, checkout]
  - name: posts-api
    title: Posts API
    path: api
    layers: [api]
    testingTypes: [functional, contract, smoke, regression]
    tags: ['@posts']
    endpoints: ['/posts', '/posts/{id}', '/posts/{id}/comments']
  - name: hybrid
    title: Hybrid flows
    path: hybrid
    layers: [hybrid]
    testingTypes: [integration]
    tags: ['@hybrid-demo']

What a module gives you:

  • Lint warns when a scenario under features/<module>/ lacks one of the module's expected tags.
  • Coverage joins routes and endpoints with scenarios per suite tag.
  • Run selection: sdods run -p demo-shop --module cart runs one module; processes may list modules:.
  • Reporting: runs, scenario trees and insights group by module, in the CLI and the web UI.

owner and jiraComponent are stored and synced to the database, but nothing consumes them yet — they do not appear on created GitHub or Jira issues today. Set them if you want the metadata in place; do not expect them to route anything.

How modules are detected

sdods analyze proposes the modules: block for you. It does not group by URL, because a URL often says nothing about the domain: in the workshop application POST / is the bank-account endpoint and /contacts plus /personal are both transaction screens. Instead several signals vote, and the strongest one wins each route:

SignalWeightWhat it reads
openapi-tag1.00the tags on an OpenAPI operation
workspace0.90the monorepo package owning the file (pnpm-workspace.yaml, turbo.json, nx.json)
domain-dir0.80src/modules/<x>/, src/features/<x>/, src/domains/<x>/, services/<x>/
source-file0.70the file that defines the route — auth.ts, user-routes.ts, UserController.java
route-segment0.30the first URL segment, as a floor so nothing is left unassigned
alias0.20folds login, signin, logout, session and friends onto auth; merges only, never creates

Role suffixes are stripped (bankaccount-routes.ts → bankaccount), PascalCase is split (TransactionsContainer.tsx → transactions), and file-router parameters are skipped so app/products/[id]/page.tsx becomes products, not id. A file that names a role rather than a domain (app.ts, index.ts, page.tsx) yields nothing and lets a weaker signal decide.

Routes that cannot name anything — catch-alls (/*), optional groups (/(public)?) and a bare root in a generic file — are skipped and listed, rather than collected into a home bucket. A path that is uninformative on its own is still kept when its file names a domain: GET /{username} in contact-routes.ts is the contact module.

The proposal prints the winning signal, the confidence and the file behind every module, so you can judge it before writing anything. See the workshop's first chapter.

A module is metadata over a folder. Nothing stops you from starting with the plain features/ui, features/api, features/hybrid layout and adding modules when a project grows.

Next steps

Using an AI coding agent? Install SDODS:

Install the SDODS plugin in Claude Code: skills, subagents, commands and the MCP server.

  1. /plugin marketplace add YarlisAISolutions/sdods-skills
  2. /plugin install sdods@sdods
Learn more about using SDODS with AI tools

On this page