# Project plan — BuildingTomorrow

Evidence date: 2026-10-19.

Source repository: `git@bitbucket.org:overdrive/buildingtomorrow.git` (`https://bitbucket.org/overdrive/buildingtomorrow.git`).

Inspected revision: `master` at `0c7d5dfbf438458c250e03ba76ca8729e0241179` (2024-10-23 06:19:32 +0000, "Merged in qa (pull request #122)").

The working clone used for this inspection was a depth-1 clone of `master`. Commits before that tip were not retrieved. Whether later commits exist on other branches was not inspected.

There was no `BuildingTomorrow/` directory in Silicon Ark before this set. The source `README.md` is the Admin Overdrive starter text. It does not describe the learner programme.

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

## Product

The browser chrome titles the admin UI **Building Tomorrow** (`app/Views/layouts/main.php`). The repository and Composer package are **BuildingTomorrow** / `codeigniter4/adminstarter`, described as "Admin Overdrive". Salesforce bulk jobs write an external id named `Ewaka_External_Id__c` and set the household parent first name to the literal `Ewaka Household`.

What "Building Tomorrow" and "Ewaka" refer to, and whether they are the same programme, is **Unknown / Requires Confirmation**.

What the code implements is a staff admin site plus phone channels:

- Households enrol learners over USSD. Session text is stored in `africas_talking_log`.
- A learner who has finished enrolment can start an initial assessment, number recognition, lessons, and later assessments. Those flows place an Africa's Talking voice call that plays question audio and collects keypad digits.
- Staff maintain languages, levels, lessons, questions, audio, and a visual flow builder.
- A cron entry pushes households, students, levels, lessons, and progress into Salesforce custom objects.
- Reports cover engagement, answers, dropped calls, redialled calls, and call performance.

Provenance: **Implemented** in controllers, models, views, helpers, and migrations. The product name in the layout is **Implemented**. The starter feature list in `README.md` is **Documented** and only covers authentication, authorisation, registration, and menu management.

External links in `README.md`, not verified from this repository:

- Jira board: `https://siliconsoftware.atlassian.net/jira/software/projects/SI/boards/12`
- Confluence space: `https://siliconsoftware.atlassian.net/wiki/spaces/AO/overview`

## Branch reality

