# Project plan — Click Foundation - LTI Integration Tool

Evidence date: 2026-10-19.

Source repository: `git@bitbucket.org:overdrive/click-foundation-lti-integration-tool.git`.

This plan describes what that repository contains. It does not decide what the product should become.

## Product

The Bitbucket repository is named for a Click Foundation LTI integration tool. The code and its own documentation identify the application as the **TAO LTI 1.3 DevKit**, a Symfony application published by Open Assessment Technologies SA (OAT). The README describes it as an IMS-oriented development kit that can act as an LTI 1.3 platform, an LTI 1.3 tool, or both.

The only Click-specific string in application configuration is the platform display name **Click Learner Portal Platform** in `config/packages/lti1p3.yaml`. No learner-portal product, Click Foundation organisation model, course catalogue, or learner record lives in this repository.

Provenance of the DevKit identity: **Documented** (`README.md`, `composer.json` description "OAT LTI 1.3 DevKit", copyright headers "Open Assessment Technologies SA").

Provenance of the Click name: **Implemented** as that one platform name. Whether this snapshot is the integration used by Click Foundation's learner portal is **Unknown / Requires Confirmation**.

Silicon Ark already documents a different repository, `click-learner-portal-platform`, which also names an LTI platform **Click Learner Portal Platform**. That other tree launches TAO Ignite with client id `click-learning` and audience `https://clms.clicklearning.org/platform` (see `silicon_ark/click-learner-portal-platform/prd.md`, evidence date 2026-10-18). This repository's registration is `local`, client id `common_client_id_value`, audience `http://127.0.0.1:8000/platform`. Nothing in this Git history names `clms.clicklearning.org` or the other repository. They share a display name. They are not the same checkout. Whether one calls the other is **Unknown / Requires Confirmation**.

## Branch reality

`master` is the only branch on the remote. Its only commit is `fbf20a6` (2022-05-30 17:52:41 +0200), subject "Initial commit".

This documentation set is based on `master` at `fbf20a6`. There is no Overdrive commit history that shows how the upstream DevKit was changed. Differences from a typical upstream checkout have to be read from the files themselves.

The task-creation inventory listed `sonar-project.properties` and `sonarqube_scan.bat` at the repository root. Neither file is in `master`. Provenance: **Unknown** — they may have been untracked files on the scan host.

## Scope in the repository

In scope of what is implemented on `master`:

- A Symfony 5.3 web application that demonstrates and exercises LTI 1.3 messages and services.
- Platform-side launch builders for resource link, deep linking, start proctoring, and submission review.
- Tool-side launch handling, deep-linking response, proctoring response, and a generic LTI service client.
- Platform services for Assignment and Grade Services (AGS), Names and Role Provisioning Services (NRPS), Assessment Control Service (ACS / proctoring), and Basic Outcome.
- An HTML operator interface for those flows, plus a dashboard.
- An HTTP API and one console command that generate the same launch messages.
- Docker Compose for local running (Traefik, nginx, PHP-FPM, Redis, Redis Commander) and a Kubernetes-oriented PHP image under `docker/kube`.
- In-repository docs: `README.md`, `CHANGELOG.md`, `doc/installation.md`, `doc/api.md`, `doc/cli.md`, and `doc/openapi/devkit.yaml`.

Out of scope of this repository, because it is not present:

- A Click Foundation learner portal, user directory, or course system.
- A production hostname, AWS stack, or deployed environment definition beyond local Docker and a kube Dockerfile.
- A roadmap, issue tracker, or planned-feature list.
- A relational database, message queue, or background worker.

## System shape

The process is one PHP application. Nginx (or another front controller) sends requests to `public/index.php`. Symfony routes split the work into four areas:

1. **Operator UI** — dashboard, launch forms, and CRUD screens. The `main` firewall allows anonymous access.
2. **HTTP API** — `/api/...`, intended to require a bearer API key.
3. **LTI message endpoints** — OIDC and launch/return URLs protected by the LTI 1.3 bundle firewalls.
4. **LTI service endpoints** — AGS, NRPS, ACS, and Basic Outcome, protected by LTI service scopes.

