SDODS
Workshop

1 · Analyze and apply

Read an unknown repository, review what it proposes, write the project, and correct the guesses it could not make.

What you'll learn

What sdods analyze can work out from an application it has never seen, how to read its evidence, and which five things you have to decide yourself before the project is yours.

An engineer passing a magnifier over an application repository while findings — framework, routes, test id attribute, existing specs — pop out as labelled stickers; the repository carries a read-only padlock../your-apppackage.jsonsrc/containers/backend/routes.tscypress/tests/.envread-onlyExpress 4.20React Router 5.37 pages · 10 endpointsdata-test ×10733 Cypress specs90% confidence80% confidenceread from the routercounted, not guessedlocators to migrate
analyze opens files and closes them again. Everything it reports has a file and a line behind it.

Time: 15 minutes · You need: the application cloned; it does not have to be running yet.

Look before you write

sdods analyze ../cypress-realworld-app
Analysis header: 196 files scanned, yarn, Express, React Router, React and Vite with confidence scores, data-test with 107 uses, detected authentication libraries and base URLs
196 files, four frameworks, one test-id attribute counted 107 times. Nothing has been written.

Read the checklist at the end of the report before anything else. It is the part that tells you what this repository will cost you:

Checklist noting the data-test attribute, no OpenAPI specification, CSS-heavy Cypress locators, no accessibility tooling and a guessed authentication strategy
Two warnings, four notes, and a command attached to the ones that have a fix.

--report-only prints the analysis without the proposal. The global --json flag prints the whole thing as JSON, which is what you want if you are onboarding twenty repositories and want a spreadsheet at the end.

How modules are decided

The part of the proposal worth reading closely is the module list. A module is the unit you will later lint, run and report on (sdods run --module auth), so a bad split costs you for the life of the project.

Modules are not grouped by URL. On this repository that would give you fourteen of them, with /login, /signin, /logout and /checkAuth as four separate modules and POST / filed under home. Instead several signals vote and the strongest wins each route — the file that defines the route outranks the path it serves:

Module table listing testdata, transactions, user, app-okta, bankaccount, contact and auth with confidence scores, the winning signal and the source file behind each, followed by three skipped routes
Seven modules, each with the confidence, the signal that won it and the file it came from. Three routes were skipped rather than guessed at.

Three lines explain the whole design:

  • auth collected /login, /logout and /checkAuth because they share backend/auth.ts — one file, one module, no synonym list required. The +alias on that row is the second signal pulling the React sign-in screens (/signin, /signup) into the same module, which is why it is the only row spanning both a UI and an API layer.
  • bankaccount exists even though its route is literally POST /. The URL carries nothing; the filename carries everything.
  • transactions is a name that appears in neither of its URLs (/contacts, /personal). It comes from TransactionsContainer.tsx — which is the domain name a person would have chosen.

The confidence column is the mean weight of the winning votes. 0.70 is the source-file signal on its own; auth scores lower at 0.54 precisely because it merged a weaker alias vote in. A low score is a prompt to look, not a defect.

Write the project

sdods analyze ../cypress-realworld-app --apply --project rwa-bank --name "RWA Bank"
Four generated files flying into a project folder, with a green tick on the foldersdods.project.yamlenvs/local.yamlfeatures/ ×14pages/ · steps/projects/your-app
One project directory: YAML you can read, Gherkin you can edit, TypeScript you own.
sdods lint -p rwa-bank
Lint output reporting fifteen feature files with no findings
Lint is the fastest feedback in the product. Run it after every edit; it takes milliseconds.

Correct the five guesses

The analyzer is literal on purpose: it reports what the files say and marks its confidence, rather than inventing a configuration you would later have to unpick. On this repository five things need a person.

The API port

.env publishes PORT=3000 for the front end and VITE_BACKEND_PORT=3001 for the API, and the analyzer takes the obvious one for both.

projects/rwa-bank/envs/local.yaml
api:
  baseUrl: http://localhost:3001

The sign-in selectors

It guessed [data-test="username"]. The application spells them signin-username — and puts the attribute on the Material UI wrapper, so the selector has to reach the control inside it.

projects/rwa-bank/sdods.project.yaml
auth:
  strategy: form
  storageState: true
  form:
    loginPath: /signin
    usernameSelector: '[data-test="signin-username"] input'
    passwordSelector: '[data-test="signin-password"] input'
    submitSelector: '[data-test="signin-submit"]'
    readyUrl: /

The routes that are not addresses

React Router patterns (/*, /(public)?) and the bare root are not pages you can open, and the analyzer now skips them itself — they are the three lines under skipped in the module table above, and no module is created for them.

One is left for you. The Okta-only /implicit/callback is a real path, so it survives detection and brings an app-okta module with it. This application is not configured for Okta, so delete that module and its route, and add the real home page.

projects/rwa-bank/sdods.project.yaml
routes:
  home: /
  contacts: /contacts
  personal: /personal
  signin: /signin
  signup: /signup

The auth strategy stub

The generated steps/auth.ts exports strategy: 'none', which makes auth capture skip every user. The application has a form login:

projects/rwa-bank/steps/auth.ts
import { defineAuth } from '@sdods/core/auth';

export const auth = defineAuth({ strategy: 'form' });

The pool users

data/common/users.csv arrives with placeholders. The application seeds real accounts and its own README publishes their password, so the workshop can use them as they are.

projects/rwa-bank/data/common/users.csv
id,username,password,role,displayName
1,Heath93,${RWA_PASSWORD:-s3cret},standard,Ted Parisian
2,Arvilla_Hegmann,${RWA_PASSWORD:-s3cret},standard,Kristian Bogan
3,Dina20,${RWA_PASSWORD:-s3cret},admin,Darrel Ortiz

The ${VAR:-default} form is how every secret in SDODS is written: the file is committable, and a real environment overrides it from .env.local.

Checkpoint

sdods lint -p rwa-bank && sdods coverage -p rwa-bank --routes

You should see no lint findings and a coverage line reading routes 4/4 endpoints 9/9 roles 0/2. Roles being zero is correct — nothing signs in yet. That is chapter 2.

If coverage reports routes you deleted, you edited sdods.project.yaml but left the generated features behind. Remove features/<module>/ for each module you dropped.

On this page