# Features — BuildingTomorrow

Evidence date: 2026-10-19.

Source: `master` at `0c7d5df` (2024-10-23). No earlier Silicon Ark feature list exists for this repository. History before the tip was not cloned.

Status words: **Current** means the code on that tip does the thing. **Starter** means it comes from the Admin Overdrive skeleton and is still wired up. **Stub** means a class or route exists and does not complete the behaviour. **Unused file** means nothing in `app/` references it.

## Current — phone channel

| Feature | Status | Evidence |
|---|---|---|
| USSD callback | Current | `GET ussd` → `Ussd::index` → `app/Views/ussd/ussd.php`. Filter exception |
| Resume an open USSD session | Current | Empty `text` plus a log row whose menu does not contain `END` |
| New-session menus from settings | Current | `unregistered_household_menu`, `registered_household_no_students_menu`, `registered_household_registered_students_menu` |
| Enrolment question walk | Current | `USSDModel::ussd_enrol_user` |
| Unique learner first name in a household | Current | Question `dbTable=student`, `dbField=first_name`, `isUnique=1` |
| Confirm enrolment with input `1` and insert household plus student | Current | `createNewHouseholdStudent` |
| Initial assessment before lessons | Current | END copy in `USSDModel::assessment` and `USSDModel::lesson` |
| Place an Africa's Talking voice call | Current | `USSDModel::initiate_africas_talking_call`. Username `siliAdmin`. From-number setting `africas_talking_ugandan_number` |
| Play the current question | Current | `app/Views/ussd/assessments.php` GetDigits / Play XML |
| Collect digits and advance the flow | Current | `app/Views/ussd/assessments_events_handler.php` |
| Repeat key and no-answer proceed key | Current | Settings `question_repeat_key`, `question_no_answer_proceed_key` |
| Fail a level under the pass score | Current | Lesson type `assessment` compared with `pass_score`; audio setting `level_failed_audio` |
| Lesson and programme completion audio | Current | `lesson_completed_congratulatory_audio`, `lesson_program_completed_congratulatory_audio` |
| Number-recognition failure resets progress | Current | `reset_user_progress_on_number_recognition_fail` |
| Store call cost, status, and duration | Current | `updateAfricasTalkingCallCosts` when `isActive` is not 1 |
| Mark an unfinished initiated assessment as redialled | Current | `call_redialled` column migration `2024-05-01-150910`, `updateAfricasTalkingRedialledCall` |
| SMS with template substitution | Current | `SendSMS`, `get_template`, `Substitute`. Dropped-call SMS in `assessments.php` is commented out |
| Account management: household opt-out, student opt-out, opt-in, number transfer, student field updates | Current | `USSDModel::account_management` and helpers in `common_helper.php` |
| Account-management option described as under maintenance | Current, conflicting | `USSDModel::ussd_enrol_user` case `2` returns that END string. The view routes action `account_management` to the real handler |

## Current — content and people

| Feature | Status | Evidence |
|---|---|---|
| Households CRUD | Current | `Household` controller, `householdsList` view, `household` table |
| Students CRUD | Current | `Students`, `app/Views/students/students.php`, `student` table |
| Levels CRUD | Current | `Levels`, `level` table |
| Lessons CRUD | Current | `Lessons`, `lessons` table. Types on the form: number recognition, assessment, enrolment, initial assessment, learning |
| Questions CRUD and audio attach | Current | `Questions::createQuestion`, `AddAudio`, `Media` |
| Languages CRUD | Current | `Language` |
| Media library upload to S3 | Current | `Media::createAudioFile`, `MediaModel` S3 put/delete, CloudFront URL |
| Lesson ordering | Current | `Lessons::updateLessonOrdering`, `reorderLessonsPerLevel` |
| Flow builder | Current | Routes `logicbuilder`, views under `app/Views/logicbuilder/`. Select2 is loaded from cdnjs on that URL |
| Manual flow test | Current | `Lessons::questiontest`, `Lessons::manual_flow_test` |
| Settings key/value store | Current | `Settings`, `settings` table, `getSetting` |
| Email templates | Current | `EmailTemplate`, `templates` migration |
| Sending-queue log and resend | Current | `Email::index`, `resendEmail`, `sending_queue_log` |

## Current — Salesforce

| Feature | Status | Evidence |
|---|---|---|
| Client-credentials login and cached token | Current | `authenticateWithSalesforce`, settings `SALESFORCE_ACCESS_TOKEN` |
| Bulk upsert households, students, levels, lessons, level-lesson links | Current | `Salesforce::sync*InBulk` |
| Bulk upsert student-level and student-level-lesson relationships | Current | Methods from `createStudentLevels` downward |
| Write Salesforce ids back to MySQL | Current | `processSuccessfulResults`, `updateAnswerLogSalesforceID` |
| Sync log | Current | `salesforce_log`, `Logs::getSalesForceLog` |
| Manual and scheduled run | Current | `Developers\Cronjob::runJobs`, `runScheduledJobs`, spark `custom:cronjobcommand` |
| TLS verification disabled | Current | `CURLOPT_SSL_VERIFYPEER` 0 in `salesforce_helper.php`, marked testing-only in a comment |

