# Skola Word Plugin — Human Guide to the Codebase

This document is your map. It explains what Skola is, how it is built, what each file does, and how all the pieces connect. You do not need prior familiarity with the code to follow it.

---

## What Is Skola?

Skola is a **Microsoft Word add-in** that brings academic writing tools directly into Word. Users get a task pane (a sidebar inside Word) where they can:

- Import and manage citations (RIS, XML, EndNote formats)
- Generate formatted bibliographies (APA 7, Harvard, MLA 9, Chicago 17, IEEE, Vancouver)
- Proofread and improve their writing with AI
- Ask AI to summarise, critique, rewrite, or extend sections of their document
- Search academic databases (Crossref, OpenAlex, Semantic Scholar) for sources that support a claim

The system has two running processes that talk to each other:

| Process | What it is | Where it runs |
|---------|-----------|---------------|
| **Word Add-in** | The UI panel inside Word | `https://localhost:3000` |
| **API server** | The backend that does heavy lifting | `http://localhost:4000` |

---

## Languages & Technologies

| Layer | Language / Tool | Why |
|-------|----------------|-----|
| All TypeScript | TypeScript (strict) | Type safety across client, server, and shared contracts |
| Backend | **Fastify** (Node.js) | Fast, schema-friendly HTTP server |
| Frontend | Vanilla TypeScript + DOM | No React — keeps bundle small and compatible with Word's old webview |
| Bundler | **Webpack + Babel** | Transpiles to ES5 so it works in older versions of Word on Windows |
| Testing | **Vitest** | Fast unit tests for backend services |
| AI | **Claude API** (Anthropic) | Proofreading, rewriting, and critique |
| Academic search | Crossref, OpenAlex, Semantic Scholar | Free academic paper search APIs |
| Styling | Plain CSS | Custom design — no framework |

---

## Folder Tree

```
Skola_Word_Plugin/
│
├── apps/                          ← The two runnable applications
│   ├── api/                       ← Backend: Node.js API server
│   └── word-addin/                ← Frontend: Word task pane
│
├── packages/
│   └── shared/                    ← Shared TypeScript types used by both apps
│
├── docs/                          ← Documentation (you are here)
│   ├── TECHNICAL_ARCHITECTURE.md  ← Deep technical reference
│   └── human.md                   ← This file
│
├── PRD.md                         ← Product requirements document
├── actionplan.md                  ← Delivery checklist (what is done / in progress)
├── README.md                      ← Quick start instructions
├── package.json                   ← Root monorepo config (workspaces + shared scripts)
├── tsconfig.base.json             ← Base TypeScript config inherited by all packages
├── .env.example                   ← Template for environment variables
└── .gitignore
```

---

## `packages/shared/` — The Contract Layer

Before looking at the apps, understand `shared` — it is the foundation both apps build on.

```
packages/shared/
└── src/
    └── index.ts    ← Every shared type, enum, and interface lives here
```

**`src/index.ts`** defines:

- **`CitationStyle`** — enum: `APA7 | HARVARD | MLA9 | CHICAGO17 | IEEE | VANCOUVER`
- **`ProofreadMode`** — enum: `proofread | formalize | simplify | shorten | expand | paraphrase | coherence`
- **`AiAction`** — enum: `summarize | critique | rewrite | add_section`
- **`SearchIntent`** — enum: `support | foundational | recent | conflicting`
- **`CitationLibrarySource`** — the full shape of a citation record (title, authors, year, journal, DOI, etc.)
- **`ProofreadRequest / ProofreadResponse`** — what the frontend sends and what the API returns for proofreading
- **`AiActionRequest / AiActionResponse`** — same for AI writing actions
- **`SupportClaimRequest / SupportClaimResponse`** — same for academic source search
- **`BibliographyRequest / BibliographyResponse`** — same for bibliography generation
- **`SettingsConfig`** — the shape of persisted user settings

Think of this package as the API contract. If the frontend and backend agree on these types, they will never miscommunicate.

---

## `apps/api/` — The Backend