Durable product data is not in a database. Line items, scores, results, memberships, basic outcomes, and proctoring assessments are stored in the Symfony Redis cache. A default NRPS membership is built in memory from `config/devkit/users.yaml` and is not written to that cache.

Keys for signing LTI messages are files under `config/keys/`. Platforms, tools, and the one registration are declared in `config/packages/lti1p3.yaml`.

## Major components

| Component | Role | Evidence |
|---|---|---|
| Operator UI | Dashboard, launch forms, AGS / NRPS / ACS / Basic Outcome screens | `config/routes.yaml`, `templates/`, `src/Action/Platform`, `src/Action/Tool`, `src/Action/DashboardAction.php` |
| Message builder | Builds the four platform-originating launch messages | `src/Service/Platform/Message/LtiMessageBuilder.php` |
| HTTP API | Same launch generation, plus NRPS and ACS CRUD | `config/routes.yaml` paths under `/api/` |
| CLI | `devkit:create:message:launch` | `src/Command/Platform/Message/CreateMessageLaunchCommand.php`, `doc/cli.md` |
| LTI bundle and libraries | OIDC, JWKS, message and service protocol handling | `oat-sa/bundle-lti1p3` and `oat-sa/lib-lti1p3-*` in `composer.json` |
| Redis cache | Persistence for demo records | `config/packages/cache.yaml`, repository classes under `src/Ags`, `src/Nrps`, `src/Proctoring`, `src/BasicOutcome` |
| Docker stack | Local reverse proxy, web, PHP, Redis | `docker-compose.yml`, `doc/installation.md` |

## Milestones

There is no project plan, milestone list, or ticket history in the repository. `CHANGELOG.md` is the upstream DevKit release log from 1.0.0 through 2.4.3. That log is historical behaviour already present in this snapshot. It is not an Overdrive delivery plan.

The displayed application version (`application_version` in `config/services.yaml`, and `info.version` in `doc/openapi/devkit.yaml`) is **2.4.2**. The changelog's newest section is **2.4.3** and records a lockfile bump of `lti1p3-core` to 6.7.1, which matches `composer.lock`. Provenance: **Implemented**. Which number operators should treat as the product version is **Requires Confirmation**.

## Dependencies

Runtime, from `composer.json` and `composer.lock`:

- PHP `>=7.2` (Docker images are `php:8-fpm` and `php:8-fpm-alpine`).
- Symfony 5.3 (`symfony/framework-bundle` v5.3.8 in the lockfile).
- OAT LTI 1.3 bundle 6.1.0 and libraries: core 6.7.1, AGS 1.3.0, basic outcome 4.1.1, deep linking 4.0.0, NRPS 7.0.0, proctoring 0.4.0, submission review 0.1.0, health check bundle 2.1.0.
- Predis 1.1.x and Redis.
- Twig, Symfony Form, Validator, Monolog.

External specifications named in the README: IMS Security, LTI 1.3 Core, AGS, Basic Outcome, Deep Linking, NRPS, Proctoring, and Submission Review.

The README links a public TAO demo at `https://lti-public-devkit.dev.gcp-eu.taocloud.org` and IMS certification pages for "TAO LTI 1.3 DevKit". Those are upstream references. They are not evidence of a Click Foundation deployment or certification.

## Current status

The repository is a frozen import. One commit, one branch, no later Overdrive changes visible in Git.

Local development is documented as `docker-compose up` and Composer install, then browse `http://devkit-lti1p3.localhost`. The checked-in LTI registration does not use that host. It points the platform at `http://127.0.0.1:8000` and the tool at `http://127.0.0.1:8001`. See the PRD and technical documentation for that conflict.

`vendor/` is part of the Git tree (the clone contains it and `master` is clean). `.env` and `config/keys/private.key` are also in the tree. Secret values are not copied into this knowledge base.

## Known gaps

- Relationship between this repository, the Click learner portal, and the separate `click-learner-portal-platform` codebase that uses the same platform display name.
- Which host, registration, and key set are used when the tool is launched for real.
- Whether the tracked `.env` secrets and private key are still in use and should be rotated.
- Whether a missing `Authorization` header is rejected on `/api/` (see business rules).
- Where, if anywhere, the Kubernetes image is deployed.
- Why the task-creation scan listed Sonar files that are not on `master`.
