backend
FreeBackend Java — Spring Boot controllers/services, JUnit controller tests, MakeMe. Read this first for any backend work. Use when working on the Java Spring backend.
The English summary is being prepared. Showing the original description.
E2E testing with Cypress and Cucumber, feature files, step definitions, page objects, fluent interface, assertions, data-app-busy / waitUntilAppIsNotBusy pairing, test execution. Use when writing Cypress/Cucumber E2E tests.
The English summary is being prepared. Showing the original description.
Run score Not tested
See how to installReview the instructions the agent will receive before you install.
Use this skill when writing or modifying E2E tests, Cypress/Cucumber feature files, step definitions, page objects, or E2E assertions. For OCR-specific canvas assertions, use the e2e-ocr skill.
The pnpm cy:run wrapper owns its stack and compiles current backend source once per batch, without a continuous backend compiler. Local batches retain frontend HMR; backend edits need a new invocation. Use pnpm cy:open for an interactive session with backend reload and frontend HMR. Required mocks are owned by the selected invocation.
If services are not running, suggest running pnpm cy:run --spec <feature> in a separate terminal.
Primary unconfigured checkouts and CI use http://localhost:5173 as the Cypress
app origin through the local load balancer. A linked worktree (or a primary
with .worktree.local.json) uses that checkout's isolated origin
http://127.0.0.1:<lbListenPort> — see docs/worktree-browser-tests.md. Isolated
Cypress accepts one or more selections from the assessed active feature set
declared in scripts/isolated-cypress-spec-selection.mjs (application-only
active specs plus the active CLI, MCP, OpenAI-mock, and Wikidata-mock focused
specs) per run; a new feature file must be added to that set (e.g.
APPLICATION_ONLY_ACTIVE_SPECS in scripts/isolated-cypress-active-specs.mjs) before an
isolated run accepts it. The CLI command is scoped to the assessed active CLI workflows.
The MCP command is scoped to that one search/graph feature. OpenAI-mock specs
start a runner-owned private OpenAI Mountebank; Wikidata-mock specs start a
runner-owned private Wikidata Mountebank; application-only, CLI, and MCP specs
do not require Mountebank. Each isolated checkout needs its own healthy E2E
allocation. Paired CLI-vs-browser reset proof:
CURSOR_DEV=true nix develop -c node scripts/worktree-reset-isolation-harness.mjs --mode cli --peer <cli-checkout> --resetter <browser-checkout>
CI vs pnpm cy:run, wait-on, NO_PROXY, and env vars are documented in
docs/gcp/prod_env.md, Local dev / Cypress under section 6.
Agents should default to pnpm cypress run --spec with one or more .feature paths tied to the changed capability. Add adjacent specs only when regression risk warrants it. Do not run bare pnpm cypress run, pnpm verify, or the whole suite unless the user explicitly asks for a full E2E run or the instructions require reproducing CI.
CURSOR_DEV=true nix develop -c pnpm cypress run --spec e2e_test/features/ai_generated_recall_questions/question_contest.feature
Important notes:
cypress run -- --spec; the empty -- causes the --spec parameter to be ignored.expose.tags in e2e_test/config/ci.ts, for example not @ignore. Override per raw pnpm cypress run with --expose tags='...' (-x; the pnpm cy:run wrapper drops it), not --env tags=... (ignored by @badeball/cypress-cucumber-preprocessor v27 on Cypress >= 15.17).@skipOptimizationDueToKnownNecessarySlowness is Donut's profile-only
exclusion for known-necessary slowness. dough-test-optimization profiles
exclude it as described under "Test-optimization profiling" below.
Normal CI/dev runs still execute these scenarios. Do not add this tag without
developer review, except when an explicit dough-test-optimization --resolve
pass makes an evident exclusion under the public skill's candidate-resolution
rules.@focus and @only are local debugging aids only. Do not commit them; CI runs ./scripts/check_focus_tags.sh on .feature files to block @focus, and @only should be treated the same.@focus or @only, @badeball/cypress-cucumber-preprocessor filters scenarios in that file to @focus or @only only.For per-scenario timing, run the selected feature scope through the owning wrapper and tee its output to a local file:
CURSOR_DEV=true nix develop -c pnpm cy:run --spec '<feature,feature,...>' 2>&1 | tee /tmp/donut-e2e-profile.log
--spec (and --browser) to Cypress
(scripts/e2e-cypress-process.mjs); --reporter and --expose tags=...
are dropped. Apply the profile-only exclusion by leaving
@skipOptimizationDueToKnownNecessarySlowness features out of the spec list,
and subtract excluded scenarios inside a selected feature from the profile.✓ <scenario> (<N>ms) lines;
associate them with the preceding Running: <feature> line..worktree.local.json) refuses glob spec selections; list the features
comma-separated. If mirroring CI, also leave out @wip features.This exclusion is profiling-only and must not narrow normal verification.
Use the canonical log-tail command for backend E2E log inspection:
CURSOR_DEV=true nix develop -c pnpm logs:tail backend-e2e
Frontend Vite checker terminal errors still matter even though the browser overlay is disabled for E2E stability. For canonical lint and format commands, use the linting_formating skill.
e2e_test/features contains BDD-style tests.e2e_test/step_definitions contains step definitions.e2e_test/start/ contains page objects.e2e_test/start/pageObjects/cli/ contains CLI page objects with the cli.xxx prefix.e2e_test/support/ contains support files.Behavior (external behavior) has 3 parts: pre-condition, trigger, and post-condition. Each part is:
Avoid e2e test that is only about the presentation of a state and having no state change after setup / given.
note_creation.feature or spaced_repetition.feature. Never name them by planning sequence number or delivery order.@usingMockedOpenAiService or @mockBrowserTime, to control test execution.Scenario Outline with an Examples table when the path and assertion focus are the same and only data varies. Do not copy-paste near-identical Scenarios for different inputs. Keep separate Scenarios when the observable behavior differs (see Explicit Conditions and step-definition guidance on variants).When("I start a conversation about the note {string}", (noteTopology: string) => {
start.jumpToNotePage(noteTopology).startAConversationAboutNote()
})
Use page objects with a fluent interface: methods perform an action and return the next page object, or this when staying on the same screen. This keeps step definitions short and navigation explicit in the types.
Navigation (ADR 0005). E2E navigation goes through e2e_test/start/router.ts
(visitNamed / named push). Compile hrefs with namedLocationHref /
noteShowHref. Page objects and steps do not call cy.visit with SPA path
strings (scripts/check_e2e_spa_visit_gate.sh in CI).
Signing in only establishes the session; it does not open the app. The first
router().push opens it, page objects that start from the Donut menu use
withinDonutMenuItem (which calls router().openApp()), and a re-login
reloads an app the scenario already opened. A scenario that never touches the
web UI pays no page load.
| Intent | Mechanism |
|---|---|
| Unique trigger is in-app navigation | UI |
Given-shaped shortcut (including Gherkin When I visit … when the unique behavior is on that screen) | Named router.push after first load |
| First SPA load, inbound URL, or explicit remount | cy.visit of href compiled from the named table |
Recall: visitRecallPage is remount (visitNamed('recall'));
navigateToRecallPage is sidebar UI. Gherkin When I visit recall
stays remount — do not convert it to sidebar.
Centralize UI interactions in page objects.
Prefer fluent chaining over one-off helpers that do not return a navigable object.
Keep page objects focused on a single responsibility.
Use meaningful method names that reflect user actions.
const notePage = {
startAConversationAboutNote() {
this.toolbarButton("Start a conversation").click()
return conversationPage()
},
}
CLI steps use cli.xxx page objects, not start.xxx. For the install feature, use cli.backend(), cli.installation(), and cli.nonInteractiveOutput() for spawned version / update stdout. The @interactiveCLI-tagged CLI files (cli_access_token.feature, cli_interactive_mode.feature, cli_recall.feature) and cli_gmail.feature are @ignore in CI; extend Vitest under cli/tests/interactive/ for interactive TTY coverage instead of adding a second Cypress PTY harness.
Then("I should see {string} in the non-interactive output", (expected: string) => {
cli.nonInteractiveOutput().expectContains(expected)
})
Product loading UI that means unfinished work marks itself with data-app-busy (LoadingThinBar from apiCallWithLoading, ContentLoader for pending page data, LoadingModal for blockUi). See .agents/skills/frontend/SKILL.md.
E2E waits with waitUntilAppIsNotBusy() from e2e_test/start/pageBase.ts (also start.waitUntilAppIsNotBusy()):
import { waitUntilAppIsNotBusy } from '../pageBase'
cy.findByRole('button', { name: 'Submit' }).click()
waitUntilAppIsNotBusy()
Rules of thumb:
waitUntilAppIsNotBusy() in the page object on the action that starts loading, before the next step that needs that work’s result.cy.wait(ms)) for this.cy.intercept / cy.wait('@…') is optional; it is not the documented default stand-in for this product/E2E pair.Follow test data and service mocking when writing Given setup or external-service fixtures.
Error messages must be immediately actionable:
expectQuizScore(expectedScore?: string) {
if (expectedScore) {
cy.get("[data-test='quiz-score']").should(($score) => {
const actualScore = $score.text().trim()
expect(
actualScore,
`Expected quiz score to be ${expectedScore}, but found ${actualScore}`
).to.equal(expectedScore)
})
}
return this
}
A scenario describes one fixed path. Prefer dumb automation: the path is visible in Gherkin and in small, purpose-named page-object methods, not inferred at runtime from a string or flag.
if / switch trees, parameter sniffing, and mode flags in steps and page objects except when the branch exists only to assert or fail fast with a clear error.cli/tests/interactive/ instead of adding a second Cypress PTY stack.@badeball/cypress-cucumber-preprocessor defaults Before hooks to order 10000. The shared DB reset Before uses order: 0 so it runs before tagged setup. Hooks that start long-lived side effects (e.g. @interactiveCLI PTY at order 2) must stay after that reset; otherwise truncate can block on MySQL locks held by the PTY’s HTTP traffic.
waitUntilAppIsNotBusy() (or a clearer user-visible success signal) first.No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Backend Java — Spring Boot controllers/services, JUnit controller tests, MakeMe. Read this first for any backend work. Use when working on the Java Spring backend.
The English summary is being prepared. Showing the original description.
Backend Java production code, Spring Boot controllers/services/repositories, controller return values, imports, schema ERD pointer. Use when editing backend production Java.
The English summary is being prepared. Showing the original description.
Backend Java tests, controller-level stable-boundary tests, JUnit, @Nested, MakeMe builders, @Transactional, parameterized tests. Use when writing or changing backend JUnit tests.
The English summary is being prepared. Showing the original description.
related to donut CLI. Use when working on donut-cli.
The English summary is being prepared. Showing the original description.
Set up and run the Donut dev environment on Cursor Cloud VM (no Nix). Use when working on Cloud VM, running tests on Cloud VM, or encountering command errors related to missing nix. Triggers on: cloud VM, cloud agent, no nix available, /workspace path.
The English summary is being prepared. Showing the original description.
Regenerate docs/database-erd.md from MySQL information_schema (Mermaid ERD: foreign keys and key columns). Use after Flyway schema changes, new migrations, or when the diagram is stale. Triggers on: database ERD, database-erd.md, export_database_erd, schema diagram, ER diagram after migration.
The English summary is being prepared. Showing the original description.