Skip to content

Production Deploy#77

Merged
NickSavino merged 25 commits into
mainfrom
deploy-merge-fix
Mar 29, 2026
Merged

Production Deploy#77
NickSavino merged 25 commits into
mainfrom
deploy-merge-fix

Conversation

@NickSavino

Copy link
Copy Markdown
Contributor

No description provided.

NickSavino and others added 24 commits February 4, 2026 03:35
Syncing main to development
Feat/middleware-wiring-webhook-setup
* added user calibration endpoints and schema"
- Added user_calibration migration
- Added sqlc queries for calibration CRUD operations
- added /api/users/me/calibration endpoints: GET, POST, DELETE
- me endpoint now fetches user from clerk id using middleware, enhancing security
- removed GET methods for user (GET /{id}, GET /)

* Fixed line endings

* Fixed time formatting in handler

* Added NOT NULL constrain to updated_at, created_at in db table

switch go dev container port to correct mapping (8080)

fixed variable typo in middleware_auth.go

---------

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>
Co-authored-by: NicolaSavino <nick.savino@arcurve.com>
* Implemented workout and calibration schema with included sqlc queries. Updated makefile and seeding files

* Regenerated SQLC to match new queries and models (workout type + workout session)

* Added workout session service

* Added Workout Handler Endpoint

* Addressed PR comments
- fixed syntax error in makefile
-  Fixed migration schema
- fixed seeding script
- added /service/helps/helpers.util file
- renamed Dtos to match go standards, (Id -> ID)

* Updated API endpoints

* updated dtos to match casing convention. updated workout_session logic

* Added functionality for workout sets and reps. (services, handlers, migrations, queries)

* Addressed PR comments

* Addressed PR comments

---------

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>
* fix: added clerk webhook secret

* updated CRLF line endings to LF
* fix: added clerk webhook secret

* updated CRLF line endings to LF

* fix
…pment