```
apps/api/
├── src/
│   ├── server.ts              ← Entry point: creates Fastify app, registers all routes
│   ├── config.ts              ← Reads environment variables (port, CORS origin, API keys)
│   │
│   ├── routes/                ← HTTP endpoint handlers
│   │   ├── health.ts          ← GET /health — confirms server is running
│   │   ├── ai.ts              ← POST /v1/ai/actions — AI rewrite/critique/summarise
│   │   ├── proofread.ts       ← POST /v1/proofread — grammar and tone suggestions
│   │   ├── references.ts      ← Citation import, library CRUD, bibliography, source search
│   │   └── settings.ts        ← GET/POST /v1/settings — read and save user preferences
│   │
│   └── services/              ← Business logic (no HTTP concerns here)
│       ├── ai-service.ts          ← Calls the Claude API
│       ├── citation-library.ts    ← Reads/writes the citation file on disk
│       ├── citation-parsers.ts    ← Parses RIS, XML, and ENW citation formats
│       ├── academic-search.ts     ← Searches Crossref, OpenAlex, Semantic Scholar
│       ├── bibliography-generator.ts  ← Formats citations into bibliography HTML/text
│       └── settings-store.ts      ← Reads/writes the settings file on disk
│
└── src/__tests__/             ← Vitest unit tests
    ├── bibliography-generator.test.ts
    └── citation-parsers.test.ts
```

### Routes in detail

| File | Endpoints | What it does |
|------|-----------|-------------|
| `health.ts` | `GET /health` | Returns `{ status: "ok" }` |
| `proofread.ts` | `POST /v1/proofread` | Sends selected text + mode to Claude; returns list of suggestions with original/suggested text |
| `ai.ts` | `POST /v1/ai/actions` | Sends document context + action to Claude; returns generated text |
| `references.ts` | `POST /v1/references/import` | Parses an uploaded citation file and saves it to disk |
| | `GET /v1/references/library` | Returns all saved citations |
| | `POST /v1/references/library/delete` | Removes one citation by ID |
| | `POST /v1/references/support-claim` | Searches academic APIs for papers matching highlighted text |
| | `POST /v1/references/bibliography` | Generates a formatted bibliography from a list of citations |
| `settings.ts` | `GET /v1/settings` | Returns current user settings |
| | `POST /v1/settings` | Saves updated settings |

### Services in detail

**`ai-service.ts`**
The only file that talks to the Claude API. Uses `fetch` directly (no SDK). Two functions:
- `proofreadWithAI()` — sends text + mode, parses Claude's JSON response into a suggestions array
- `runAiActionWithAI()` — sends document context + action, returns generated text
Returns scaffold (placeholder) responses if no API key is configured, so development can continue without one.

**`citation-library.ts`**
Manages the citation file at `~/Documents/Skola/citations/sources.skl`. This is a plain JSON file. The service loads it into memory, adds/removes entries, and writes it back. Each citation gets a numeric ID (`decimalId`).

**`citation-parsers.ts`**
Three parsers for common academic export formats:
- `parseRis()` — handles `.ris` files (the most common export from databases like PubMed)
- `parseEndnoteXml()` — handles `.xml` exported from EndNote
- `parseEnw()` — handles `.enw` (EndNote text format)
A single `parseCitationFile()` dispatcher detects the format and calls the right parser.

**`bibliography-generator.ts`**
Takes a list of `CitationLibrarySource` objects and a `CitationStyle` and produces both HTML and plain text output. Implements all six styles with correct author name formatting per style. The HTML wraps each entry in a `<p class="bibliography-entry">` tag with italicised journal names.

**`academic-search.ts`**
Queries three free academic APIs in parallel, deduplicates results by DOI, then re-sorts them by `SearchIntent`:
- `recent` → newest papers first
- `foundational` → oldest papers first
- `support` / `conflicting` → relevance score from the API

**`settings-store.ts`**
Reads and writes `~/Documents/Skola/settings.json`. Merges stored values with safe defaults (APA7, empty API keys) so the app never crashes on a missing field.

### Data persisted to disk

```
~/Documents/Skola/
├── citations/
│   └── sources.skl    ← JSON array of all imported citations
└── settings.json      ← User preferences (citation style, API keys, email for search APIs)
```

---

## `apps/word-addin/` — The Frontend

