This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Dockstore UI2 is the Angular front end for Dockstore, a registry of bioinformatics tools, workflows, services, notebooks and apptools. It talks to the backend in the separate dockstore/dockstore repo; the CLI (dockstore/cli) and user-facing documentation (dockstore/dockstore-documentation) are also separate repos, and the project has a discussion forum at https://discuss.dockstore.org/. Issues are tracked in the dockstore/dockstore repo, not here.
Favor Angular's own recommended libraries/patterns (and Angular Material/CDK) for things it has an opinion on over ad hoc alternatives. Beyond that, prefer, in order: (1) built-in TypeScript/browser/Angular features, (2) a third-party library already in package.json, (3) a new third-party dependency — only reach for a new one when neither of the above covers the need (and see the PR checklist items on npm audit and CVE due diligence).
Hubflow (gitflow) conventions: develop is the main integration branch and the default PR target, with work on feature/* branches branched from and merged back into develop, hotfix/* for urgent fixes, and release/* cut for releases.
- Always create PRs in draft mode. A human developer must be the one to mark a PR ready for review — don't do it yourself.
- Always check with the user before pushing to GitHub, even to a branch/PR already being worked on in the conversation — a push can kick off a long CI build or interrupt one already running.
- When a GitHub MCP server or
ghis available, diff the work againstdevelop(or the PR's target branch) and minimize stylistic or otherwise-minor changes that inflate the diff, unless they fix something a Codacy finding or other code-quality check actually flagged. - Keep the freeform "Description" and "Review Instructions" sections of
.github/PULL_REQUEST_TEMPLATE.mdbrief — one paragraph each, or two for a genuinely complicated fix. - The template's checklist must be copied into PR descriptions verbatim — never reword, reformat, condense, or append explanatory text to a checklist item. Only toggle
[ ]to[x], and only after actually confirming that item was done/verified for this PR; leave it unchecked otherwise.
When diagnosing a failing build or iterating on an open PR, pull in whatever signal is actually available rather than guessing:
- If
ghor a GitHub MCP server is available, use GitHub Actions results (check runs, job logs — this repo has CodeQL, npm audit, accessibility and license workflows in.github/workflows/) to guide diagnosis and fixes. - If a CircleCI MCP server is available, use its results (workflow/job status, test failures, logs) — lint, unit tests, Cypress and the build run on CircleCI (
.circleci/config.yml). - Codacy findings aren't reliably fetchable through available tooling. If Codacy results seem significant to the task, ask the user to copy-paste them rather than guessing at what Codacy flagged.
- Code review comments from human developers are high-priority direction — investigate each one and propose concrete solutions, even without an explicit instruction to do so. Bot-authored comments (Codacy, Copilot Autofix, etc.) are useful but secondary.
When adding comments to JIRA tickets, clearly indicate that the comment was written by Claude (e.g. lead with a line like "This comment was generated by Claude (Claude Code).").
Node version is pinned in .nvmrc; install with npm ci (don't set CI=true, or the Husky pre-commit hook won't install). Java 21+ and wget are needed because the build generates the API client.
npm run build/npm run build.prod— runsprebuildfirst (writes git version info and regenerates the OpenAPI client, see below), thenng build.npm run start— dev server on :4200, proxying/api,/swagger.json,/openapi.yamlto a webservice onlocalhost:8080(proxy.conf.json). Requires the OpenAPI client to have been generated at least once.npm run lint—ng lint(ESLint).npm test— Karma/Jasmine unit tests in Chrome (watch mode). CI runs:npx ng test --progress=false --watch=false --code-coverage --browsers ChromeHeadless --source-map=false.- Single spec file:
npx ng test --watch=false --browsers ChromeHeadless --include src/app/path/to/foo.component.spec.ts(--includealso accepts a directory or glob). - Cypress e2e: Cypress is not in
package.json(see.circleci/config.ymlfor the version).npx cypress run --spec "cypress/e2e/group1/**/*". Needs Postgres, the UI served on :4200, and a running webservice jar —npm run webservice(scripts/run-webservice-script.sh) downloads the jar, loadstest/${DB_DUMP:-db_dump.sql}and runs migrations. - Smoke tests against a local stack:
npm run test-local-no-auth; othertest-<qa|staging|prod>-*scripts target deployed environments. - After dependency changes:
npm run licenseto regenerateTHIRD-PARTY-LICENSES.csv, then manually review/revert entries that become "unknown".
Prettier (single quotes, printWidth 140) and eslint --fix run on staged files via Husky + lint-staged.
src/app/shared/openapi/ is generated and gitignored — never edit it by hand. scripts/generate-openapi-script.sh (run by prebuild) uses openapi-generator typescript-angular against the webservice's openapi.yaml, chosen by package.json config:
use_snapshot: false→ fetchesopenapi.yamlfrom the dockstore/dockstore GitHub repo at tagwebservice_version.use_snapshot: true→ downloadsdockstore-webservice-${webservice_version_prefix}-SNAPSHOTfrom OICR Artifactory via Maven (the prefix can include a branch name with/replaced by-).- Override without editing the file:
npm pkg set config.webservice_version=....
API services (WorkflowsService, ContainersService, UsersService, MetadataService, …) and models are imported from app/shared/openapi (or shared/openapi). If a backend field/endpoint is missing, the fix is usually bumping the webservice version and regenerating, not hand-writing types. Loose dockstore-webservice-*.openapi.yaml files in the repo root are download byproducts of snapshot builds.
- Bootstrap/config:
app.module.tswires everything; at startupConfigurationService.load()fetches/configfrom the webservice (MetadataService.getConfig()) and copies values into static fields on theDockstoreclass (shared/dockstore.model.ts) — OAuth client IDs, launch-with platform URLs, feature settings. Code readsDockstore.Xstatics rather than injecting config.FeatureServicehandles URL-param feature flags. - Auth: a vendored, modified copy of ng2-ui-auth lives in
src/app/ng2-ui-auth/; the token is stored in localStorage asng2-ui-auth_token.shared/auth.guard.tsprotects logged-in routes; HTTP interceptors are insrc/app/interceptors/. - Routing:
app.routing.tslazy-loads feature areas (containers/tools,workflows,services,apptools,notebooks,my-*,organizations,search,docs,users,aliases). Services, apptools and notebooks are variants of workflows (BioWorkflow/Service/AppTool/Notebookshare the workflow code insrc/app/workflow/andsrc/app/workflows/); tools/containers live insrc/app/container/andsrc/app/containers/. Public entry pages and "my-*" management pages reuse the same entry components. Before adding per-entry-type logic, look for the shared code (src/app/shared/entry/,entry.ts,my-entry.ts,shared/state/) — new entry-type behavior is usually an extension of it, not a new parallel code path. - State: Akita stores. The common pattern is a trio per concern —
foo.store.ts(state),foo.query.ts(selectors/observables),foo.service.ts(actions that call the API and update the store). Global ones are insrc/app/shared/state/(e.g.WorkflowService/WorkflowQueryfor the currently viewed workflow,ExtendedWorkflow*,MyEntries*,Token*); feature areas likesearch/,organizations/,container/have their ownstate/folders. - Search (
src/app/search/) builds Elasticsearch queries withbodybuilderand sends them through the webservice's ES proxy. - Components are standalone (Angular 22); Angular Material +
@ngbracket/ngx-layoutfor layout, Bootstrap 3 CSS still present. Ace editor, Cytoscape (DAGs), Chart.js, marked/KaTeX are loaded as noted inangular.jsonscripts. - Unit test helpers:
src/app/test/holds shared stubs (service-stubs.ts,router-stubs.ts) and fixture objects (mocked-objects.ts,openapi-mocked-objects.ts) — reuse them in specs instead of building new mocks.
cypress/e2e/group1..3run against a webservice loaded withtest/db_dump.sql(or other dumps intest/selected viaDB_DUMP);immutableDatabaseTestsmust not mutate data;smokeTests/sharedTestsrun against any environment (thepackage.jsonsmoke scripts also referenceqaOnly/stagingOnly/prodOnlyspecs that don't currently exist in the repo).- When a smoke test fails in CI it's either a UI change (fix the test) or missing data in
test/smoke_test_db.sql(update the dump). To log in locally as a test user, set localStorageng2-ui-auth_tokentofake-admin-token,fake-curator-tokenorfake-basic-1-token. Never link real accounts when regenerating dumps — the dumps are public; check thetokentable before committing.