# Conflicts:
#	scripts/ci/deploy_via_ssm.sh
* Prod fix (#67)

* Small changes to dev tooling (docker/make/compose

* Server: minor variable rename

* Auth middleware + clerk webhook handler

* Added WithTransaction to store

* Removed debug logging message exposing userid

* Removed docker-compose changes not relevant to PR

* Renamed users.go to users.handler.go in handlers

* Added documentation explaining dev bypass

* Feat/calibration-endpoints (#57)

* added user calibration endpoints and schema"
- Added user_calibration migration
- Added sqlc queries for calibration CRUD operations
- added /api/users/me/calibration endpoints: GET, POST, DELETE
- me endpoint now fetches user from clerk id using middleware, enhancing security
- removed GET methods for user (GET /{id}, GET /)

* Fixed line endings

* Fixed time formatting in handler

* Added NOT NULL constrain to updated_at, created_at in db table

switch go dev container port to correct mapping (8080)

fixed variable typo in middleware_auth.go

---------

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>

* Fixed syntax error on migration (#58)

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>

* Feat/workouts api (#59)

* Implemented workout and calibration schema with included sqlc queries. Updated makefile and seeding files

* Regenerated SQLC to match new queries and models (workout type + workout session)

* Added workout session service

* Added Workout Handler Endpoint

* Addressed PR comments
- fixed syntax error in makefile
-  Fixed migration schema
- fixed seeding script
- added /service/helps/helpers.util file
- renamed Dtos to match go standards, (Id -> ID)

* Updated API endpoints

* updated dtos to match casing convention. updated workout_session logic

* Added functionality for workout sets and reps. (services, handlers, migrations, queries)

* Addressed PR comments

* Addressed PR comments

---------

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>

* fix: added clerk webhook secret (#62)

* Fix/add clerkwebhook secret (#64)

* fix: added clerk webhook secret

* updated CRLF line endings to LF

* Fix/add clerkwebhook secret (#66)

* fix: added clerk webhook secret

* updated CRLF line endings to LF

* fix

---------

Co-authored-by: NicolaSavino <nick.savino@arcurve.com>

* fix: wipe data on seed

---------

Co-authored-by: Nicola Savino <77707655+NickSavino@users.noreply.github.com>
Co-authored-by: NicolaSavino <nick.savino@arcurve.com>
- updated workout session history endpoint
- added reset_workflow script along with github action
- added ingestion functionality for webhook
* feat: setup AWS Cloudwatch resource and updated deploy script to attach to logging
* Increaed EC2 Tier and added elastic ip

* added newline to EOF
* Added Logging Middleware to increase observability

* small rename

* Refactored user handler logic to be executed in service

* Updated logging.go to adress bot comments

* Updated logging middleware to forward optional http.ResponseWriter interfaces
@qodo-code-review

Copy link
Copy Markdown
ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Refactor user service, add logging middleware, and enhance infrastructure

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Refactored user service with DTOs and calibration endpoints
• Added user deletion webhook handler for Clerk integration
• Enhanced workout session history with aggregated sets/reps counts
• Implemented HTTP request logging middleware for observability
• Added CloudWatch logging infrastructure and database reset workflow
• Fixed line endings and formatting across infrastructure files
Diagram
flowchart LR
  A["User Service"] -->|DTOs| B["Handler Layer"]
  C["Clerk Webhook"] -->|user.deleted| D["Delete User Handler"]
  E["Workout Session"] -->|Aggregation| F["History with Stats"]
  G["HTTP Requests"] -->|LoggingMiddleware| H["CloudWatch Logs"]
  I["Infrastructure"] -->|Logs Module| J["CloudWatch Log Group"]
Loading

Grey Divider

File Changes

1. internal/core/service/user.service.go ✨ Enhancement +173/-48

Added DTOs and calibration management functions

internal/core/service/user.service.go


2. internal/core/service/workout/workout_session.service.go ✨ Enhancement +38/-2

Added history DTO with aggregated stats

internal/core/service/workout/workout_session.service.go


3. internal/db/users.sql.go ✨ Enhancement +9/-0

Added DeleteUserByClerkID query function

internal/db/users.sql.go


View more (27)
4. internal/db/workout_session.sql.go ✨ Enhancement +33/-33

Updated history query with sets/reps aggregation

internal/db/workout_session.sql.go


5. internal/http/handlers/auth.handler.go ✨ Enhancement +7/-1

Added user.deleted webhook event handler

internal/http/handlers/auth.handler.go


6. internal/http/handlers/health.handler.go 🐞 Bug fix +0/-2

Removed debug logging from health check

internal/http/handlers/health.handler.go


7. internal/http/handlers/users.handler.go ✨ Enhancement +11/-84

Refactored to use service layer DTOs

internal/http/handlers/users.handler.go


8. internal/http/middleware/logging.go ✨ Enhancement +142/-0

New HTTP request logging middleware

internal/http/middleware/logging.go


9. internal/http/router.go ✨ Enhancement +1/-1

Integrated logging middleware into router

internal/http/router.go


10. scripts/ci/deploy_via_ssm.sh ✨ Enhancement +40/-37

Added CloudWatch logging configuration

scripts/ci/deploy_via_ssm.sh


11. scripts/ci/reset_database.sh ✨ Enhancement +28/-0

New database reset script for migrations

scripts/ci/reset_database.sh


12. .gitattributes ⚙️ Configuration changes +1/-0

Added line ending normalization for shell scripts

.gitattributes


13. .github/workflows/deploy.yml ⚙️ Configuration changes +84/-83

Added LOG_GROUP_NAME environment variable

.github/workflows/deploy.yml


14. .github/workflows/reset-database.yml ✨ Enhancement +37/-0

New manual database reset workflow

.github/workflows/reset-database.yml


15. db/queries/users.sql ✨ Enhancement +3/-0

Added DeleteUserByClerkID query

db/queries/users.sql


16. db/queries/workout_session.sql ✨ Enhancement +16/-8

Updated history query with aggregations

db/queries/workout_session.sql


17. db/seeds/seed.sql ✨ Enhancement +6/-0

Added table truncation for clean seeding

db/seeds/seed.sql


18. infra/env/prod/.terraform.lock.hcl Dependencies +0/-33

Removed unused provider dependencies

infra/env/prod/.terraform.lock.hcl


19. infra/env/prod/main.tf ✨ Enhancement +17/-2

Added logs module and infrastructure variables

infra/env/prod/main.tf


20. infra/env/prod/variables.tf ✨ Enhancement +15/-1

Added AMI and instance type variables

infra/env/prod/variables.tf


21. infra/modules/compute/main.tf ✨ Enhancement +14/-18

Replaced AMI lookup with variable, added EIP

infra/modules/compute/main.tf


22. infra/modules/compute/outputs.tf ✨ Enhancement +10/-10

Updated public IP to use EIP allocation

infra/modules/compute/outputs.tf


23. infra/modules/compute/variables.tf ✨ Enhancement +5/-1

Added ami_id variable parameter

infra/modules/compute/variables.tf


24. infra/modules/logs/main.tf ✨ Enhancement +31/-0

New CloudWatch logs module for API logging

infra/modules/logs/main.tf


25. infra/modules/logs/outputs.tf ✨ Enhancement +7/-0

Log group name and ARN outputs

infra/modules/logs/outputs.tf


26. infra/modules/logs/variables.tf ✨ Enhancement +18/-0

Log retention and role configuration variables

infra/modules/logs/variables.tf


27. infra/modules/network/main.tf Formatting +206/-206

Fixed formatting and line endings

infra/modules/network/main.tf


28. infra/modules/network/variables.tf Formatting +42/-42

Fixed formatting and line endings

infra/modules/network/variables.tf


29. infra/modules/rds/main.tf Formatting +77/-77

Fixed formatting and line endings

infra/modules/rds/main.tf


30. infra/modules/github_oidc/main.tf Formatting +182/-182

Fixed formatting and line endings

infra/modules/github_oidc/main.tf


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 29, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Wrong created_at mapping 🐞 Bug ✓ Correctness
Description
dtoFromUserRow sets UserProfileDTO.CreatedAt from row.UpdatedAt and only when
UpdatedAt.Valid, so the /me response can return an empty or incorrect created_at (often
mirroring updated_at).
Code

internal/core/service/user.service.go[R59-68]

+func dtoFromUserRow(row sqlc.User) UserProfileDTO {
+	created := ""
+	if row.UpdatedAt.Valid {
+		created = row.UpdatedAt.Time.Format(time.RFC3339)
+	}
+
+	updated := ""
+	if row.UpdatedAt.Valid {
+		updated = row.UpdatedAt.Time.Format(time.RFC3339)
+	}
Evidence
The DTO builder uses row.UpdatedAt for both created and updated. The underlying sqlc model has
distinct CreatedAt and UpdatedAt fields, so this mapping is incorrect and can produce empty
created_at when updated_at is NULL/invalid.

internal/core/service/user.service.go[59-78]
internal/db/models.go[11-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`dtoFromUserRow` populates the `created_at` DTO field from `UpdatedAt`, which returns incorrect timestamps to clients and may produce an empty `created_at` value.

### Issue Context
The sqlc-generated `User` model includes both `CreatedAt` and `UpdatedAt`.

### Fix Focus Areas
- internal/core/service/user.service.go[59-78]
- internal/db/models.go[11-20]

### Suggested fix
- Change the `created` calculation to use `row.CreatedAt` (and `row.CreatedAt.Valid`) instead of `row.UpdatedAt`.
- Keep `updated` derived from `row.UpdatedAt`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Prod DB reset exposed 🐞 Bug ⛨ Security
Description
The new workflow_dispatch "Reset Database" job can run a destructive goose reset against a
hardcoded production DB URL path with only a string-confirmation gate, increasing the risk of
accidental production data loss.
Code

.github/workflows/reset-database.yml[R11-37]

+jobs:
+  reset-database:
+    if: ${{ inputs.confirm_reset == 'RESET' && github.ref == 'refs/heads/main'}}
+    runs-on: ubuntu-latest
+
+    permissions:
+      id-token: write
+      contents: read
+    
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - name: Configure AWS credentials with OIDC
+        uses: aws-actions/configure-aws-credentials@v4
+        with:
+          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
+          aws-region: ${{ secrets.AWS_REGION }}
+      
+      - name: Run database reset
+        env:
+          AWS_REGION: ${{ secrets.AWS_REGION }}
+          ECR_REPO: ${{ secrets.ECR_REPO }}
+          EC2_INSTANCE_ID: ${{ secrets.EC2_INSTANCE_ID }}
+          GITHUB_SHA: ${{ github.sha }}
+        run: |
+          bash ./scripts/ci/reset_database.sh
Evidence
The workflow is manually dispatchable and, when confirm_reset == 'RESET' on main, executes
scripts/ci/reset_database.sh. That script fetches /cgc-2026-prod/api/database_url and runs
goose ... reset followed by up, which is inherently destructive.

.github/workflows/reset-database.yml[1-37]
scripts/ci/reset_database.sh[12-24]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
A manually-triggered GitHub Action performs a production database reset (goose `reset`) with minimal in-workflow safety controls.

### Issue Context
The reset script is hardwired to `/cgc-2026-prod/api/database_url` and runs `reset` + `up` via SSM.

### Fix Focus Areas
- .github/workflows/reset-database.yml[1-37]
- scripts/ci/reset_database.sh[12-24]

### Suggested fix
- Add an `environment: production` to the job and rely on protected environment approvals.
- Add an explicit allowlist check for `github.actor` (or require a second confirmation input that is not easily guessable/replayed).
- Avoid hardcoding the production SSM parameter name in the script; pass it as a protected secret/variable or workflow input and validate it.
- Consider using a dedicated, tightly-scoped IAM role for resets (separate from deploy), so even authorized deployers can’t reset without explicit access.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@NickSavino
NickSavino merged commit 5c36b75 into main Mar 29, 2026
Comment on lines +59 to +68
func dtoFromUserRow(row sqlc.User) UserProfileDTO {
created := ""
if row.UpdatedAt.Valid {
created = row.UpdatedAt.Time.Format(time.RFC3339)
}

updated := ""
if row.UpdatedAt.Valid {
updated = row.UpdatedAt.Time.Format(time.RFC3339)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Wrong created_at mapping 🐞 Bug ✓ Correctness

dtoFromUserRow sets UserProfileDTO.CreatedAt from row.UpdatedAt and only when
UpdatedAt.Valid, so the /me response can return an empty or incorrect created_at (often
mirroring updated_at).
Agent Prompt
### Issue description
`dtoFromUserRow` populates the `created_at` DTO field from `UpdatedAt`, which returns incorrect timestamps to clients and may produce an empty `created_at` value.

### Issue Context
The sqlc-generated `User` model includes both `CreatedAt` and `UpdatedAt`.

### Fix Focus Areas
- internal/core/service/user.service.go[59-78]
- internal/db/models.go[11-20]

### Suggested fix
- Change the `created` calculation to use `row.CreatedAt` (and `row.CreatedAt.Valid`) instead of `row.UpdatedAt`.
- Keep `updated` derived from `row.UpdatedAt`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants