Skip to content

feat(website, backend): Sequence citations #6491

Open
tombch wants to merge 132 commits into
mainfrom
sequence-citations
Open

feat(website, backend): Sequence citations #6491
tombch wants to merge 132 commits into
mainfrom
sequence-citations

Conversation

@tombch

@tombch tombch commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Backend Changes

  • Adds a get-sequence-citations endpoint, which returns citing sources for seqsets that include the sequence entry.
  • The endpoint requires an accession for the sequence entry, with version as an optional parameter. If only the accession is provided, the endpoint returns citing sources for seqsets which use any version {accession}.*, as well as unversioned {accession}, of the sequence entry. If both an accession and version are provided, the endpoint returns citing sources which reference that exact {accession}.{version}.

Website Changes

  • Adds a CitationList component to display the first N citations (in this case, currently three) directly on the sequence details page, and adds a 'view all citations modal', clickable if they exceed this number.
  • The displayed citations also include the seqset they came from, and how the sequence was used (i.e. pinned version or unversioned).

Screenshot

image

PR Checklist

  • All necessary documentation has been adapted.
  • The implemented feature is covered by appropriate, automated tests.
  • Any manual testing that has been done is documented (i.e. what exactly was tested?)

🚀 Preview: Add preview label to enable

tombch and others added 30 commits April 27, 2026 16:30
…d exposing doiPrefix for use outside of the service
…, added periodic task to update citations with crossref results
… citing sources, with source ID that can be either a DOI or URL if a manual citation does not have a DOI
@tombch tombch marked this pull request as ready for review June 12, 2026 15:43
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @tombch's task in 2m 57s —— View job


Code Review

  • Read changed files and gather context
  • Review backend changes (API, controller, database service, security config, tests)
  • Review website changes (components, services, types, pages)
  • Post inline comments for specific issues
  • Write overall review summary

The feature is well-structured — the backend query logic (using LikePattern.ofLiteral for safe LIKE matching, the 5-table join grouped by citation source) is correct, the CitationList inline-preview-plus-modal pattern is a reasonable UX, and the unwrapOr(undefined) fallback keeps citation failures from breaking the sequence details page.

Four things worth addressing before merge (inline comments added):

  1. Non-deterministic ordering (SeqSetCitationsDatabaseService.kt:546) — getSeqSetCitations orders by year DESC but getSequenceCitations has no orderBy, so results are non-deterministic. Add the same ordering.

  2. Missing @Operation annotation (SeqSetCitationsController.kt:115) — all other methods in the controller have this for Swagger; getSequenceCitations is missing it.

  3. Version-agnostic citation fetch on version-specific pages (index.astro:21, details.json.ts:17) — the call always omits version, so /seq/ABC.1/ shows citations for all ABC versions. This may be the intended behaviour, but it's worth a comment to make it explicit; the plumbing to pass version is absent if requirements ever change.

  4. No auth test for the new public endpoint (CitationEndpointsTest.kt:301) — the authorizationTestCases list doesn't include getSequenceCitations. Adding it with isModifying = false would document the intended public access.

One minor UI nit on CitationTable.tsx:39-47: multiple seqSets in the "From SeqSet(s):" row render without separators and can run together — see inline suggestion.

Comment thread website/src/pages/seq/[accessionVersion]/index.astro Outdated
Comment thread website/src/components/SeqSetCitations/CitationTable.tsx
Comment thread website/src/pages/seq/[accessionVersion]/index.astro Outdated
Comment thread website/src/components/SeqSetCitations/CitationTable.tsx
@anna-parker anna-parker self-requested a review June 15, 2026 10:14
@theosanderson

Copy link
Copy Markdown
Member

@codex review

</div>
)}

{hasSequenceCitations && <hr className='my-8 border-t-2 border-gray-200' />}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it could just be folded into the sections above, with no horizontal rule?

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e710bbee7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +21 to +23
const sequenceCitationsPromise = SeqSetCitationClient.create().call('getSequenceCitations', {
params: { accession }, // Display citations across all accession versions
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard citation fetching behind the SeqSets flag

When SeqSets are disabled, the existing /seqsets routes are hidden/rewritten via seqSetsAreEnabled(), but this sequence page still unconditionally waits for getSequenceCitations before rendering. In seqset-disabled deployments that adds a failing backend request to every sequence detail load, and if the backend route is still enabled it can render Cited in links to pages the website intentionally disables; gate this request, and the matching details.json request used by previews, on the SeqSets feature flag.

Useful? React with 👍 / 👎.

@Schema(description = "A citation of a SeqSet.")
data class SeqSetCitation(val source: CitationSource)

data class SeqSetCitingSequence(val seqSetAccession: String, val sequenceAccession: String)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might have a specific type for loculus accessions and seqSetAccessions in the backend

}

fun getSequenceCitations(accession: String, version: Long?): List<SequenceCitation> {
log.info { "Get sequence citations for accession $accession, version $version" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably not log " version " when version is empty

// Otherwise, return all citations for the accession, regardless of version, including unversioned
val accessionQuery: Op<Boolean> = if (version != null) {
val accessionVersion = AccessionVersion(accession, version)
SeqSetRecordsTable.accession eq accessionVersion.displayAccessionVersion()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you could leave a comment somewhere that accession can be accession and accessionVersion - I wonder if we should actually refactor the table to have an accession and version column instead of having to parse the contents of the accession column


return SeqSetCitationSourceTable.innerJoin(
SeqSetToCitationSourceTable,
).innerJoin(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we discussed that the seqsettorecordstable can actually be dropped and the seqsetrecordstable refactored as:

object SeqSetRecordsTable : Table("seqset_to_records") {
    val seqSetRecordId = long("seqset_record_id").autoIncrement()
    val accession = varchar("accession", 255)
    val type = varchar("type", 255)
    val isFocal = bool("is_focal").default(true)
    val seqSetId = varchar("seqset_id", 255) references SeqSetsTable.seqSetId
    val seqSetVersion = long("seqset_version") references SeqSetsTable.seqSetVersion
    override val primaryKey = PrimaryKey(seqSetRecordId, seqSetId, seqSetVersion)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend related to the loculus backend component website Tasks related to the web application

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants