# Handoff for the n8n teammate

The engine takes a course configuration, topic-level assessment scores and the previous complete plan. It returns remedial study tasks and the changes between plans. You are responsible for saving plans, mapping stable task IDs to calendar events, sending notifications and handling repeated runs.

## Files to receive

- `engine/dist/n8n-code-node.js`: the complete single-file code to paste into a Code node.
- `engine/README.md` and `engine/HANDOFF.md`: the input/output contract, rules and integration notes. These source documents are in Chinese; this file provides the English handoff.
- `engine/examples/course.json`: the manually configured Thermodynamics demo course.
- `engine/examples/alex-assessment-1.request.json`, `engine/examples/sarah-assessment-1.request.json` and `engine/examples/alex-assessment-2.request.json`: three complete requests ready to use.
- The matching `.output.json` files for those three examples: expected outputs generated by running the code locally, for checking your integration.
- `engine/examples/resources/`: four clearly labelled local demo resources. Publish them somewhere the team can access, or map each `resource_id` to your existing material and update the incoming `resource_ref`.

Use the complete repository if you need to rebuild or change the source. If transferring individual files, include the entire `engine/` directory, `src/priority.js`, `data/sample-grades.json` and `api/` (the engine test directory also includes HTTP endpoint tests). The full website test suite additionally needs `tests/`, `web/`, `package.json` and `package-lock.json`; run `npm ci` first.

## First integration

1. In the Code node, select **JavaScript → Run Once for All Items** and paste the entire contents of `engine/dist/n8n-code-node.js`. See the [official n8n Code documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/) for this mode.
2. Pass **exactly one item** from the upstream node. Its `json` must contain the contents of a `.request.json` file, with `input`, `course` and `previous_plan` at the top level. Explicitly send `previous_plan: null` for the first assessment. Zero items, multiple items, an omitted previous-plan field or invalid inner data cause a `VALIDATION_ERROR`.
3. The output is `[{ json: plan }]`. Save the complete `json` object. On the next assessment, retrieve it using `student_id` and `course_id`, then supply it as `previous_plan`. See the [official n8n data-structure documentation](https://docs.n8n.io/build/work-with-data/understand-n8ns-data-structure/).
4. Check the output with Alex's first-assessment request, then check the changes with Alex's second-assessment request. The second example already embeds the first plan generated by the code; you do not need to assemble it by hand.

Run the local demo and core engine tests from the repository root with Node.js 22. These commands require no package installation or model API key:

```sh
node engine/scripts/demo.js
node --test engine/tests/*.test.js
```

The full website test suite also includes browser DOM tests using the jsdom development dependency. Install development dependencies before running the full suite:

```sh
npm ci
npm test
```

The engine and deployed runtime have no third-party dependencies.

After changing the core, regenerate the single-file adapter and check that it matches the source:

```sh
node engine/scripts/build-n8n.js
node engine/scripts/build-n8n.js --check
```

## How downstream nodes should read the result

- `priorities` is the array of tasks actually allocated. Each `duration_minutes` is a multiple of 30 minutes. `available_minutes` is the budget for the entire round. `exam_date` is metadata only; you choose the actual dates and time slots.
- `task_id` follows `studygps:remedial:{student_id}:{course_id}:{topic_id}`. Each segment is URI-encoded before the segments are joined with colons. A different ranking or assessment does not change the ID of the same remedial task. Save the `task_id → calendar_event_id` mapping on your side; this module does not generate event IDs.
- The first plan has `plan_changed: true` and `changes.type: "initial_plan"`, even when its task list is empty. On later runs, first save the new complete result, then inspect `changes` for task additions/removals, order, duration, resources and activities. If only the assessment ID, explanation wording or scores change while executable tasks stay the same, `plan_changed` is false. `score_changes` may still contain entries.
- Read `status` together with `warnings`. Missing scores are never replaced with zero, and make `overall_score` null. `target_met` only means the valid scores that were provided meet the reference target. Do not create calendar events just to fill an empty task list.
- A repository-relative `resource_ref` does not let cloud-hosted n8n access files on your computer. The upstream node must supply the course. You also handle resource publishing or ID mapping.

Demo checkpoints: Alex and Sarah both have a weighted first-assessment result of 63.5, but their first tasks are Rankine Cycle and First Law respectively. Alex's second plan starts with Second Law, with task durations of 60, 90 and 30 minutes in order. Weights and durations are demo assumptions. The output does not predict score gains or guarantee a final result.

**Not yet verified in a real n8n environment.** Local adapter tests cover the input wrapper, error behaviour and consistency with the core. Your environment still needs to verify the actual n8n version, workflow, persistence, deduplication across runs and Google Calendar/Gmail calls. See [README.md](README.md) for the complete field definitions and status precedence.

## Calling the Vercel HTTP endpoint

The repository also provides `POST /api/study-plan`. An n8n HTTP Request node can call this endpoint on the deployed service. Set `Content-Type: application/json` and use the same `.request.json` contents as the JSON body: `input`, `course` and `previous_plan`.

A successful HTTP response is the complete `plan` object directly. The Code node returns `[{ json: plan }]`. These wrappers differ, but the plan inside is the same. The endpoint needs no model API key and does not write to a database. Upstream must supply the course and previous plan on each run. This is a public prototype calculation endpoint with no user login.

| HTTP status | Meaning |
| --- | --- |
| 200 | Success; the response is the complete plan. |
| 400 | Invalid JSON or failed data validation. Inspect `error.code`, `error.message` and `error.issues` when available. |
| 405 | Wrong method; use POST. |
| 413 | The request body exceeds 256 KiB. |
| 415 | Content-Type is not application/json. |
| 500 | An unexpected service error occurred. The response contains a generic error without exposing a stack trace. |

`GET /api/health` provides service health information. Calculation responses use `Cache-Control: no-store`. This module does not log request bodies or save assessment data. The four resources included in the hosted demo have accessible paths. If supplying a course from another source, use resource references that your team can access.

The actual Vercel deployment URL and verification record are maintained in `engine/DEPLOYMENT.md` in the repository. Passing HTTP endpoint checks and verifying a real n8n workflow integration are separate scopes.