```
apps/word-addin/
├── src/
│   ├── main.ts                  ← The entire UI: state, rendering, event handling
│   ├── taskpane.ts              ← Entry point: loads polyfills then main.ts
│   ├── commands.ts              ← Ribbon button handler (opens the task pane)
│   ├── polyfills.ts             ← ES5 compatibility shims (fetch, matches, closest)
│   ├── styles.css               ← All visual styling
│   ├── office-globals.d.ts      ← TypeScript type stubs for the Word/Office.js global
│   │
│   └── lib/
│       ├── api.ts               ← HTTP client: wraps fetch calls to the API server
│       ├── office.ts            ← Word document operations via Office.js
│       ├── referencing-engine.ts ← Client-side citation and bibliography formatting
│       └── navigation.ts        ← View state (which panel is currently visible)
│
├── manifest.xml       ← The Office add-in config file (registered with Word)
├── taskpane.html      ← HTML shell that loads the task pane bundle
├── commands.html      ← HTML shell for ribbon command handlers
├── index.html         ← Fallback entry point
├── webpack.config.cjs ← Webpack build config (dev server + ES5 transpilation)
└── public/assets/     ← Icons (16px, 32px, 80px PNG + SVG)
```

### `src/main.ts` — The Application

This is the heart of the frontend. It is a **state machine** with a render loop:

```
State changes → render() called → DOM rewritten → user interacts → state changes → ...
```

**Views** (top-level panels in the task pane):

| View | What the user sees |
|------|--------------------|
| `home` | Dashboard / welcome screen |
| `referencing` | Citation import, library, bibliography, style selector |
| `review` | Proofread, formalize, critique |
| `edit` | Rewrite, add section, insert |
| `support` | Search for supporting sources |
| `settings` | API keys, default citation style |

**Key state fields:**

| Field | Type | What it holds |
|-------|------|---------------|
| `officeReady` | boolean | Whether Word's Office.js API has initialised |
| `selectedText` | string | The text currently highlighted in the Word document |
| `sources` | array | All citations loaded from the library |
| `citationStyle` | CitationStyle | Currently selected style |
| `proofreadResponse` | object | Latest suggestions from the proofread endpoint |
| `aiResponse` | object | Latest output from the AI action endpoint |
| `supportResponse` | object | Latest results from the academic search endpoint |
| `banner` | object | A status message shown at the top of the pane (info/success/warning/error) |

### `lib/api.ts` — Talking to the Backend

A thin HTTP client. Every function corresponds to one API endpoint:

```typescript
proofreadSelection(req)      → POST /v1/proofread
runAiAction(req)             → POST /v1/ai/actions
supportClaim(req)            → POST /v1/references/support-claim
importCitationFile(req)      → POST /v1/references/import
generateBibliography(req)    → POST /v1/references/bibliography
getSettings()                → GET  /v1/settings
saveSettings(req)            → POST /v1/settings
```

### `lib/office.ts` — Talking to Word

