* feat(cart): add a local Redefine cart filler
Match the admin order-list CSV to the live menu and add each meal to a guest cart so the weekly bulk order does not have to be typed in by hand.
* fix(cart): report cart failures without a traceback
A closed window or a failed cart request during the fill now prints a short failure and the Added/Failed/Skipped summary instead of crashing.
* fix(cart): fail cleanly on a bad CSV and a closed browser
A non-UTF-8 order list and a Playwright error while opening the page now print a short message and exit 1 instead of a traceback.
* fix(cart): account for a closed window and an empty menu
A closed page during add marks the remaining meals as not attempted, and an empty menu catalog raises the same error as the menu parser.
* feat(menu): publish the weekly menu from the job worker
Monday publish parses the catalog embedded in the Redefine menu page and runs on the Fargate worker, so the GitHub Actions scrape cron can go away.
* fix(menu): address review feedback
Use the form deadline in the Monday Slack post, and compare that message exactly so CodeQL does not treat the test as URL sanitization.
* chore(deps): update npm minor and patch
* test(openapi): stop pinning the Redocly patch version
Renovate minor bumps fail CI when the contract test hardcodes @redocly/cli.
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Adam Moussa <adam@seahavenind.com>
* ci(workflows): use autofix formatter presets (PLAT-222)
Point autofix at the presets commit so ruff and Terraform fmt use the
org presets, and write the template Prettier and ESLint fixes CI checks.
* style: add an unused import for autofix
Deliberate F401 in week_keys so the ruff preset can remove it.
* ci(workflows): pin autofix to v1.0.15 (PLAT-222)
The previous pin was the pre-squash commit, which became unreachable
when that branch was deleted, so CI failed before autofix started.
* style: apply formatter
---------
Co-authored-by: sea-haven-auto-fix[bot] <5037331+sea-haven-auto-fix[bot]@users.noreply.github.com>
* fix(iam): drop githubdeploy workflow_ref OIDC condition
AWS STS does not evaluate GitHub workflow_ref, so that trust condition fail-closes AssumeRoleWithWebIdentity.
* chore(security): retarget githubdeploy Checkov suppression
Dropping the workflow_ref trust condition shifted CKV_AWS_111 from line 49 to 42. Permissions are unchanged.
* style: apply formatter
---------
Co-authored-by: sea-haven-auto-fix[bot] <5037331+sea-haven-auto-fix[bot]@users.noreply.github.com>
* ci: convert onto org HCP reusables
Switch Fargate CD and CI to the v1.0.13 org workflows, emit ci-complete, and retarget githubdeploy OIDC to the reusable plus the thin caller.
* chore(security): retarget githubdeploy Checkov suppression
The OIDC dual-claim edit shifted CKV_AWS_111 from line 40 to 49. Permissions are unchanged.
* style: apply formatter
* ci: pin org reusables to v1.0.14
Drop collect-only and requirements from the python lint caller now that ci-python-app is lint-only.
* test(ci): probe autofix with a ruff format violation
* style: apply formatter
---------
Co-authored-by: sea-haven-auto-fix[bot] <5037331+sea-haven-auto-fix[bot]@users.noreply.github.com>
* feat(infra): export attached VPC ids and lock prod to afterhours (DEV-289)
Prod must keep existing_vpc_id pointed at the afterhours VPC. Outputs
expose the resolved vpc_id and public subnet IDs.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* feat(api): add OpenAPI 3.1 and Redocly lint in CI (DEV-289)
Same extends: recommended ruleset and @redocly/cli 2.52.1 as
internal-portal. Documents current { error: string } JSON errors.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(api): document 4xx and reject invalid form-status weeks (DEV-289)
Health, form-status, and roster document 400. form-status now maps
current and returns 400 for a week that is not current or YYYY-WNN.
Redocly treats 302 as a success response, matching the portal.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* style(test): format VPC contract assertions for ruff (DEV-289)
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(api): fail Redocly on missing 4xx and 2xx/3xx (DEV-289)
Promote operation-4xx-response and the 2xx-or-3xx success rule to error.
Replace unused health and roster 400s with 403, matching portal health.
Form-status keeps its real 400 for invalid week.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(api): split week params and allow live menu nulls (DEV-289)
Menu and form-status take current or YYYY-WNN. Orders take YYYY-WNN or a
calendar date and reject current. Menu payloads may emit null menu_url,
calories, protein, and image_url.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(infra): fail prod apply without the afterhours VPC (DEV-289)
Prod never creates the 10.60 fallback VPC. A terraform_data precondition
fails plan and apply when existing_vpc_id is empty, instead of a check
block that only warns.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
Initialize the SDK on gunicorn and the SQS worker with afterhours-style scrubbing. Store the DSN in SSM and inject only the parameter name onto the live task.
* fix(infra): share the afterhours VPC when existing_vpc_id is set
Prod is at the account VPC quota, so the v1.0.0 apply destroyed Lambda/API Gateway then failed on CreateVpc. Skip creating a sixth VPC when the workspace supplies afterhours subnets.
* style(test): format the VPC terraform assertion for ruff
* feat(api): serve meals on ECS Fargate instead of Lambda
Keep the Flask app always-on with in-process jobs so CloudFront no longer fronts a cold-start API Gateway.
* fix(jobs): run delayed close and reminder deliveries
Wall-clock skip windows dropped the only weekly SQS attempt when Scheduler already fired in Eastern time. Dev schedules stay disabled.
* fix(api): return JSON objects and stop logging job payloads
Flask now jsonify-s handler dicts so API responses are not HTML, and the worker logs only event and status.
* fix(ci): restore the reusable workflow so the required check is named ci / ci
Inlining the job reported `ci` instead of the org ruleset's `ci / ci`.
* fix(secrets): drop unused os import so ruff check passes
* style: apply ruff format so ci-python-app lint passes
* fix(infra): give meals its own VPC because prod has none
* chore(security): re-key ALB SG checkov suppression after vpc.tf
* fix(iam): ignore default tags on hcptf roles (PLAT-210)
The apply role cannot iam:TagRole on itself. Provider default_tags from
the env split 403'd the prod apply on hcptf-meal-order-manager and -plan.
* fix(iam): ignore tags_all on hcptf roles (PLAT-210)
ignore_changes on tags does not cover provider default_tags. The prod
speculative plan still wanted Environment on tags_all and would TagRole.
* feat(infra): add lightweight meal-order-manager-dev (PLAT-210)
Parameterize the HCP root for seahaven-dev with schedules, PITR, alarms, and Paychex gated off so a second env does not clone production cost or side effects.
* fix(infra): drop prod-only authorizer import so dev can create it (PLAT-210)
The PLAT-102 import is already in meal-order-manager-prod state. A shared import block fails in seahaven-dev because the permission does not exist there.
* fix(iam): allow creating the weekly-menu githubdeploy role in seahaven-dev (PLAT-210)
Prod imported that role. A new account needs CreateRole on tf-managed/githubdeploy-meal-order-manager-weekly-menu.
* fix(auth): accept federated portal Cognito tokens for meals admin
Google Workspace federation stores email_verified=false, which 403'd the
portal Admin probe while the public menu still loaded.
* fix(iam): grant plan role CloudFront DescribeFunction
* feat(edge): proxy portal meals API paths on orders.seahaven.com (DEV-282)
Keep the static form on / while CloudFront forwards submit, form-status, admin, and caller-only order lookup so the portal can use the public meals host without a form redirect.
* fix(style): apply ruff format
* chore(meals): remove email_report payroll SES path (PLAT-135)
Stop Monday SES deduction emails now that Flex checkcomponents owns payroll posting.
* chore(meals): delete email_report handler and SAM resources
Remove the leftover SES Lambda source so it cannot be redeployed from template.yaml.
* feat(meals): send weekly deductions to paychex checkcomponents (PLAT-154)
* fix(meals): round checkcomponents amounts half-up
Keep SQS deduction amounts on the same rounding path as submit_order so extra-precision totals cannot diverge by a cent.
* feat(iam): import hcptf roles into app Terraform (PLAT-146)
Move the existing hcptf pair into this repo so app Terraform owns prod IAM after the substrate handoff.
* fix(iam): add apply-role IAM list permissions (PLAT-146)
IamReadOnly omitted ListRoleTags and ListInstanceProfilesForRole needed after detaching the substrate guardrail.