# Project plan — ear_lambdas

Evidence date: 2026-10-16.

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

Inspected revision: `master` at `1539c1d` (2023-09-27, Ettiene, "added on put function"). The scan-host path `~/projects/sonar_scan/repos/ear_lambdas` was not on this machine. The tree below was read from that git revision.

This repository is a snapshot of AWS Lambda console exports. It is not an application source tree and it has no written product plan. This document describes what is in the snapshot. It does not decide what the product should become.

Credential values that appear in the SAM templates are not copied here. See the security note in `technical-documentation.md`.

## Product

There is no README, PRD, or issue tracker in the source repository, and there was no `silicon_ark/ear_lambdas/` set before this one.

The commit that added the functions is `cc029a4` (2023-09-14, Ettiene), message "exports of all cape town lambdas". A later commit adds one more function. Provenance: **Documented** by that commit message that the export was intended to cover Cape Town Lambdas. The templates themselves do not set `AWS::Region`. Resource names, the RDS hostname, and a Lambda layer ARN use `af-south-1`. Provenance: **Inferred** that the functions were exported from `af-south-1`.

What the snapshot contains:

1. Five Node.js functions that HTTP GET `https://www.ear-academy.com/admin/...` paths. Two of them have EventBridge schedules in the template. Three are named for a time of day and have no schedule in the template.
2. Four Node.js functions from the Serverless service whose bundles were compiled from `C:/wamp64/www/theear_transcode/region_south_africa/` (source-map paths inside the zips): catalog an S3 object into MySQL `resources`, backfill that table from a staging bucket, write a DynamoDB "note", and a Serverless custom-resource helper for an existing S3 bucket.
3. One Node.js function that copies an S3 object from `the-ear-prod-resources` to `the-ear-prod-video-upload`.
4. Two Python 3.9 functions that read an HLS playlist and write `resources.duration`.

The sibling Silicon Ark set `theear_transcode/` documents the Serverless source those bundles name (`master` at `fda49df`, 2022-05-04). This repository is the 2023 console export of deployed Cape Town functions, plus cron ping functions and duration functions that are not in that source snapshot.

The public site name `www.ear-academy.com` is in the cron handlers. Bucket and database names use `the-ear`. Provenance: **Inferred** that this supports Ear Academy media and scheduled admin jobs. The audience, the owner of each job, and whether any function still runs are **Unknown / Requires Confirmation**.

## Branch reality

| Line | Tip | Date | What it is |
|---|---|---|---|
| `master` (default; `origin/HEAD`) | `1539c1d` | 2023-09-27 | Only branch. 5 commits |

| Commit | Date | Author | What changed |
|---|---|---|---|
| `9a4c214` | 2023-09-13 | Jaco Brits | Initial commit |
| `d9921eb` | 2023-09-13 | Jaco Brits | `sonar-project.properties` created online with Bitbucket |
| `731d7c9` | 2023-09-13 | Jaco Brits | `bitbucket-pipelines.yml` created online with Bitbucket |
| `cc029a4` | 2023-09-14 | Ettiene | "exports of all cape town lambdas". Eleven function zip/yaml pairs |
| `1539c1d` | 2023-09-27 | Ettiene | "added on put function". `VideoDurationOnPut.yaml` and its zip |

No commits after 2023-09-27. No other branches were present at inspection.

**Discrepancy:** the task-creation file list included `sonarqube_scan.bat` and "2 more entries". `sonarqube_scan.bat` is not in the tree at `1539c1d` and is not in the commit history that was fetched. Provenance: **Unknown** — it may have been an untracked file on the scan host.

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

- Keep a copy of the Cape Town Lambda configuration and the code that was deployed at export time.
- Ping Ear Academy admin HTTP routes on a schedule (daily bundle, and an hourly bundle).
- Record objects in the resources bucket as MySQL `resources` rows, and backfill from the staging bucket over HTTP.
- Copy a resources object to the Ireland video-upload bucket.
- Fill `resources.duration` from HLS playlists, on a schedule and on object create.
- Run SonarQube against `master`. The pipeline does not build or deploy.

## Scope

### In the export (one yaml plus one zip per function)

| Function (template logical id) | Handler | Runtime | Trigger in the template |
|---|---|---|---|
| `phpCronEveryDay` | `index.handler` | nodejs12.x | `cron(0 6 * * ? *)` |
| `phpCronEveryDay2am` | `index.handler` | nodejs14.x | none |
| `phpCronEveryDay6am` | `index.handler` | nodejs14.x | none |
| `phpCronEveryDay8am` | `index.handler` | nodejs16.x | none |
| `phpCronTrigger` | `index.handler` | nodejs12.x | `rate(1 hour)` |
| `theearresourcestoupload` | `index.handler` | nodejs12.x | none |
| `theearresourcesproductioncreate` | `create.main` | nodejs12.x | `POST /create` |
| `theearresourcesproductioncustomresourceexistings3` | `s3/handler.handler` | nodejs12.x | none (CloudFormation custom resource when invoked) |
| `theearresourcesproductionsortfiles` | `sort_files.main` | nodejs12.x | `GET /sort_files` |
| `theearresourcesproductiontranscode` | `transcode.main` | nodejs12.x | `s3:ObjectCreated:*` on template resource `Bucket1` |
| `videoDuration` | `lambda_function.lambda_handler` | python3.9 | `cron(0 18 * * ? *)` |
| `VideoDurationOnPut` | `lambda_function.lambda_handler` | python3.9 | `s3:ObjectCreated:*` on template resource `Bucket1` |

### Present in a zip but not the configured handler

The custom-resource zip also contains `cognitoUserPool/`, `eventBridge/`, and `apiGatewayCloudWatchRole/` handlers, plus `s3/lib/*` and `utils.js`. The template handler is only `s3/handler.handler`.

`VideoDurationOnPut` zip contains a second copy of `VideoDurationOnPut.yaml`.

`create.js`, `sort_files.js`, and `transcode.js` are Webpack bundles. Most of each file is `mysql` and other dependencies. The application module is at the end. Source maps name `region_south_africa/create.js`, `sort_files.js`, and `transcode.js`.

### Out of scope / not in this repository

- The PHP application behind `www.ear-academy.com`. This repo only lists URLs.
- The Serverless project that produced the bundles. That tree is `theear_transcode`.
- Elastic Transcoder pipeline definitions. The exported `transcode` handler does not call Elastic Transcoder. The client construction is commented out.
- MySQL table DDL. The handlers assume a `resources` table with columns used in the SQL text (`id`, `name`, `url`, `type`, `duration`, `created`, `status`).
- IAM policy documents. Templates name role ARNs. The policies are not in git.
- The real S3 bucket names for `theearresourcesproductiontranscode` and `VideoDurationOnPut`. Both templates declare an empty `AWS::S3::Bucket` called `Bucket1` with no `BucketName`.
- Tests, a deploy step, alarms, and a statement of which functions are still enabled in AWS.

## System architecture

```text
EventBridge
  phpCronEveryDay     cron(0 6 * * ? *)  --> HTTPS GET www.ear-academy.com/admin/...
  phpCronTrigger      rate(1 hour)       --> HTTPS GET www.ear-academy.com/admin/...
  videoDuration       cron(0 18 * * ? *) --> MySQL resources + CloudFront HLS

API Gateway (authorizer not in the export)
  POST /create       --> DynamoDB table name env tableName ("loging")
  GET  /sort_files   --> S3 list the-ear-staging-resources + MySQL insert if missing

S3 ObjectCreated (bucket name not in the template; code assumes a resources bucket)
  transcode          --> MySQL INSERT resources
  VideoDurationOnPut --> MySQL UPDATE resources.duration from CloudFront HLS

S3 event shape expected, trigger not in the template
  the-ear-resources-to-upload --> copy key to the-ear-prod-video-upload (eu-west-1 client)

CloudFormation (no event in the template)
  custom-resource-existing-s3 --> Lambda permission + bucket notification config

MySQL (env host, af-south-1 RDS cluster the-ear-prod-db-a, database the_ear_prod_db_a)
DynamoDB DocumentClient (region not set in create.js; table name from env)
```

Node catalog functions and `the-ear-resources-to-upload` use VPC security group `sg-04a9c8db07f607e2d` and subnets `subnet-0c90a693b84fa59b9`, `subnet-073bdac49e88c7daa`. The two Python functions use a different VPC attachment: `sg-0b1438e5765fd1440` and subnets `subnet-0d3f1cc6598f5d416`, `subnet-02d6fd15bd0519011`. The five PHP-cron functions have no `VpcConfig`.

Account id on every role ARN: `055752874982`.

## Major components

| Component | What it is in this repo |
|---|---|
| SAM template (`*.yaml`) | One `AWS::Serverless::Function` per file, `Transform: AWS::Serverless-2016-10-31`, `CodeUri: .`, `PackageType: Zip` |
| Deployment zip | Sibling file named `{function}-{uuid}.zip`. This is the code. It is not unpacked next to the yaml |
| PHP cron ping | `index.js` loops a hardcoded URL list and `https.get`s each one |
| Resources catalog | Webpack `transcode.main` inserts a `resources` row |
| Staging backfill | Webpack `sort_files.main` lists `the-ear-staging-resources` |
| Notes create | Webpack `create.main`, Serverless Stack starter, DynamoDB `put` |
| Existing-S3 custom resource | Serverless Framework helper, README is one sentence |
| Upload copy | `index.js` `s3.copyObject` toward `the-ear-prod-video-upload` |
| Duration | Python `m3u8` + `pymysql`, layer `packages:2` |
| SonarQube | `bitbucket-pipelines.yml` on branch `master` only |

## Milestones

There is no milestone list in the repository. The only timeline is the commit table above: Bitbucket and Sonar files on 2023-09-13, the Cape Town export on 2023-09-14, and `VideoDurationOnPut` on 2023-09-27. Nothing in git says these were planned releases.

## Implementation plan

None is written down. The pipeline does not run `sam deploy`, Serverless, or any test. Provenance: **Implemented** as a scan-only pipeline. How the Lambdas were originally deployed is **Inferred** to be the Lambda console (blueprint tag `lambda-console:blueprint: hello-world` on the cron and upload functions) and the Serverless Framework (source-map paths and the custom-resource package). **Requires Confirmation** for the actual deploy path.

## Known dependencies

- AWS Lambda, EventBridge schedules, API Gateway, S3, IAM roles, and (for two functions) a Lambda layer in `af-south-1`.
- Amazon RDS MySQL cluster named by the hostname `the-ear-prod-db-a.cluster-coaufliysybm.af-south-1.rds.amazonaws.com`, database `the_ear_prod_db_a`.
- DynamoDB table named by environment variable `tableName`. The create/sort/transcode templates set that variable to `loging`. `create.js` is the only handler that reads it.
- Public site `https://www.ear-academy.com`.
- CloudFront host `d1ogvodmq23438.cloudfront.net`, hardcoded in both Python files.
- S3 buckets named in code: `the-ear-prod-resources`, `the-ear-prod-video-upload`, `the-ear-staging-resources`.
- Python layer `arn:aws:lambda:af-south-1:055752874982:layer:packages:2`. Its contents are not in git. The handlers import `m3u8` and `pymysql`, which are not in the zip. Provenance: **Inferred** that the layer provides those libraries.
- npm packages bundled into the three large zips, including `mysql` (via `serverless-mysql` style `require`) and `uuid` v1. `aws-sdk` is an external.
- Bitbucket Pipelines pipe `sonarsource/sonarqube-scan:2.0.1` on image `maven:3.3.9`.

## Current project status

**Implemented** as a frozen export. Last change 2023-09-27. No application tests. No deploy automation. Node runtimes in the templates are `nodejs12.x`, `nodejs14.x`, and `nodejs16.x`. Whether AWS still invokes those runtimes was not checked against current AWS documentation in this pass. **Unknown / Requires Confirmation.**

Whether each function is still enabled, still attached to the schedules and buckets described, or has drifted since the export is **Unknown / Requires Confirmation**. This git tree cannot answer that.

## Human confirmation

1. Are these Lambdas still enabled in account `055752874982`, region `af-south-1`?
2. Do `phpCronEveryDay2am`, `phpCronEveryDay6am`, and `phpCronEveryDay8am` have schedules in AWS that the export omitted?
3. Which real buckets notify `theearresourcesproductiontranscode`, `VideoDurationOnPut`, and `theearresourcestoupload`?
4. Should the plaintext database password in the five SAM environment blocks be rotated and removed from git history?
5. Is `www.ear-academy.com` still the target of the cron pings, and are those admin routes still valid?
6. Is the DynamoDB table `loging` still the table `POST /create` writes, and in which region?
