# Project plan — theear (The Ear)

Evidence date: 2026-10-01.

Source repository: `git@bitbucket.org:overdrive/theear.git`.

Inspected revision: `master` at `f1a82c841` (2023-08-10, "bitbucket-pipelines.yml edited online with Bitbucket - Master", author Rachel Mogano). The scan-host path named in the onboarding task (`~/projects/sonar_scan/repos/theear`) was not present on this machine. Evidence comes from a read-only clone of `origin/master`.

The clone used for this pass is shallow. Ninety-four commits are visible, from `c51c17f` (2023-03-03, "Cronjob diagnostics", liam-ovd) through `f1a82c841`. The repository root and the full author history are **Unknown**. `git branch -r` in this clone lists only `origin/master`. Whether other remote branches exist beyond this fetch is **Unknown / Requires Confirmation**.

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

## Product

**The Ear** is a browser learning product for musicians. Learners sign up, pick an instrument, take a free trial or pay, and practise inside courses that include hearing exercises (hear/sing, hear/play, hear/write, read/sing), playgrounds, facets, quizzes, and video. Staff run the catalogue, enrolments, institutions, coupons, affiliates, and finance jobs from an admin area. The signed-in learner home is called Earspace.

Provenance: **Implemented**, recovered from controllers, SQL seeds, and email copy. A written product brief was not found in Markdown. PDF manuals sit in `documentation/` (Administrator, Developer, Installation-and-update, Quick-Start, User). Their text was not extracted in this pass, so how far they describe The Ear rather than the upstream Academy LMS is **Unknown**.

Email subjects in `db_updates/update.1.rachel.sql` use the name "The Ear" and "The Ear Team". Login of a non-admin user redirects to `home/profile/earspace#student-area` (`Login.php`).

The application is a CodeIgniter 3.1.9 fork of Academy LMS (`composer.json` name `codeigniter/framework`, JWT key string `academy-lms-api-token-handler` in `application/libraries/TokenHandler.php`). The Ear-specific additions are hearing content, instruments and levels, PayFast subscriptions, institutions, affiliates, Xero manual journals, and the Earspace pages.

## Scope in this repository

In scope of the code that is present:

- Public marketing pages (home, educators, individuals, instruments, pricing, about, jobs, social impact, campaigns).
- Learner account: registration, email verification, password set/reset, profile, wishlist, cart, messages, notes, course progress, quizzes.
- Enrolment and payment: free trial, PayFast subscription and outright terms, coupons including a 100% coupon path, refund and downgrade actions.
- Course delivery: sections, lessons, hearing items, playgrounds, facets, sandbox, certificates route.
- Instructor course building under `User.php` and `Api_instructor.php`.
- Admin operations under `Admin.php`.
- Scheduled jobs implemented as HTTP views: `admin/run_cron_daily/{job}` and `admin/run_cron_hourly`.
- Mobile-oriented JSON under `Api.php`, plus web views named for mobile payment and quiz.
- Deployment to nginx on AWS CodeDeploy.

Out of scope of this repository, or not established:

- The live DNS name. `base_url` is built from the request host (`application/config/config.php`). No hostname is hardcoded there.
- The scheduler that calls the cron URLs (no crontab file is in the repo).
- The definitions of `aws_get_parameter` and `aws_get_secret`. They are called and are not defined in this tree.
- Native mobile app source. Only the HTTP API and a few mobile web views are here.

## System shape

One PHP application. `index.php` boots CodeIgniter. Apache rewrite in `.htaccess` sends non-file requests to `index.php`.

| Area | Where it lives |
|---|---|
| Public site and checkout | `application/controllers/Home.php` |
| Sign-in, MFA, registration | `application/controllers/Login.php` |
| Admin | `application/controllers/Admin.php` |
| Instructor UI | `application/controllers/User.php` |
| Learner JSON API | `application/controllers/Api.php` |
| Instructor JSON API | `application/controllers/Api_instructor.php` |
| Daily job selection | `application/views/backend/admin/cron_daily.php` |
| Hourly job runner | `application/views/backend/admin/cron_hourly.php` |
| Xero journals | `application/views/backend/admin/authorizedResource.php` |
| Schema deltas | `db_updates/*.sql` |
| Deploy | `bitbucket-pipelines.yml`, `appspec.yml` |

MySQL via `mysqli`. Credentials are loaded at runtime through `aws_get_parameter` / `aws_get_secret` (`application/config/database.php`). Commented-out host values in that file name `medmin.co.za` / database `medminco_ear` and a local database `ear`. Those lines are commented. Whether any of them were ever production is **Unknown**. The password in the comment is not repeated here.

## Major components

