All write-ups

ResearchGo

Launching soon

A platform for CIBES Research Centre that takes an academic paper from submission to publication. Built and in its last checks before launch.

My role
Architecture and development
Year
2026
Built with
Next.js · Supabase (EU) · Python · FastAPI · GROBID · OpenAlex · Stripe
AUTHOR: PDF OR WORDNEXT.JS + SUPABASEPYTHON WORKER: FASTAPI + GROBIDVERSIONS: ENCRYPTEDTRACK CHANGES, REFERENCE CHECKJOURNAL MATCH: OPENALEXSIGN INSIGNED JOBPARSED TEXTCOMPAREEMBEDDINGALL DATA IN THE EURULES ONLY, NO LANGUAGE MODELTEXT STAYS ON OUR WORKER

Scroll sideways to see the whole diagram.

ArchitectureUPLOAD → PARSE ON ARRIVAL → ENCRYPTED VERSIONS → EDITOR TOOLS

The problem

Academic submissions run on email threads and spreadsheets. Versions, reviewer comments and journal requirements drift apart as soon as more than one person is involved, and editors answer the same questions by hand every time: which version is this, what changed, do the references check out, which journal fits?

How it is built

A Next.js app on Supabase, with all data kept in the EU. Authors sign in with ORCID or email and upload a manuscript as PDF or Word. A Python worker (FastAPI) parses it on arrival, PDFs through GROBID, and sends the structured text back over a signed, timestamped callback that rejects forged or replayed jobs. Each successful parse becomes a new version, stored encrypted, but only if the text actually changed. Editors compare any two versions with Word-style track changes, check in-text citations against the reference list, and get journal suggestions ranked by meaning, using embeddings computed on our own worker with journal data from OpenAlex. Payments run on Stripe.

Decisions that mattered

  • No language model where a rule will do

    Track changes and the reference check are deterministic code, with no AI involved. An editor has to trust a diff, and a rule gives the same answer every time.

  • Manuscripts never leave our servers

    Journal matching embeds the paper on our own worker, so no manuscript text goes to a third party. The ranking is pure similarity. Index, open-access and fee details are shown as labels and never change the order.

  • Every job is signed

    Jobs between the web app and the worker carry an HMAC signature and a timestamp. A forged or replayed job is rejected, and a worker that dies mid-job does not lose the manuscript's place.

Code from the repo

apps/web/lib/versions/diff.tsTrack changes between two manuscript versions, without a language model
function diffParagraphPair(before: string, after: string): DiffSegment[] {
  return diffWordsWithSpace(before, after).map((part) => ({1
    op: part.added ? "ins" : part.removed ? "del" : "equal",
    text: part.value,
  }));
}
 
export function diffManuscripts(before: string, after: string): DiffResult {
  const a = splitParagraphs(before);
  const b = splitParagraphs(after);
  // …
  const parts = diffArrays(a, b);2
  let i = 0;
  while (i < parts.length) {
    const part = parts[i];
    if (!part) break;
    if (!part.added && !part.removed) {
      // …
      i++;
      continue;
    }
    const next = parts[i + 1];
    const paired = Boolean(part.removed && next?.added);3
    const removedList = part.removed ? part.value : [];
    const addedList = part.added ? part.value : paired && next ? next.value : [];
 
    const pairs = Math.min(removedList.length, addedList.length);
    for (let k = 0; k < pairs; k++) {
      const segments = diffParagraphPair(removedList[k] as string, addedList[k] as string);
      paragraphs.push({ kind: "changed", segments });
      // …
    }
    // …
    i += paired ? 2 : 1;
  }
 
  return { paragraphs, summary };
}
  1. Line 2. Inside a changed paragraph the diff runs word by word and keeps the spacing, so it reads like track changes in Word.

  2. Line 12. First pass: a longest-common-subsequence diff over whole paragraphs finds what stayed, what was added and what was removed.

  3. Line 23. A removal followed directly by an addition is one edited paragraph, not two separate changes.

Where it is now

Built and in its last checks. It launches as soon as they are done.

Next write-upÜrünereklam