# Project plan — lambda_grinder

Evidence date: 2026-10-10.

Source: `git@bitbucket.org:overdrive/lambda_grinder.git`, branch `main` at `ffa0b1e0` (2025-03-22, "update files for deployment").

There is no prior `lambda_grinder` directory in Silicon Ark. The source README is an architecture note for a Lambda split. It is not a project plan. No milestone dates, owners, or release checklist are in the repository.

A sibling Silicon Ark set, `orginal_code` (`main` at `18caf8e`, 2024-11-12), describes the same Express route mounts, `grinder.js`, and `schedule.js` shape. This plan does not treat the two repositories as one codebase. They were not diffed file by file.

## Purpose

**Inferred.** Run a single-course golf operations service: accept GPS fixes from tags, turn those fixes into rounds, and expose staff and on-course APIs for tee times, devices, pace, geofences, caddies, players, food and beverage, and messages.

**Documented** in `README.md` as a breakout of `grinder.js` into Lambda functions "to improve modularity, scalability, and maintainability of the golf round tracking system."

**Implemented** as two things at once:

1. The original Node processes are still in the tree: `app.js` (Express and Socket.IO), `grinder.js` (5-second fix loop), and `schedule.js` (cron).
2. An AWS SAM application in `template.yaml` deploys two functions, `FixInsert` and `GrindFunction`, plus an API, an SQS queue, a dead-letter queue, layers, and one CloudWatch alarm.

## Scope

In scope for this repository, from the tree at `ffa0b1e0`:

- HTTP API mounted in `app.js`.
- Background round builder `grinder.js`.
- Scheduled jobs in `schedule.js`.
- SAM resources in `template.yaml` and `samconfig.toml`.
- Lambda handlers `FixInsert/index.js` and `grind/index.js`.
- MongoDB models under `models/`, duplicated as Lambda layer schemas under `layers/database/nodejs/models/`.
- Tee-sheet provider modules under `teetimes/providers/`.

Out of scope of this repository, and not present as source:

- The browser client that calls the JWT routes. CORS defaults point at localhost port 3000.
- The Laravel-style user service called through `LOCALHOST`.
- The legacy site `https://{course}.tagmarshal.com` that course import reads.
- The SAM stacks named in `samconfig.toml` were not queried. Whether they are still deployed is **Unknown**.

## Status

| Item | Evidence | State |
|---|---|---|
| Last commit | `ffa0b1e0`, 2025-03-22 | Committed SAM build output under `.aws-sam/build/` and layer `node_modules` |
| Breakout commit | `cd41d752`, 2024-11-21, "Grinder lambda breakout" | Start of the Lambda work after `40f05300` "Initial commit" (2024-11-06) |
| SAM config names | `samconfig.toml` | Stack names `EttieneSamLayerDeployTest14` and `EttieneSamLayerDeployTest8`, region `us-east-2`, profile `tagm` |
| README target | Three functions: Grind (schedule), Handle Fix (SQS), Get Raw Fixes (HTTP) | **Documented**. Only two functions are in `template.yaml`, and their triggers do not match that README |
| Lambda round logic | `grind/index.js` | Hardcodes course `Steenberg`, deletes every `Round` when one round has more than 100 locations, and comments say "create new test round" |
| Original round logic | `grinder.js` | Still present and still polls MongoDB |
| Tests | `tests/app.test.js` | A Jest test whose body is `// TODO: write test` |
| Sonar files named at onboarding | `sonar-project.properties`, `sonarqube_scan.bat` | **Not in git** at `ffa0b1e0`. They were listed from a scan-host working tree on 2026-09-28 |

**Inferred** current status: a deployment experiment on top of the course API, using test stack names, not a finished replacement of `grinder.js`.

**Unknown / Requires Confirmation:** whether production still runs `node app.js`, `node grinder.js`, and `node schedule.js`; whether the SAM stack is the live fix path; whether `Steenberg` is the only course this Lambda build is allowed to touch.

## Architecture

```text
On-course tag
    |
    |  Express (still in tree)                SAM (template.yaml)
    |  POST /device/fix/:imei                 POST /device/fix/{device_id}
    |  writes Fix in MongoDB                  FixInsert -> SQS FixProcessingQueue
    |                                          GrindFunction (batch 10)
    v                                          |
MongoDB database "tagmarshal"  <--------------+
    ^
    |
app.js  ------ staff and device HTTP API, Socket.IO
grinder.js ---- every 5s, Fix -> Round (full rules)
schedule.js --- tee sheets, midnight close, pins, legacy fixes
```

Both ingest paths can write the same database. They do not call each other.

Mongo host hardcoded in `app.js`, `grinder.js`, and `schedule.js`, and set as `mongoqrnlb` on `GrindFunction`:

`tagmarshal-poc-data-config-nlb-3d7a4f2e6b8260e7.elb.us-east-2.amazonaws.com:27017`, database name `tagmarshal`.

`.env` also has a `DATABASE_URL` key. The three Node entry points above do not read it.

## Major components

