# Technical documentation — DoctorX_lambda_api_Josh

Evidence date: 2026-10-16.

Source: `git@bitbucket.org:overdrive/doctorx_lambda_api_josh.git`, `master` at `40da799` (2021-04-30).

Credential values are not in git. This document names environment variables and does not invent their values. Mock files contain a `requestContext`; those values are omitted.

## What this repository is

A Serverless Framework service (`service: josh-lambda-api`) that packages Node.js Lambda functions. HTTP routes use API Gateway with an IAM authorizer. Data access is `serverless-mysql` plus the AWS SDK DynamoDB document client.

The tree started as a copy of the Unity lambda API (`7a24423`, service name `unity-lambda-api`). `df3b05d` removed those handlers. `README.md`, `LICENSE` (MIT, copyright 2017 Anomaly Innovations), and `package.json` name `serverless-nodejs-starter` version `1.1.0` were not updated except the README heading "DoctorX lambda api (josh)". The GitHub repository URL in `package.json` is still `https://github.com/AnomalyInnovations/serverless-nodejs-starter.git`.

## Repository layout

```text
serverless.yml                 service, provider, six functions, resources
resources/api-gateway-errors.yml
package.json
package-lock.json
yarn.lock
adduser.js                     crmDoctors insert (routed)
getusers.js                    all crmDoctors rows (routed)
updateuser.js                  crmDoctors update (routed)
getdetails.js                  crmDoctors by DoctorID (routed)
getuseruuid.js                 crmDoctors by strEmail (routed)
postxray.js                    fixed diagnose string (routed)
global.js                      generic SQL (not routed)
logging.js                     DynamoDB audit put
libs/handler-lib.js            status and CORS wrapper
libs/response-lib.js           success() and failure()
libs/dynamodb-lib.js           DocumentClient promise helpers (not imported)
libs/images-lib.js             empty
mocks/*.json                   local invoke events
tests/adduser.test.js          constant assertion
README.md                      starter text
LICENSE                        MIT, Anomaly Innovations 2017
.gitignore
```

Not in git at this revision: `.env`, `env.yml`, `node_modules`, `.serverless`, `.webpack`. `sonar-project.properties` and `sonarqube_scan.bat` were named in the 2026-09-28 scan-host file list and are not in `git ls-files`.

## Route table

Stage prefix `/prod` is a Serverless default for this file. No custom domain is declared.

| Function key | Handler | Method | Path | SQL or result |
|---|---|---|---|---|
| `create` | `adduser.main` | POST | `josh/create` | `INSERT INTO crmDoctors` |
| `getusers` | `getusers.main` | POST | `josh/getusers` | `SELECT * FROM crmDoctors` |
| `update` | `updateuser.main` | POST | `josh/update` | `UPDATE crmDoctors` |
| `get` | `getdetails.main` | POST | `josh/get` | `SELECT * ... WHERE DoctorID = {id}` |
| `getuseruuid` | `getuseruuid.main` | POST | `josh/getuuid` | `SELECT * ... WHERE strEmail = "{strEmail}"` |
| `diagnose` | `postxray.main` | POST | `josh/diagnose` | fixed object, no SQL |

YAML comments above `create`, `getusers`, `update`, `getuseruuid`, and `diagnose` still say method GET and the older paths `/josh/adduser`, `/josh/updateuser`, `/josh/getuseruuid`, and `/josh/postxray`. The `events` blocks are the routes that deploy.

All six events set `cors: true` and `authorizer: aws_iam`.

## Provider settings

| Setting | Value in `serverless.yml` |
|---|---|
| `provider.name` | `aws` |
| `runtime` | `nodejs12.x` |
| `stage` | `prod` |
| `region` | `eu-west-1` |
| `profile` | `unity` |
| `memorySize` | `512` |
| `package.individually` | `true` |
| `environment.tableName` | `loging` |
| `environment.databaseHost` | `${env:DBHOST}` |
| `environment.databaseUser` | `${env:DBUSERNAME}` |
| `environment.databasePass` | `${env:DBPASSWORD}` |
| `environment.databaseName` | `${env:DBNAME}` |

VPC `securityGroupIds` / `subnetIds` are comments. They are not deployed.

Plugins, in order: `serverless-bundle`, `serverless-offline`, `serverless-dotenv-plugin`.

IAM role statement: `dynamodb:DescribeTable`, `Query`, `Scan`, `GetItem`, `PutItem`, `UpdateItem`, `DeleteItem` on `arn:aws:dynamodb:eu-west-1:*:*`.

There is no `httpApi`, no authorizer resource, no `AWS::DynamoDB::Table`, and no S3, SQS, SNS, or EventBridge resource.

## Request handling

`libs/handler-lib.js` returns a function that:

1. Runs the inner async function.
2. On resolve, status 200 and body = `JSON.stringify` of whatever the inner function returned.
3. On reject, status 500 and body = `JSON.stringify({ error: e.message })`.
4. Sets `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Credentials: true`.

`success(body)` and `failure(body)` in `libs/response-lib.js` build the same headers with status 200 or 500 and `JSON.stringify(body)`. The handlers return those objects. The wrapper stringifies them again. Clients that read the Lambda proxy body must parse twice to reach the MySQL result. A `failure()` return does not reject, so API Gateway sees HTTP 200.

`adduser.js`, `updateuser.js`, `getdetails.js`, and `getuseruuid.js` copy `JSON.parse(event.body)` and then `event.pathParameters` into one object. Path keys overwrite body keys. They `console.log` the event, the parameter object, and (in create) the SQL string.

`getusers.js` and `postxray.js` do not parse a body.

