# ADAM knowledge graph

ADAM (Assessment Delivery and Management) is a Go/Gin monolith plus four Vue apps that rosters K-12 tenants, sets up tests and administrations, delivers them (AD player, TestNav, legacy Learnosity), scores them (in-process save-off, PASS/OSCAR, hand scoring) and reports on them (Postgres + SingleStore). This directory is a graph of Markdown nodes in `nodes/`. `INDEX.md` lists every node, `permissions.md` lists every permission key, and `graph.html` is the viewer.

Built from `git ls-files` of the `adam` repo on branch `development`. `kg.config.json` records the stamped commit.

## Start here

1. [api-server](nodes/api-server.md): `main.go` wiring, the middleware chain, secure vs insecure API groups, `handleError` and `RequirePermission`.
2. [client](nodes/client.md), [org](nodes/org.md), [user](nodes/user.md), [role](nodes/role.md): the tenant model. `role` lists every permission column.
3. [test](nodes/test.md), [admin](nodes/admin.md), [session](nodes/session.md): a test, its *administration* ("admin" is never a person here), and one student's session. `session` holds the state lifecycle.
4. [take-test](nodes/take-test.md) and [submit-and-score-session](nodes/submit-and-score-session.md): the core student journey.
5. [external-queue-consumer](nodes/external-queue-consumer.md) and [sqs](nodes/sqs.md): almost every async job is an SQS actionType handled by a single consumer.
6. [async-jobs](nodes/async-jobs.md): every gocron job and its schedule.
7. [postgres](nodes/postgres.md) and [singlestore](nodes/singlestore.md): the two databases, migrations, and the reporting sync.
8. [frontend-app](nodes/frontend-app.md): the staff Vue 3 app, its 156 routes and its menu-to-permission table. Also see [tester-ui-app](nodes/tester-ui-app.md), [admin-ui-app](nodes/admin-ui-app.md) and [legacy-client](nodes/legacy-client.md).
9. [feature-flags](nodes/feature-flags.md) and [app-options](nodes/app-options.md): global-settings flags and environment variables.

## Main flows

- **Delivery and scoring:**
  - [take-test](nodes/take-test.md), [proctor-a-session](nodes/proctor-a-session.md), [submit-and-score-session](nodes/submit-and-score-session.md)
  - [deliver-ad-session](nodes/deliver-ad-session.md), [deliver-testnav-test](nodes/deliver-testnav-test.md), [score-externally](nodes/score-externally.md), [hand-score-responses](nodes/hand-score-responses.md)
  - [build-and-assign-class-assignment](nodes/build-and-assign-class-assignment.md); legacy: [run-classroom-test](nodes/run-classroom-test.md)
- **Setup:**
  - [create-administration](nodes/create-administration.md), [generate-sessions](nodes/generate-sessions.md), [bulk-import-administrations](nodes/bulk-import-administrations.md)
  - [sync-ad-content](nodes/sync-ad-content.md), [sync-testnav-forms](nodes/sync-testnav-forms.md), [author-qti-item](nodes/author-qti-item.md)
- **Rostering:** [sync-clever-roster](nodes/sync-clever-roster.md), [sync-launchpad-roster](nodes/sync-launchpad-roster.md), [sync-oneroster-raas](nodes/sync-oneroster-raas.md), [import-roster-csv](nodes/import-roster-csv.md), [launch-via-lti](nodes/launch-via-lti.md)
- **Auth:** [log-in](nodes/log-in.md), [switch-account](nodes/switch-account.md), [save-role-permissions](nodes/save-role-permissions.md)
- **Reporting:** [sync-results-to-singlestore](nodes/sync-results-to-singlestore.md), [view-performance-report](nodes/view-performance-report.md), [generate-bulk-isr-pdfs](nodes/generate-bulk-isr-pdfs.md), [export-results-data](nodes/export-results-data.md)
- **Operations:**
  - [create-tenant](nodes/create-tenant.md), [copy-tenant](nodes/copy-tenant.md), [delete-tenant](nodes/delete-tenant.md)
  - [place-materials-order](nodes/place-materials-order.md), [resolve-rejected-test](nodes/resolve-rejected-test.md), [ask-chat-assistant](nodes/ask-chat-assistant.md), [deploy-adam](nodes/deploy-adam.md)

## Layout

The backend lives in `src/v2`. `apis/` holds one file per API group, each registered in `apis/init.go`'s `BindAll`, and each file is an `*-api` interface node. Those call `services/` (the `*-service` and domain module nodes), which use go-pg/Bun models in `models/`.