Wraps Office.js (Microsoft's API for interacting with the Word document). All functions use `Word.run()` which opens a request context, does work, and then syncs. Key functions:

- `getSelectedText()` — reads what the user has highlighted
- `insertTextAtSelection()` — replaces the selection with new text
- `insertOrUpdateBibliography()` — writes the bibliography into a special content control in the document

### `lib/referencing-engine.ts` — Client-Side Citation Formatting

Formats citations and bibliography entries entirely in the browser — no network call needed. Handles:
- **Author-year styles** (APA7, Harvard, MLA9, Chicago): `(Smith & Jones, 2023)`
- **Numbered styles** (IEEE, Vancouver): `[1]`, `[2]`
- Tracks citation numbers across the document so each source gets a consistent number in numbered styles

### `lib/navigation.ts` — View Routing

Manages which view is active. Persists the current view to `localStorage` so it survives task pane reloads (Word can reload the pane on certain events).

### `manifest.xml` — The Add-in Registration

This XML file tells Word:
- What this add-in is called and its unique ID
- Which URL to load the task pane from (`https://localhost:3000/taskpane.html`)
- What permissions it needs (`ReadWriteDocument` — can read and modify the document)
- What ribbon buttons to show and what they do

### `webpack.config.cjs` — The Build

Webpack compiles the TypeScript source into a JavaScript bundle that:
- Is transpiled to **ES5** via Babel (so it works in older Word webviews on Windows)
- Serves over **HTTPS** on `localhost:3000` with Office-issued dev certificates
- Produces two entry bundles: `taskpane` (the main UI) and `commands` (ribbon handlers)

---

## How the Pieces Connect: End-to-End Flows

### Proofreading a selection

```
User highlights text in Word
  → main.ts reads selection via office.ts → getSelectedText()
  → User clicks "Proofread"
  → main.ts calls api.ts → proofreadSelection()
  → api.ts: POST /v1/proofread
  → routes/proofread.ts receives request
  → services/ai-service.ts: calls Claude API
  → Claude returns JSON array of suggestions
  → Response flows back through routes → api.ts → main.ts
  → main.ts re-renders the pane showing each suggestion
  → User accepts → main.ts calls office.ts → insertTextAtSelection()
  → Word document is updated
```

### Importing a citation file

```
User selects a .ris file in the Referencing panel
  → main.ts reads file content from the file input
  → main.ts calls api.ts → importCitationFile()
  → api.ts: POST /v1/references/import
  → routes/references.ts receives request
  → services/citation-parsers.ts: parses the RIS text into CitationLibrarySource objects
  → services/citation-library.ts: assigns IDs and writes to sources.skl
  → Response returns the new citations
  → main.ts updates the sources list and re-renders
```

### Generating a bibliography

```
User clicks "Refresh Bibliography"
  → main.ts calls api.ts → generateBibliography() with current sources + style
  → api.ts: POST /v1/references/bibliography
  → routes/references.ts receives request
  → services/bibliography-generator.ts: formats all citations per style
  → Returns { html, plain }
  → main.ts calls office.ts → insertOrUpdateBibliography()
  → Word document bibliography section is updated
```

### Searching for supporting sources

```
User highlights a claim in their document
  → main.ts reads selection → getSelectedText()
  → User selects intent (e.g. "Support") and clicks search
  → main.ts calls api.ts → supportClaim()
  → api.ts: POST /v1/references/support-claim
  → routes/references.ts receives request
  → services/academic-search.ts: queries Crossref + OpenAlex + Semantic Scholar in parallel
  → Deduplicates by DOI, sorts by intent
  → Returns list of academic papers
  → main.ts renders results with title, authors, year, venue, DOI
  → User clicks "Add to library" → triggers citation import flow
```

---

## Design Decisions Worth Knowing

**Why Webpack instead of Vite?**
Vite produces ES modules. The webview embedded in some older versions of Microsoft Word on Windows does not support ES modules. Webpack with Babel produces ES5 JavaScript which works everywhere.

**Why no React/Vue/Svelte?**
The task pane runs in a constrained browser environment. A hand-rolled state machine (`main.ts`) keeps the bundle small, has no framework overhead, and is easier to debug when Word's webview misbehaves.

**Why `fetch` instead of the Anthropic SDK?**
Fewer dependencies. The SDK adds weight and complexity for what is ultimately one API call pattern.

**Why local file storage instead of a database?**
Simplifies local development dramatically — no database to install or configure. The `~/Documents/Skola/` directory acts as the user's library and can be backed up or synced with any file sync tool.

**Why `@skola/shared`?**
If the frontend and backend share the same TypeScript types, the TypeScript compiler will catch mismatches at build time rather than at runtime. Changing a field name in `shared` immediately breaks both sides, making it impossible to silently introduce API drift.

**Why pane-first navigation?**
The custom ribbon (the Skola tab in Word's toolbar) requires newer Word APIs that are not always available. The task pane is the reliable, always-available entry point. The ribbon is additive, not required.

---

## Running the Project

```bash
# Install all dependencies (run once)
npm install

# Start the API server (Terminal 1)
npm run dev:api

# Start the Word add-in dev server (Terminal 2)
npm run dev:word

# Sideload the add-in into Word (Terminal 3, run once per machine)
npm run sideload:word

# Type-check everything
npm run typecheck

# Run tests
npm run test -w @skola/api
```

---

## What Is Done vs. What Is Not

**Working end-to-end:**
- Citation import (RIS / XML / ENW)
- Bibliography generation (all 6 styles)
- Proofreading and AI writing actions (with Claude)
- Academic source search
- Settings persistence
- Word selection read and text insertion

**Partially built:**
- Figures, tables, abbreviations UI panels (panels exist, Word binding not complete)
- In-document citation anchors (ContentControl framework started, not finished)

**Not yet started:**
- Track changes integration
- External reference manager sync (Zotero, Mendeley, EndNote)
- Institution-level authentication
- Real-time citation deduplication UI