## MySQL

Each routed SQL handler (not `postxray.js`) creates `serverless-mysql` with:

```text
host     = process.env.databaseHost
database = process.env.databaseName
user     = process.env.databaseUser
password = process.env.databasePass
```

Queries are concatenated strings. There are no `?` placeholders. After `mysql.query`, the handler calls `mysql.end()`.

`postxray.js` contains the same client constructor inside a block comment.

`global.js` uses the same client and is not referenced from `serverless.yml`.

## DynamoDB audit

`logging.js`:

```text
TableName = process.env.tableName
userID    = event.requestContext.identity.cognitoIdentityId
logID     = uuid.v1()
event     = JSON.stringify(event)
query     = JSON.stringify(query)
result    = JSON.stringify(result)
createdAt = Date.now()
```

`dynamoDb.put` uses a callback. The function returns before the callback runs. `libs/dynamodb-lib.js` is a separate promise wrapper and has no callers.

`postxray.js` calls `log(event, results)`, so `query` is `undefined`. `JSON.stringify(undefined)` is not a string. The document client rejects `undefined` attribute values. That failure stays in the callback.

## API Gateway error responses

`resources/api-gateway-errors.yml` defines `GatewayResponseDefault4XX` and `GatewayResponseDefault5XX` on `ApiGatewayRestApi`. Both set:

- `gatewayresponse.header.Access-Control-Allow-Origin` = `'*'`
- `gatewayresponse.header.Access-Control-Allow-Headers` = `'*'`

These cover gateway-generated 4XX and 5XX (including IAM denies). They do not change the double-encoded handler body.

## Dependencies

From `package.json`:

| Package | Range | Section |
|---|---|---|
| `serverless-mysql` | `^1.5.4` | dependencies |
| `uuid` | `^7.0.3` | dependencies |
| `aws-sdk` | `^2.706.0` | devDependencies |
| `serverless-bundle` | `^1.2.5` | devDependencies |
| `serverless-dotenv-plugin` | `^2.1.1` | devDependencies |
| `serverless-offline` | `^5.3.3` | devDependencies |

`aws-sdk` is imported by `logging.js` and `libs/dynamodb-lib.js`. On Node.js 12 Lambda it is provided by the runtime. It is not a production `dependencies` entry.

`npm test` runs `serverless-bundle test`. The only test file does not load a handler.

`package-lock.json` and `yarn.lock` are both in git.

## Environment and ignore rules

`.gitignore` ignores `logs`, `node_modules`, `coverage`, `.webpack`, `.serverless`, `env.yml`, `.env`, and `.idea`.

The README still tells the reader to copy `env.example`. That file was removed in `df3b05d`. Names the template actually interpolates: `DBHOST`, `DBUSERNAME`, `DBPASSWORD`, `DBNAME`. Names that appear only in comments: `SECURITYGROUPIDS`, `SUBNETIDS1`, `SUBNETIDS2`.

Deploy uses the AWS shared config profile `unity` (`provider.profile`). The profile's keys are not in the repo.

## Local development steps that the README states

The README documents `serverless invoke local --function hello`, `serverless offline start`, `serverless deploy`, and `serverless deploy function --function hello`. There is no `hello` function in `serverless.yml`. The function keys that exist are `create`, `getusers`, `update`, `get`, `getuseruuid`, and `diagnose`.

Mocks are shaped for an invoke event (`pathParameters` plus `requestContext`). The README does not mention the `mocks/` directory.

## Testing

`tests/adduser.test.js` is a Jest test in name only. Expected and actual are both the literal `4000`. `storage` is unused. It cannot fail unless the file is edited.

No integration test, fixture database, or CI config is in the tree.

## Deployment and operations

No `bitbucket-pipelines.yml`, Dockerfile, buildspec, or serverless dashboard config was found.

`serverless deploy` from a machine with Serverless, Node, the `unity` AWS profile, and a `.env` containing the four `DB*` names is the only deploy path the template supports. Whether anyone has run it since 2021-04-30 is **Unknown**.

CloudWatch is implied by Lambda and by the `console.log` calls. No log group, metric, or alarm is declared. The README's claim about Webpack sourcemaps in CloudWatch is starter text. `serverless-bundle` is installed, which is consistent with that claim, and this repo does not add its own bundle config.

## Security notes (observed, not a design)

- SQL values are concatenated. Create escapes only single quotes inside `strRole`.
- `SELECT *` and the unfiltered list return the full row to any IAM caller who can invoke the route.
- The DynamoDB IAM resource is the whole `eu-west-1` account partition in the role, not the `loging` table ARN.
- The audit item stores `JSON.stringify(event)`, which includes the body and path the caller sent.
- CORS allows origin `*` together with `Access-Control-Allow-Credentials: true`.

## Process

Git history is 28 commits on `master` only, 2021-03-17 through 2021-04-30, authors Joshua Gatley-Dewing and Jaco Brits. Several merges are "Merge branch 'master' of https://bitbucket.org/overdrive/doctorx_lambda_api_josh", so two clones were pushing to `master`. No pull-request template or branching model file is in the repo.

`0067c18` (2021-04-28, "serverless.yml edited online with Bitbucket") is in the history. The tip's `serverless.yml` matches the six-route shape introduced by `414737d`. A line-by-line read of the online edit was not required beyond the route table at the tip.

## Related Silicon Ark directory

`unity-lambda-api` documents the service this repository was copied from. Current code here does not import that repository. The shared AWS profile name `unity` and the shared table-name string `loging` are the remaining template links. Treat a shared database or a shared deployment as **Unknown / Requires Confirmation**.
