# Project plan — Click Foundation - LTI Integration Platform

Evidence date: 2026-10-19.

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

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

## Product

The Bitbucket repository is named **Click Foundation - LTI Integration Platform**. There is no README, product brief, or in-repository requirements document. The application is a Symfony 5.4 project whose only application screen builds an LTI 1.3 resource-link launch and returns an HTML auto-post form.

The configured platform display name is **Click Learner Portal Platform** (`config/packages/lti1p3.yaml`). The configured tool display name is **LTI 1.3 DevKit (as tool)**. No learner-portal product, Click Foundation organisation model, course catalogue, or learner record lives in this repository.

Provenance of the repository name: the Git remote and this Silicon Ark directory name. Provenance of the platform and tool display names: **Implemented**.

## Related Silicon Ark sets

Two other documented repositories use overlapping names. They are not this checkout.

| Silicon Ark directory | Git remote | What it is | How it differs |
|---|---|---|---|
| `Click Foundation - LTI Integration Tool` | `click-foundation-lti-integration-tool.git` | TAO LTI 1.3 DevKit (platform and tool UI, AGS, NRPS, ACS, Basic Outcome) | Full DevKit tree, `master` at `fbf20a6`. This platform repo does not contain that tree. |
| `click-learner-portal-platform` | `click-learner-portal-platform.git` | Symfony launcher that names the same platform display string and launches TAO Ignite | Client id `click-learning`, audience `https://clms.clicklearning.org/platform` on the `tao` registration. This platform repo uses client id `common_client_id_value` and audience `http://127.0.0.1:8000/platform`. |

Whether this repository was meant to call either of those systems is **Unknown / Requires Confirmation**. The active tool launch URL in `DefaultController` is `http://127.0.0.1:8001/tool/launch`, which matches the DevKit tool launch path documented for the Integration Tool. The `launch_url` in this repo's `lti1p3.yaml` is `http://127.0.0.1:8001/api/v1/auth/launch-lti-1p3/`, which matches the Ignite-style path used by `click-learner-portal-platform`. The controller sets the resource-link URL itself, so the yaml `launch_url` is not what `/default` sends. A commented block in `DefaultController` also names `https://testrunner-ignite.prod.gcp-eu.taocloud.org/api/v1/auth/launch-lti-1p3/`. That block is not executed.

## Branch reality

`master` is the only branch on the remote.

| Commit | Date | Author recorded by Git | Subject | Contents |
|---|---|---|---|---|
| `16e328c` | 2022-05-30 15:38:29 +0000 | Abdurahmaan Ismail `<maanie@overdrive.co.za>` | Initial commit | `.gitignore` only |
| `6731ace` | 2022-05-30 17:46:00 +0200 | silmaanie `<maanie@overdrive.co.za>` | Initial commit | The Symfony application. `origin/HEAD` |

This documentation set is based on `master` at `6731ace`. There is no later commit.

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.4 web application (PHP `>=8.0.2`) that builds one LTI 1.3 resource-link launch.
- One application route, `/default` (the `@Route` does not restrict the HTTP method).
- LTI bundle routes for JWKS, platform OIDC authentication, tool OIDC initiation, and the platform OAuth2 token endpoint.
- One LTI registration, `local`, with localhost audiences on ports 8000 (platform) and 8001 (tool).
- Dev signing keys committed under `config/secrets/dev/`.

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

- A Click Foundation learner portal, user directory, course system, or gradebook.
- AGS, NRPS, deep linking, proctoring, or Basic Outcome implementations in this tree.
- A production hostname, Docker stack, Kubernetes manifest, or CI pipeline.
- A README, changelog, OpenAPI file, or test suite (`tests/` is declared in Composer autoload and the directory is absent; `packages-dev` in `composer.lock` is empty).
- A relational database, message queue, or background worker.

## System shape

The process is one PHP application. The front controller is `public/index.php`. Symfony loads `config/routes.yaml`, `config/routes/*.yaml`, and the LTI bundle route files imported by `config/routes/lti1p3.yaml`.

Durable product data is not stored. Cache configuration is the Symfony filesystem default. Redis is present only as comments in `config/packages/cache.yaml`.

Signing keys are files under `config/secrets/dev/`. The platform, the tool, and the one registration are declared in `config/packages/lti1p3.yaml`.

## Major components

| Component | Role | Evidence |
|---|---|---|
| Launch action | `/default` builds a resource-link launch, runs OIDC initiation and authentication in process, and returns an HTML redirect form | `src/Controller/DefaultController.php` |
| LTI registration config | Names the platform, the tool, the client id, the deployment id, and the key chains | `config/packages/lti1p3.yaml` |
| Bundle endpoints | JWKS, OIDC authentication, OIDC initiation, OAuth2 token | `config/routes/lti1p3.yaml` importing `oat-sa/bundle-lti1p3` 6.1.1 |
| Local registration class | In-memory `RegistrationRepositoryInterface` implementation. Not the repository the controller type-hints. | `src/Controller/RegistrationRepository.php`, bundle alias in `oat-sa/bundle-lti1p3` 6.1.1 `Resources/config/services.yaml` |
| Local user authenticator | Always succeeds with a null user identity. Constructed with `new` inside the action. | `src/Controller/UserAuthenticator.php` |
| Symfony security | `dev` and `main` firewalls, empty in-memory user provider, no access-control rules | `config/packages/security.yaml` |

## Milestones

There is no project plan, milestone list, ticket history, or changelog in the repository. Both commits are dated 2022-05-30 and both subjects are "Initial commit". Nothing in Git records a later delivery.

## Dependencies

Direct requirements in `composer.json`:

- PHP `>=8.0.2`, `ext-ctype`, `ext-iconv`
- `doctrine/annotations` `^1.13`
- `oat-sa/bundle-lti1p3` `^6.1` (locked 6.1.1, which requires `oat-sa/lib-lti1p3-core` `^6.0`; locked core is 6.7.1)
- Symfony 5.4 components: `console`, `dotenv`, `flex` `^2`, `framework-bundle`, `runtime`, `yaml`
- `extra.symfony.require` is `5.4.*`

`composer.json` license is `proprietary`. The OAT bundle license recorded in `composer.lock` is LGPL-2.1.

`symfony.lock` records several Symfony components at 6.0 (including `http-kernel`, `http-foundation`, `cache`, `dependency-injection`, and `runtime`) while `composer.lock` pins those packages to 5.4.8 or 5.4.9. Composer installs from `composer.lock`. The Flex lock is metadata and disagrees with it. Provenance: **Implemented** in both files. Which file an operator last treated as current is not a product question; install follows `composer.lock`.

No deploy manifest names a host, a database, or an external Click service beyond the localhost URLs in `lti1p3.yaml` and `DefaultController`.

## Current status

The repository is a single-day import from May 2022. `master` has not moved since `6731ace`. The launch action contains `dump()` calls, a comment that the authenticator arguments are "TESTING ONLY", and a large block of code after the `return` that does not run. Whether this tree was ever deployed is **Unknown / Requires Confirmation**.

## Known gaps that block a confident reading

- Intended production tool: DevKit on port 8001, TAO Ignite, or something else.
- Whether the committed dev private key and the secrets in `.env` were ever used outside a workstation. Values are not copied into this document.
- Whether `/default` can boot. See technical-documentation.md for the autowiring and duplicate-route observations. The container was not started during this investigation.