1. **Catalogue** — categories, courses, sections, lessons, quizzes, bundles (addon controllers).
2. **Hearing practice** — `hearing_content` rows on a lesson, modes `hear_sing`, `hear_play`, `hear_write`, `read_sing`, with notation, reference tone, and MIDI audio (`db_updates/update.6.liam.sql`).
3. **Earspace** — learner profile area after login, plus explainer and how-to pages.
4. **Commerce** — PayFast as the path the checkout and daily jobs actually call. Stripe and PayPal methods remain on `Home.php` and on the bundle addon. Razorpay remains on `Payment_model.php` and `Home_old.php`.
5. **Institutions** — organisation records and users with `role_id` 4.
6. **Finance ops** — invoices (mPDF), credit notes, affiliate payouts, Xero manual journals, revenue reports.
7. **Lifecycle mail** — rows queued in `syscronjob` and sent by the hourly view.

## Milestones visible in the repo

There is no project-plan file and no release tags in the inspected history. The sequence below is inferred from SQL file names and the shallow commit window. It is not an approved roadmap.

| When | What the repo shows | Provenance |
|---|---|---|
| Academy baseline | Installer, updater, course/lesson/quiz/cart, PayPal and Stripe | Implemented (upstream LMS still present) |
| SQL pack `update.1.rachel.sql` | Instruments, levels, payment terms, coupon types, "The Ear" email templates (timestamps in the seed are 2021-10-12) | Documented in SQL |
| `update.6.liam.sql` | `hearing_content` and lesson `tracking` | Documented in SQL |
| Later SQL (`update.28`–`update.38`) | Affiliates, institutions, institution role | Documented in SQL |
| 2023-03 to 2023-08 (visible commits) | Cron diagnostics, homepage and playground layout, instrument links, email-report datatable, CodeDeploy pipeline key edits | Git history |

Current status: **maintenance-quiet on `master`**. The tip commit is 2023-08-10 and only changes `bitbucket-pipelines.yml`. No open milestone after that date is written in the repository.

## Implementation plan (as the code stands)

There is no forward plan in the repo. The operating model that is implemented:

1. Schema changes are hand-written SQL files in `db_updates/`. There is no CodeIgniter migration runner wired as the source of those files (`application/config/migration.php` exists as framework config; the applied order of `db_updates` is **Unknown**).
2. `master` pipeline zips the tree and deploys with AWS CodeDeploy using staging variable names (`CODEDEPLOY_ID_STAGING`, `$APPLICATION_NAME`, `$S3_BUCKET`, `$DEPLOYMENT_GROUP`).
3. Branch `production` in `bitbucket-pipelines.yml` uses `AWS_ACCESS_KEY_ID_PROD`, `$APPLICATION_NAME_PROD`, and `$S3_BUCKET_PRODUCTION`. That branch was not in the shallow remote listing. Whether it still exists on Bitbucket is **Unknown / Requires Confirmation**.
4. `appspec.yml` copies the archive onto `/usr/share/nginx/html` owned by `nginx`.

## Dependencies

PHP constraint in Composer: `>=5.3.7`. CodeIgniter 3.1.9. Runtime packages: `calcinai/xero-php` ^2.2, `xeroapi/xero-php-oauth2` ^2.9, `payfast/payfast-php-sdk` ^1.1, `phpmailer/phpmailer` ^6.5, `aws/aws-sdk-php` ^3.204, `mpdf/mpdf` ^8.0, `pragmarx/google2fa` ^8.0, `bacon/bacon-qr-code` ^2.0, `chillerlan/php-qrcode` ^3.4. Dev: PHPUnit 4 or 5, vfsStream. No `tests/` directory is present, so those dev packages are unused in this tree.

External systems: MySQL, AWS Parameter Store and Secrets Manager (called, client code not in repo), S3 (presigned URLs and a hardcoded transcode bucket `the-ear-prod-transcode`), CloudFront invalidation from admin, PayFast, Xero, SMTP (parameters `smtp_host`, `smtp_user`, `smtp_port`, secret `ses_smtp_password`), optional Google reCAPTCHA, Google Authenticator-compatible TOTP for admins.

## Known gaps

- Public production URL.
- Who schedules `run_cron_daily` and `run_cron_hourly`, and whether those URLs are still reachable without a session (the admin checks in those methods are commented out).
- Where `aws_get_parameter` and `aws_get_secret` are defined.
- Exact `role.name` for role ids 1 and 2 (see business rules).
- Whether the PDF manuals match the customised product.
- Whether `bitbucket-pipelines-ftp.yml` was ever the active pipeline. Bitbucket runs `bitbucket-pipelines.yml`, not that filename, unless a project setting says otherwise. That setting is **Unknown**.