## Current — reports

| Feature | Status | Evidence |
|---|---|---|
| Student engagement for a date range | Current | `Studentengagementreport`, `ReportModel::getStudentEngagement`. Default: first to last day of the current month |
| Student answer report | Current | `Studentanswerreport` and `Studentanswerrpt` (two controllers, both call lesson-detail helpers) |
| Dropped calls | Current | `Droppedcallsreport` |
| Redialled calls | Current | `Redialledreport` |
| Initiated assessments list | Current | `Initiatedassessments`, view `africastalking/initiated_assessments.php` |
| Call performance tracking | Current | `Performancetracking`, view `africastalking/performance_tracking.php` |
| Africa's Talking log browser | Current | `Logs::getAfricasTalkingLog`, view `logs/africastalkingLog.php` |

Seeded menus do not list the report URLs except "Performance Tracking", whose URL is `#`. See the PRD.

## Current — access and admin shell

| Feature | Status | Evidence |
|---|---|---|
| Login and logout | Starter, current | `Welcome::index`, `Welcome::logout` |
| Forgot password, set password | Starter, current | `Welcome::forgot_password`, `reset_password`, `set_password`, `update_password` |
| Self-registration as role 1 | Starter, current | `Welcome::registration` |
| Users, roles, menu grants | Starter, current | `Users`, seeds `UserRole`, `UserMenu`, `UserAccess` |
| Menu categories | Starter, current | Seed: Material, Content development, Settings, Reports, Developers |
| Profile update | Current | `Profile::updateProfile` |
| Forbidden page | Current | `GET blocked` |
| Menu management that can write a controller and view | Starter, current | `Developers\MenuManagement` |
| CRUD generator | Starter, current | `Developers\CRUDGenerator` |
| Database table viewer | Starter, current | `Developers\DbTableDataView`, `DbAdmin` |
| Dashboard | Starter, current | `Home::index`, seeded menu URL `home` |

Seeded Material menus: Dashboard, Households, Students, Lessons, Levels, Questions, Media.

Seeded Content development menus: Email Template, Flow Builder (`lessons/logicbuilder`).

Seeded Settings menus: Users, User Roles, Language, Logs, Sending queue Log.

Seeded Developers menus: Menu Management, CRUD Generator, Db Tables View, Cron Job.

## Organisations API

| Feature | Status | Evidence |
|---|---|---|
| Login with organisation name and API key | Current | `Organisations::login` |
| Bearer-token list, show, create, update, delete | Current | Resource controller. Route comments in `Routes.php` document the URLs |
| Token lifetime 6000 seconds, HS256 | Current | `JwtLibrary`, default secret literal `secret` |

Response copy still says "Employee". The list JSON key is `incident_type`. Both are **Inferred** leftovers.

## Stub, commented, or unused

| Feature | Status | Evidence |
|---|---|---|
| ChatGPT page | Stub | `ChatGPT::index` loads helper `chatgpt` and view `ChatGPT`. Neither file exists. `chatGPTMessage` is not defined. Package `orhanerday/open-ai` is required |
| SMS when a voice call ends | Removed from the active path | Block in `assessments.php` is inside a comment |
| Salesforce Enterprise SOAP | Unused file | `buildingtomorrow.wsdl`. No reference under `app/` |
| SonarQube scan on the pipeline | Commented | `bitbucket-pipelines.yml` build step is commented. `sonar-project.properties` remains |
| Student Salesforce placement columns via migration | Commented | `2023-08-10-124016_StudentExtraFields2.php` `up()` body is a block comment. Call sites still mention `initial_assessment_placement_level_salesforce_id` |
| `install_dependencies` hook | Stub | File contains only a commented `yum install` |
| PHPUnit domain tests | Not present | `tests/` is the framework sample (`HealthTest`, example session, example database) |
| mPDF and PhpSpreadsheet | Dependency only | In `composer.json`. No use under `app/` was found in this pass |
| Drawflow "AWS" palette node | Present in the builder UI | `logicbuilderquestionflow.php` has a draggable node labelled AWS. It is a builder palette item, not an AWS integration |

## Planned

Nothing in the repository describes a planned feature except:

- `README.md` "Development TODOS" links to a Jira board. The board was not read.
- The Sonar step is written and then commented, which reads as an intended scan that is not active.

Provenance: **Planned** only as those two pointers. **Unknown** what the board contains.

## Recently changed

The depth-1 clone cannot show a diff series. The newest schema change in the tree is the May 2024 migration that adds `africas_talking_log.call_redialled`. The tip commit, 23 October 2024, is a merge of qa pull request #122. The files included in that merge versus its parents were not diffed.

## Deprecated or removed

No removal log exists in the repository. Commented blocks (end-of-call SMS, student extra columns, Sonar step, SOAP WSDL with no caller) are the only evidence of behaviour that was turned down or never connected. They are not marked deprecated in comments except the Salesforce TLS lines, which say to remove the bypass before live use.