`master` is the branch that was checked out. `bitbucket-pipelines.yml` deploys the `master` branch to production and the `qa` branch to QA. The tip commit message is a merge of `qa` (pull request #122). Other branches were not listed.

| Item | Evidence |
|---|---|
| Tip | `0c7d5df` on 2024-10-23, merge of qa PR #122 |
| Production deploy branch | `master` in `bitbucket-pipelines.yml` |
| QA deploy branch | `qa` in `bitbucket-pipelines.yml` |
| History before the tip | Not inspected (depth-1 clone) |

## Scope in the repository

In scope of what is present on `master`:

- A CodeIgniter 4.3.8 application (`codeigniter4/framework` pinned to `4.3.8`, PHP `^8.0`).
- Session login, self-registration, forgot-password and set-password screens, and menu grants.
- USSD menus for enrolment, initial assessment, lessons, and account management (`app/Views/ussd/ussd.php`, `app/Models/USSDModel.php`).
- Africa's Talking voice callbacks that play S3/CloudFront audio and collect DTMF (`app/Views/ussd/assessments.php`, `app/Views/ussd/assessments_events_handler.php`).
- Staff CRUD for households, students, lessons, levels, questions, languages, media, settings, email templates, and logs.
- A lesson flow builder (`Lessons::logicbuilder` and related views).
- Salesforce REST bulk upserts (`app/Controllers/Salesforce.php`, `app/Helpers/salesforce_helper.php`).
- Reports for student engagement, student answers, dropped calls, redialled calls, initiated assessments, and call performance.
- A JSON organisations resource that issues a JWT (`app/Controllers/Organisations.php`).
- AWS CodeDeploy to `/var/www/html` from Bitbucket Pipelines on `master` and `qa`.
- Developer screens: menu management, CRUD generator, database table view, cron jobs.

Out of scope of the code that was found, or present only as a stub, comment, or unused file:

- `buildingtomorrow.wsdl` (Salesforce Enterprise WSDL, API 57.0, generated 2023-04-07). No PHP reference to the file or to `SoapClient` was found under `app/`.
- ChatGPT. `ChatGPT` calls `helper('chatgpt')` and `chatGPTMessage()`. No such helper or function exists under `app/`, and no `ChatGPT` view was found.
- SonarQube as a running pipeline step. The scan step in `bitbucket-pipelines.yml` is commented out. `sonar-project.properties` still sets `sonar.projectKey`.
- PHPUnit coverage of the learner flows. `tests/` contains the CodeIgniter examples only.
- mPDF and PhpSpreadsheet usage in application code. They are Composer requirements. No call site under `app/` was confirmed in this pass.
- A background queue worker. Call and SMS rows are written to `sending_queue_log`. The scheduled command runs Salesforce sync functions, not a generic queue consumer.

## System architecture

```text
Staff browser
  → Apache (CodeDeploy destination /var/www/html, public/ is the intended web root)
      → CodeIgniter 4.3.8
          → Filters: session login, then menu grant (both have public exceptions)
          → Controllers under app/Controllers
          → MySQL database name buildingtomorrow (from the committed env template)
          → Views (Bootstrap 5, DataTables, jQuery)

Handset (USSD)
  → GET /ussd (Africa's Talking posts sessionId, serviceCode, phoneNumber, text)
      → app/Views/ussd/ussd.php
          → USSDModel (enrolment, assessment, lesson, account management)
          → africas_talking_log

Handset (voice)
  → Africa's Talking voice call (username siliAdmin, from-number from settings)
      → GET /assessments plays question audio (GetDigits XML)
      → GET /assessments_events_handler scores the digit and advances the flow
          → answer_log, student progress, optional SMS

Scheduler
  → GET /cronjob/runScheduledJobs  or  php spark custom:cronjobcommand
      → Salesforce bulk API (credentials from AWS SSM parameters)
          → Household__c, Students_Updated__c, Level__c, Lesson__c,
            Level_Lesson_Relationship__c, Student_Level_Relationship__c,
            Student_Level_Lesson_Relationship__c

Media upload
  → MediaModel → S3 bucket and CloudFront host from AWS SSM parameters
```

`Routes.php` sets `$routes->setAutoRoute(true)` and the default controller to `Home`. Many staff screens are reached by controller name rather than by an explicit route.

## Major components

| Component | Location | Role |
|---|---|---|
| USSD session | `app/Views/ussd/ussd.php`, `app/Models/USSDModel.php` | Menu, enrolment, resume of an open session |
| Voice playback | `app/Views/ussd/assessments.php` | Africa's Talking XML that plays the current question |
| Voice events | `app/Views/ussd/assessments_events_handler.php` | DTMF, scoring, next question, completion audio and SMS |
| Content admin | `Lessons`, `Levels`, `Questions`, `Language`, `Media` | Lessons, levels, questions, languages, audio |
| Flow builder | `Lessons::logicbuilder*` , `app/Views/logicbuilder/` | Draw the question graph |
| People | `Household`, `Students` | Household and learner records |
| Salesforce sync | `Salesforce`, `salesforce_helper.php`, `SalesforceModel` | Bulk upsert and write-back of Salesforce ids |
| Cron | `Developers\Cronjob`, `app/Commands/CronjobCommand.php` | Run the sync functions named in `scheduled_cronjob` |
| Reports | `Studentengagementreport`, `Studentanswerreport`, `Studentanswerrpt`, `Droppedcallsreport`, `Redialledreport`, `Performancetracking`, `Initiatedassessments` | Staff reports |
| Access | `Welcome`, `Users`, `Filters\Authentication`, `Filters\Authorization` | Login and menu grants |
| Organisations API | `Organisations`, `Libraries/JwtLibrary.php` | JSON CRUD with a bearer token |
| Deploy | `bitbucket-pipelines.yml`, `appspec.yml`, `codedeploy_deploy.py`, `scripts/` | Zip, S3, CodeDeploy, `composer update`, `php spark migrate` |

## Milestones visible in the tree

These are implementation milestones inferred from migration dates and the tip commit. They are not a signed project plan.

| When | What landed in migrations or the tip |
|---|---|
| 2022-11 | Users, roles, menus, access, sessions, organisations |
| 2023-03 | Lessons, levels, questions, assessments, answer log, contacts, enrol, cronjob |
| 2023-04 | Students, households, languages, logs, lesson flow, Salesforce log, settings, scheduled cron |
| 2023-05 | Media, templates, Africa's Talking log, question language |
| 2023-08 | Extra lesson, lesson-flow, Africa's Talking, and student columns. The student extra-column migration body is inside a block comment |
| 2023-10 | Extra answer-log field |
| 2024-01 | Lesson flow `require_response` style column (`LessonsFlowRequireResponse3`) |
| 2024-03 | Answer-log number-recognition field |
| 2024-05 | `africas_talking_log.call_redialled` |
| 2024-10-23 | Tip: merge of qa pull request #122 |

## Implementation plan

No forward implementation plan is stored in the repository. `README.md` points at a Jira board for "Development TODOS". The contents of that board were not read.

The deploy path that is implemented:

1. A push to `qa` or `master` runs Bitbucket Pipelines (`python:3.5.7`).
2. The step zips the tree and runs `codedeploy_deploy.py` with AWS and CodeDeploy variables from the pipeline environment.
3. CodeDeploy copies the archive to `/var/www/html`, runs `scripts/install_dependencies` (the file only contains a commented `yum` line), then `scripts/start_server`.
4. `start_server` runs `composer update --no-dev`, tries to start httpd or apache2, and runs `php spark migrate`.

## Known dependencies

- PHP `^8.0` with intl, curl, mbstring, mysqlnd, json, xml (`README.md`).
- CodeIgniter 4.3.8.
- MySQL via MySQLi. Template database name `buildingtomorrow` on `localhost`, user `root`, empty password (`env`).
- Africa's Talking PHP SDK `^3.0` for voice (and the USSD callback contract).
- Salesforce REST bulk API. Client id, secret, login URL, and base URL are read from AWS SSM. Parameter names in code: `SALEFORCE_BASE_URL`, `SALEFORCE_CLIENT_ID`, `SALESFORCE_CLIENT_SECRET`, `SALESFORCE_LOGIN_URL` (the first two names omit an S).
- AWS SDK for S3 media and SSM. Media parameter names: `MEDIA_UPLOAD_BUCKET`, `MEDIA_UPLOAD_CLOUDFRONT_END_POINT`.
- Composer packages also required, with no confirmed call site in `app/` during this pass: `aws/aws-sdk-php` is used; `mpdf/mpdf` and `phpoffice/phpspreadsheet` were not found in use; `orhanerday/open-ai` is required and the ChatGPT helper that would call it is missing.
- jQuery, Bootstrap 5, DataTables, and a gulp/sass toolchain for `public/assets`.

## Current project status

**Implemented** on `master` as of 2024-10-23: the admin shell, USSD and voice lesson loop, Salesforce bulk sync, media upload, and the reports named above.

**Not established:**

- Whether `master` at `0c7d5df` is what production is running now. The inspection date is almost two years after the tip.
- The live USSD short code. A comment in `ussd.php` names `*134*433*33#`. The menus read `getSetting("ussd_code")`.
- The AWS account, CodeDeploy application names, and hostnames. They are pipeline variables, not values in git.
- Whether the organisations API is called by any other system.
- Whether self-registration is exposed in production. The route exists and assigns role id 1 (Developer).

Discrepancies that need a human decision are listed in the PRD and business-rules documents. They are not treated here as approved product changes.
