# Project plan — click-learner-portal-platform

Evidence date: 2026-10-18.

Source repository: `git@bitbucket.org:overdrive/click-learner-portal-platform.git`.

Inspected revision: `master` at `99bde51` (2022-10-20 11:24:09 +0200, author silmaanie `<maanie@overdrive.co.za>`, message "updates"). `origin/HEAD` points at `master`.

A second remote branch, `origin/Production`, is `master` plus nine later commits. Its tip is `131cc59` (2023-01-11, author bitbucket-pipelines, message "added home page route"). The merge base of the two branches is `99bde51`, so `Production` is strictly ahead of `master`. There are no tags.

The scan-host path named in the onboarding task (`~/projects/sonar_scan/repos/click-learner-portal-platform`) was not on this machine. Evidence comes from a read-only clone. `vendor/` is tracked (6930 files) but was not checked out here, because Windows path length rejected files under `vendor/friendsofphp/proxy-manager-lts/`. Application code, config, scripts, and history were read. Private-key and secret *values* are not copied into this set.

`silicon_ark/click-learner-portal-platform/` did not exist before this set. The source repository has no README and no product brief.

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

## Product

LTI platform config names the platform **Click Learner Portal Platform** (`config/packages/lti1p3.yaml`, both `localPlatform` and `ClickLearningPlatform`). The CodeDeploy destination directory is `/var/www/html/clms.clicklearning.org/`. The `Production` branch adds a `/` response whose only body text is `clms.clicklearning.org`.

What the application code does is act as an LTI 1.3 platform: a browser request carrying a learner id, a quiz id, and a quiz end date builds an LTI resource-link launch against TAO Ignite and returns an HTML form that posts the browser to that tool. A second, API Platform route still targets a localhost tool and is marked in a comment as testing.

Provenance: **Implemented** (config names, deploy path, controllers). A written statement of organisational purpose is **Unknown / Requires Confirmation**.

`silicon_ark/ClickPortal/` documents a different repository (`clickportal.git`) that also uses the `clicklearning.org` domain. Nothing in this repository names ClickPortal, and nothing read in ClickPortal names this repository, TAO, or `clms`. Whether they are parts of one product **Requires Confirmation**.

## Branch reality

| Line | Tip | Date | What it is |
|---|---|---|---|
| `master` (`origin/HEAD`) | `99bde51` | 2022-10-20 | 51 commits. Launch return URL is `portaltest.clicklearning.org`. No `/` route. Pipeline deploys this branch with `QA_*` variables. |
| `Production` | `131cc59` | 2023-01-11 | Same history plus 9 commits. Return URL is `learn.clicklearning.org`. `/` returns a one-line HTML title. Pipeline deploys this branch with `PROD_*` variables. |

No other remote branches were present.

**Discrepancy:** the task-creation scan listed `sonar-project.properties` and `sonarqube_scan.bat` at the repository root. Neither file is in git at `99bde51` or in the `Production` file list. Provenance: **Unknown** — they may have been untracked files on the scan host.

Which branch is deployed, and whether either host is still in use, is **Unknown / Requires Confirmation**.

## Objectives (inferred from the application, not from a written plan)

No project plan or requirements document exists in the repository. The following are **Inferred** from controllers and LTI config:

- Let a caller open a TAO Ignite quiz for a learner by hitting a URL that includes the learner id, quiz id, and quiz end date.
- Send that launch as an LTI 1.3 resource-link message, with the learner role, deployment id `1`, a return URL on a Click Learning host, and a custom claim that closes the delivery at the end of the given date.
- Advertise this app as the LTI platform at `https://clms.clicklearning.org/platform`.
- Keep a localhost platform/tool registration used by an API Platform action that a comment calls testing.

## Scope

### In this repository

- A Symfony 5.4 application (`composer.json` extra `symfony.require` is `5.4.*`).
- OAT `oat-sa/bundle-lti1p3` `^6.1` and API Platform `^2.6`.
- Two application routes that build LTI launches (`DefaultController`, `LtiRequestController`).
- LTI platform, tool, and registration config, plus committed dev key files.
- Doctrine and a PostgreSQL Compose service from the Symfony recipe. No migration classes and no query against a table.
- Bitbucket Pipelines packaging the tree as a zip and deploying it with AWS CodeDeploy. `appspec.yml` copies the tree onto Apache.

### Not in this repository

