Adding a Feature End-to-End
A short worked example: suppose you want to add an endpoint that lists all abstract classes in a graph and surface them in the navigation tree with an italic style.
Step 1 — Backend use case
// services/select/ListAbstractClassesUseCase.java
public interface ListAbstractClassesUseCase {
List<ClassDTO> listAbstractClasses(GraphIdentifier graphIdentifier);
}
Step 2 — Service implementation
Either extend an existing service (if one already holds the same DatabasePort and is logically related — e.g. QueryClassService) or create a new services/select/AbstractClassQueryService that implements the use case and wires the DatabasePort via @RequiredArgsConstructor.
Step 3 — Controller endpoint
Add a new @GetMapping to AllClassesRESTController (or a new controller if a new path tier is involved). Keep the controller thin — call the use case, log on receive and respond.
@GetMapping("/abstract")
@Operation(summary = "list abstract classes", tags = {"class"})
public List<ClassDTO> listAbstract(@PathVariable String datasetName,
@PathVariable String graphURI,
@RequestHeader(...) String originURL) {
logger.info("Received GET request: \".../abstract\" from \"{}\".", originURL);
var result = listAbstractClassesUseCase.listAbstractClasses(...);
logger.info("Sending response to GET request: \".../abstract\" to \"{}\".", originURL);
return result;
}
Step 4 — Tests
- Unit-test the service against the in-memory database (
InMemoryDatabaseImpl). - Integration-test the endpoint with
@SpringBootTest+MockMvcif the routing or DTO shape is non-trivial.
Step 5 — Frontend BackendConnection method
async listAbstractClasses(datasetName, graphURI) {
const url = `${PUBLIC_BACKEND_URL}/datasets/${encodeURIComponent(datasetName)}/graphs/${encodeURIComponent(graphURI)}/classes/abstract`;
return fetch(url, {
method: "GET",
credentials: "include",
});
}
Step 6 — Reactive consumer
Either update the existing class-list reactive store or read on demand from a component. If the navigation tree needs to mark the abstract ones, extend build-nav-object.js to include the abstract flag on each class node, and update ClassEntry.svelte to render italic when the flag is set.
Step 7 — Tests
Vitest unit tests for any new logic in lib/. Manual smoke test through the UI; include a live Fuseki instance when the feature touches snapshots.
Step 8 — PR
Follow the squash commit format and the pre-merge checklist in CONTRIBUTING.md. Update CHANGELOG.md under ## [Unreleased] if the change is user-facing.