| Component | Path | Role |
|---|---|---|
| API process | `app.js` | Express mounts, CORS, Mongo connect, Socket.IO |
| Round loop | `grinder.js` | Poll fixes and maintain rounds |
| Scheduler | `schedule.js` | node-cron jobs |
| Fix ingest Lambda | `FixInsert/index.js` | Parse a form body and send SQS |
| Grind Lambda | `grind/index.js` | SAM handler. Insert fixes and a simplified round update |
| Unused grind drafts | `grind/index copy.js`, `grind/newgrind.js`, `grind/grind-new.js`, `grind/*.txt` | Not the SAM handler (`index.handler`) |
| SAM template | `template.yaml` | Functions, layers, API, queues, alarm |
| Alternate template | `template-new.yaml` | Same description. Layer `ContentUri` values differ. Not referenced by `samconfig.toml` |
| Express domain code | `routes/`, `controllers/`, `models/`, `modules/` | Course operations API |
| Lambda domain copy | `layers/database/nodejs/` | Schemas and modules loaded from `/opt/nodejs` |
| Older layer copy | `layers/layer1/` | Commented out in `template.yaml` |
| Dependency layers | `layers/layer-node-modules/`, `layers/LayerAWSSDKONLY/` | Packaged `node_modules` for Lambda |
| Tee sheets | `teetimes/providers/*.js` | One module per provider name |
| SAM build output | `.aws-sam/build/` | Committed build artefacts, including copies of the grind drafts |

## Milestones

No milestone list exists in the repository. The commit subjects that describe the work are:

| Date | Commit | Subject |
|---|---|---|
| 2024-11-06 | `40f05300` | Initial commit |
| 2024-11-21 | `cd41d752` | Grinder lambda breakout |
| 2025-03-05 | `097ed7e2` | updated |
| 2025-03-07 | several | "sending to Dirk", "adding new layers" |
| 2025-03-08 | `ff379891` | sending to Dirk |
| 2025-03-19 | `737d492b` | before tear down |
| 2025-03-22 | `ffa0b1e0` | update files for deployment |

**Unknown / Requires Confirmation:** who Dirk is in this context, what "tear down" removed, and whether any of those commits were accepted as production.

## Implementation plan as the code stands

There is no written plan after the README. The code shows this sequence, not a completed one:

1. Keep the Express API and the original `grinder.js`.
2. Add SAM functions for fix intake and grinding.
3. Move Mongo models and helper modules onto a Lambda layer (`layers/database`).
4. Move npm dependencies onto `layer-node-modules` and the AWS SDK onto `LayerAWSSDKONLY`.
5. Leave `HandleFix` and `GetRawFixes` named only in the README and in commented template outputs.

`grind/index.js` does not implement the round rules in `grinder.js` `handleFix`. See the PRD workflows and the conflict list.

## Dependencies

Runtime and libraries are listed in technical documentation. External systems the code calls:

- MongoDB on the NLB host above.
- Legacy Tagmarshal HTTP host `https://{course}.tagmarshal.com` (`controllers/course.js`).
- User and role HTTP API at `process.env.LOCALHOST` (`controllers/modules/user.js`). `.env.example` defines `LARAVEL_AUTH_SERVER`. The JavaScript that was searched does not read that name.
- Tee-sheet providers selected by `Config.teesheetIntegration.provider`.
- Golf Genius when `Config.golfGeniusConfig.apiKey` is set.
- European Tour helpers when the provider is `etx` (`modules/europeanTour.js`).
- Firebase, Mailgun, and MessageBird through environment variables read in `modules/notifications.js`, `modules/caddie.js`, and `modules/messagebird.js`. The variable names are in technical documentation. The secret files are not in git.
- AWS API Gateway, Lambda, SQS, CloudWatch, X-Ray, and the VPC subnets and security group written in `template.yaml`.
- Monday.com is coded in `controllers/course.js` after a `return`, so it does not run. The bearer token in that block is omitted from this documentation.

## Known risks in the tree

- `grind/index.js` calls `Round.deleteMany({})` before creating a round. That deletes every round in the database, not one course.
- `.gitignore` leaves `node_modules/` commented out, and the layer `node_modules` trees are committed. `.env` is tracked. Secret values are omitted here.
- `controllers/course.js` contains a hardcoded Monday.com bearer token in unreachable code.
- `controllers/modules/trackmap.js` contains a Gmail SMTP password next to `customerexperience@tagmarshal.com`. The password is omitted here.
- Express fix insert and the Lambda grind can both write `Fix` and `Round` documents. Nothing in the repo coordinates them.
- `tests/app.test.js` does not assert behaviour. Loading it requires `app.js`, which connects to MongoDB at import time.

## Human confirmation

- Is the live fix path the Express routes, `grinder.js`, the SAM queue, or more than one of those?
- Is the `Steenberg` course name and the delete-all-rounds behaviour approved, or is `grind/index.js` leftover test code?
- Should the README's third function and the 5-minute schedule be treated as cancelled?
- Are the test stack names in `samconfig.toml` the stacks that should stay deployed?
- Should the tracked `.env`, the Monday token, and the SMTP password be rotated?
- What is the intended relationship to the `orginal_code` repository?