- The TAO Ignite tool itself (`testrunner-ignite.prod.gcp-eu.taocloud.org` and `auth-ignite.prod.gcp-eu.taocloud.org` are remote URLs).
- The page at `click-home-learning` on `portaltest.clicklearning.org` or `learn.clicklearning.org`. This app only places that URL in the launch claim.
- A learner directory, quiz catalogue, or check that the learner id and quiz id exist.
- Tests, a README, Sonar project files in git, a PHP application service in Docker Compose, queues, or a monitoring agent.

## System architecture

```text
Caller (browser or anything that can open the URL)
  │
  ├─ GET /default/{learnerId}/{quizId}/{quizEndDate}     master and Production
  │     DefaultController
  │       registration "tao"
  │       HTML auto-post form (toHtmlRedirectForm)
  │         └─ TAO Ignite launch-lti-1p3/{quizId}
  │              return_url claim → click-home-learning on
  │                portaltest.clicklearning.org   (master)
  │                learn.clicklearning.org        (Production)
  │              custom claim deliverySettings.closeOn
  │
  ├─ GET /api/ltiresourcelink/{learnerid}                API Platform
  │     LtiRequestController
  │       registration "local", tool URL 127.0.0.1:8001
  │       comment: TESTING ONLY
  │       JSON-encoded URL string (HTML redirect is commented out)
  │
  └─ GET /                                                Production only
        HTML body "clms.clicklearning.org"

Deployed document root (appspec.yml):
  /var/www/html/clms.clicklearning.org/   owner apache

Configured platform issuer:
  https://clms.clicklearning.org/platform
  OIDC, token, and JWKS URLs on the same host (see technical-documentation.md)
```

Docker Compose defines only a PostgreSQL 13 container. It does not define the PHP app. Provenance: **Implemented** in `docker-compose.yml`.

## Major components

| Component | Path | Role |
|---|---|---|
| TAO launch | `src/Controller/DefaultController.php` | Resource-link launch for a learner and quiz |
| Local launch | `src/Controller/LtiRequestController.php` | API Platform action aimed at a localhost tool |
| API resource | `src/Entity/ltirequest.php` | Declares `GET /api/ltiresourcelink/{learnerid}`. Not a Doctrine entity |
| User stub | `src/Controller/UserAuthenticator.php` | LTI user authenticator. Always succeeds. Display name is a literal |
| Registrations | `src/Controller/RegistrationRepository.php`, `config/packages/lti1p3.yaml` | In-memory platform/tool registrations `local` and `tao` |
| Keys | `config/secrets/dev/` | Committed public and private key files used by every key chain |
| Deploy | `bitbucket-pipelines.yml`, `appspec.yml`, `scripts/` | Zip, CodeDeploy, Apache start |
| Recipe leftovers | `config/packages/doctrine.yaml`, `docker-compose.yml`, `templates/base.html.twig` | Database URL, Postgres service, unused Twig shell |

## Milestones

No milestone list, issue tracker, or roadmap is in the repository.

Observed history on `master` (selected; full log is 51 commits, 2022-06-03 to 2022-10-20):

| When | What | Evidence |
|---|---|---|
| 2022-06-03 | Two "Initial commit" commits, then API Platform, CodeDeploy, Apache pack, and a commit that adds `vendor/` | `9ce6f9d` Abdurahmaan Ismail; `092dbdc`, `de800a2`, `f34d9e8`, `844cbe2`, `da17b65` |
| 2022-06-06 to 2022-06-15 | Pipeline and gitignore edits; launch URL pointed at TAO; learner id, quiz id, and return URL moved from localhost to a domain | messages on `fb6afa7`, `2069c54`, `824b541`, `25c5f4b` |
| 2022-07-04 | Environment flipped to prod and back to dev; debug mode disabled | `535f550`, `4f6cc87`, `b346c18` |
| 2022-08-03 to 2022-08-04 | Custom claims for auto-close, delivery TTL, and quiz end date; redirect back | `dcfe401`, `8abb811`, `bf54aba` |
| 2022-09-25 to 2022-10-20 | TAO tool endpoints, OIDC URL, platform URLs. `master` stops here | `af284f4`, `e97168f`, `de1f3cf`, `99bde51` |

`Production` only, after `99bde51`:

| When | What | Evidence |
|---|---|---|
| 2022-10-21 | Production CodeDeploy step added; branch key renamed from `production` to `Production` | `50ba7e3`, `1fcda4a` |
| 2022-10-26 | Return URL changed to `learn.clicklearning.org` | `91d9530` |
| 2022-12-07 | `.env` `APP_ENV` set to prod, then reverted to dev | `4c10c2e`, `325e804` |
| 2022-12-20 | Composer update; message "prod working and stable" | `79afe70`, `0ffcb19` |
| 2023-01-06 | Message "test deployment" | `6fc83f1` |
| 2023-01-11 | `/` route added | `131cc59` |

The current `DefaultController` on `master` has the close-on claim and does not contain a delivery-TTL claim. The August TTL commits are history, not a second live claim.

## Implementation plan

There is no plan in the repository. Unfinished or unused pieces that are visible in the tree:

- `UserAuthenticator::authenticate` contains the comment `//TODO:` and does not look up a learner. The identity name is the literal `Maanie`.
- `LtiRequestController` takes `$learnerid` and does not use it. The login hint is the literal `loginHint`. The tool URL is `http://127.0.0.1:8001/tool/launch`. A comment on the authenticator construction says `TESTING ONLY, 2nd param needs to be false`. The HTML redirect return is commented out.
- `ltirequest` imports Doctrine ORM annotations and lives under `src/Entity`, but the class has no `@ORM\Entity` mapping. `quiz_id` is never read by the controller.
- `DefaultController` constructs a `PlatformOriginatingLaunchBuilder` and does not use that variable. The launch uses the injected `LtiResourceLinkLaunchRequestBuilder`.
- `templates/base.html.twig` calls Webpack Encore helpers. Encore is not a Composer requirement, and no template extends `base.html.twig`.
- `scripts/install_dependencies` is a commented `yum` line. `scripts/stop_server` is not referenced by `appspec.yml` and assigns a shell variable with spaces around `=`.
- `scripts/test.txt` contains the text `test document`.
- Doctrine migrations path is configured. `migrations/` contains only an empty `.gitignore`.
- `.gitignore` lists `/vendor/`, `/.env.local.php`, and `/var/`. On `master`, `vendor/` is still tracked. On `Production`, `.env.local.php` and `var/cache/dev/` are also tracked.

Whether any of those are intentional is **Unknown / Requires Confirmation**.

## Known dependencies

- PHP `>=8.0.2` on `master`. On `Production`, `>=8.0` and Composer `platform.php` `8.2`. Symfony `5.4.*`.
- `api-platform/core` `^2.6`, `oat-sa/bundle-lti1p3` `^6.1`, Doctrine ORM `^2.12`, Nelmio CORS `^2.2`.
- `Production` also requires `laminas/laminas-code` `^4.8`.
- PostgreSQL 13 image in Compose, matching the `serverVersion=13` in `DATABASE_URL`. No application code opens a connection.
- TAO Ignite hosts named in `lti1p3.yaml` and `DefaultController`.
- AWS CodeDeploy and an Apache (`httpd`) host. Pipeline credentials are Bitbucket variables (`QA_*` on `master`, plus `PROD_*` on `Production`), not values in git.
- Committed dev key pair under `config/secrets/dev/`.

## Current project status

`master` last moved on 2022-10-20. `Production` last moved on 2023-01-11. Neither branch has a commit after that as of this inspection. There is no release tag.

The `Production` pipeline message "prod working and stable" (`0ffcb19`) is a commit message, not a health check stored in the repo.

Whether `clms.clicklearning.org` still serves this tree, which branch it serves, and whether the TAO registration is still accepted are **Unknown / Requires Confirmation**.

## Human confirmation

- Is Click Learner Portal Platform / `clms.clicklearning.org` still the live host, and is the deployed branch `master` or `Production`?
- Is the approved return URL `portaltest.clicklearning.org` or `learn.clicklearning.org`?
- Is launching a quiz for any caller who knows a learner id an approved rule?
- Should the localhost `/api/ltiresourcelink/{learnerid}` action still be deployed?
- Is the hardcoded LTI display name `Maanie` a placeholder that was meant to be replaced with the learner record?
- Are the committed dev private key, `APP_SECRET`, and `LTI1P3_SERVICE_ENCRYPTION_KEY` still in use, and should they be rotated? Values are not copied here.
- Is this repository part of the same product as ClickPortal, or only a neighbour on `clicklearning.org`?
- Were `sonar-project.properties` and `sonarqube_scan.bat` ever part of the product, or only untracked scan-host files?