Background work runs in two places:
- `async/`: gocron jobs, see [async-jobs](nodes/async-jobs.md).
- `sqs/`: the single SQS consumer, see [external-queue-consumer](nodes/external-queue-consumer.md).

External clients live in `src/ad` (AD), `mot`, `services/{pass,oscar,launchpad,...}` and `mzclever`. The OneRoster server is in `src/one_roster`, and LTI is in `src/lti`. One-off operational scripts are in `src/scripts`, grouped into `scripts-*` nodes under [ops-scripts](nodes/ops-scripts.md). CI never compiles them, and many no longer build.

There are four SPAs, each shipped in its own image of the same Go binary (see [build-deploy](nodes/build-deploy.md)):
- `frontend/`: staff, Vue 3, nodes named `fe-*`.
- `tester-ui/`: students and proctors, nodes named `tester-*`.
- `admin-ui/`: internal staff console, nodes named `admin-*-ui`.
- `client/`: the legacy Vue 2 "Classic" app, still built and served at `/`, nodes named `legacy-*`.

## Conventions for implementers

- **Migrations:** add a pair `db/migrations/<YYYYMMDDHHMMSS>_<name>.up.sql` and `.down.sql`, each wrapped in `BEGIN; … COMMIT;`, with idempotent DDL. They are applied by golang-migrate when `DBUPDATE_FLAG` is set (see [postgres](nodes/postgres.md)). go-pg skips zero values unless the field is tagged `use_zero`.
- **Routes:**
  - Add the handler to an existing `XxxAPI.RegisterAll` in `src/v2/apis/`, or create a new API and append it in `init.go`. Secure routes go in `apis`; unauthenticated callbacks go in `insecureAPIS`.
  - Guard every route with `AuthRequired` plus `RequirePermission(<role guard>)`, and scope every query by the caller's `client_id`. Workers found many routes that trust `client_id` or ids from the request body. The org-scope checkpoint is still log-only.
  - Errors use the `"<status> - message"` convention in `handleError`.
- **Async work:**
  - Add an SQS actionType handled in `src/v2/sqs/external_queues.go`, or a gocron job in `async.Setup()`. Don't spawn goroutines in `main.go`.
  - Handlers that return an error are not deleted, so they are retried every 30 minutes and must be idempotent.
- **Reporting data:** after mutating results, bump `sessions.updated` or call `singlestore.Delete*` so the SingleStore sync picks the change up (see [sync-results-to-singlestore](nodes/sync-results-to-singlestore.md)).
- **Frontend:** use `<script setup>`. Use the ADAM wrapper components rather than raw PrimeVue; this is enforced by ESLint and the component-convention CI gate (see [fe-components](nodes/fe-components.md)). Use Tailwind tokens only. Router permission checks are UI-only, so always enforce on the backend too.
- **Tests:**
  - `make test` runs the Go tests serially and excludes scripts.
  - `make test_unit` runs Vitest for all three Vue 3 apps.
  - `cd e2e-automation && npm test` runs the Playwright/Cucumber suite (see [e2e-automation](nodes/e2e-automation.md)).
  - `make mocks` regenerates mocks and `make templ` regenerates the templ templates.
- **PR gates (blocking):** Go product coverage must stay at or above 95% into development (`GO_COVERAGE_FLOOR`, ADAM-2883); new ESLint errors on changed lines fail the PR (`eslint-changed-lines.yml`); ERROR-tier a11y findings on changed lines fail the PR (`accessibility-violation-check.yml`, ADAM-2896). See [build-deploy](nodes/build-deploy.md).

## Status and caveats

Every node carries a `status:` value. `legacy` means still reachable but superseded (Learnosity, classroom tests, v1 reports, the legacy client). `dead` means no caller, and the node says how that was established.

Many module and interface nodes have a `## Gotchas` section. Security findings from the build (missing tenant checks, unauthenticated callbacks, secrets in logs and URLs) are recorded there. They are worth a read before you touch auth, scoping or external callbacks.

## Product features and glossary

There are 32 `capability` nodes, each describing a product feature in plain language, with the role keys and flags that gate it. Start with [student-test-taking](nodes/student-test-taking.md), [administration-scheduling](nodes/administration-scheduling.md), [performance-reporting](nodes/performance-reporting.md) and [rostering-and-roster-sync](nodes/rostering-and-roster-sync.md). There are also 33 `concept` nodes for terms that mean something specific in ADAM. Read [admin-term](nodes/admin-term.md), [session-term](nodes/session-term.md), [tenant-term](nodes/tenant-term.md), [saveoff](nodes/saveoff.md) and [assignment-term](nodes/assignment-term.md) first. `INDEX.md` lists all of them.
