Skip to content

Add Trip Dates#245

Open
aahiltn wants to merge 3 commits intomainfrom
aahil/add-trip-dates
Open

Add Trip Dates#245
aahiltn wants to merge 3 commits intomainfrom
aahil/add-trip-dates

Conversation

@aahiltn
Copy link
Copy Markdown
Contributor

@aahiltn aahiltn commented Apr 2, 2026

Description

Required for differentiation between past and upcoming trips. Also a part of the onboarding Figma.

How has this been tested?

Checklist

  • I have self-reviewed my code for readability, maintainability, performance, and added comments/documentation where necessary.
  • New and existing tests pass locally with my changes.
  • I have followed the project's coding standards and best practices.
  • Adds optional start_date and end_date to trips (DB, backend models, repo, services, API, frontend types/schemas) and validates end_date > start_date when both set.
  • Persists and returns trip dates in list/detail endpoints; omitting dates leaves fields out of responses.
  • Adds integration tests covering create/retrieve/list/update happy paths, validation failure when end_date < start_date, and omission behavior.
  • Regenerates OpenAPI/Swagger and frontend schemas/types; also documents activity time_of_day and new comment-reaction API surface (unrelated feature included in same changeset).

Features

  • DB migration: nullable DATE columns trips.start_date, trips.end_date; composite index idx_trips_dates(start_date, end_date).
  • Backend models: Trip, CreateTripRequest, UpdateTripRequest, TripDatabaseResponse, TripAPIResponse include StartDate/EndDate.
  • Repository: SELECT and UPDATE queries read/persist start_date/end_date; UPDATE conditionally sets when provided.
  • Services: CreateTrip and UpdateTrip validate end_date is after start_date and persist dates.
  • Tests: integration tests exercising create/get/list/update, validation failures, and omission behavior.
  • Frontend: updated/generated TypeScript types and Zod schemas to include start_date/end_date; OpenAPI/Swagger updated to expose new fields.
  • Additional unrelated API additions in this PR: activity.time_of_day enum and comment-reactions endpoints/schemas/hooks.

Improvements

  • Composite index on (start_date, end_date) to optimize date-based queries.
  • Extended activity listing to support optional date and time_of_day filters (docs/types).

Infra

  • Swagger/OpenAPI doc updates and regenerated frontend schema/type artifacts.

Author Contribution

Component Added Removed Net
Backend (migrations, models, repository, services, tests) 197 10 +187
Frontend (types, schemas, API surface) 378 18 +360
API Documentation (docs.go, swagger.json/yaml) 436 1 +435
Total 1,011 29 +982

aahiltn and others added 2 commits April 1, 2026 21:05
Adds optional trip date range support across the full backend stack:
- Migration: adds start_date/end_date DATE columns with composite index
- Models: Trip, TripAPIResponse, TripDatabaseResponse, CreateTripRequest, UpdateTripRequest
- Repository: includes date columns in SELECT queries and UPDATE handler
- Service: maps dates through create/update/get paths with end > start validation

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Runs kubb to regenerate TypeScript types, Zod schemas, and React Query
hooks reflecting the new start_date and end_date fields on TripAPIResponse.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

This PR adds comment-reaction API schemas and frontend types/hooks, introduces trip start_date/end_date (DB migration, models, repo, service, tests), and adds activity time_of_day plus optional date/time filters for activity listing. API docs and generated types/schemas are updated accordingly.

Changes

Cohort / File(s) Summary
Backend Swagger / Docs
backend/docs/docs.go, backend/docs/swagger.json, backend/docs/swagger.yaml
Added comment-reaction endpoints and models. Added time_of_day enum and date query param for trip activities. Added start_date/end_date to trip schemas.
Database Migration
backend/internal/migrations/20260401000000_add_trip_dates.sql
Add nullable start_date and end_date to trips and composite index idx_trips_dates.
Backend Models
backend/internal/models/trips.go
Added StartDate/EndDate fields to Trip, Create/Update requests, DB/API responses.
Backend Repository & Service
backend/internal/repository/trips.go, backend/internal/services/trips.go
Select and conditionally update date columns in repo queries. Service-level validation rejecting end_date <= start_date; persist dates on create/update and include in API mapping.
Backend Tests
backend/internal/tests/trips_test.go
New tests covering create/list/get/update behavior and validation for trip start/end dates.
Frontend API Re-exports
frontend/api/index.ts, frontend/index.ts
Re-export new comment-reaction hooks, keys, and options (add/remove/get summary/get users + suspense variants).
Frontend Hooks JSDoc
frontend/api/activities/useGetActivitiesByTripID.ts, frontend/api/activities/useGetActivitiesByTripIDSuspense.ts
Updated docstrings to include filtering by time_of_day and date (no runtime changes).
Frontend JSON Schemas — Activity
frontend/schemas/modelsActivity*.json, frontend/schemas/modelsActivityTimeOfDay.json, frontend/schemas/modelsCreateActivityRequest.json, frontend/schemas/modelsSearchActivitiesResult.json, frontend/schemas/modelsUpdateActivityRequest.json
Added time_of_day enum (morning
Frontend JSON Schemas — Trip
frontend/schemas/modelsCreateTripRequest.json, frontend/schemas/modelsTrip*.json, frontend/schemas/modelsSearchTripsResult.json, frontend/schemas/modelsTripCursorPageResult.json, frontend/schemas/modelsTripAPIResponse.json, frontend/schemas/modelsUpdateTripRequest.json
Added start_date and end_date string fields to trip-related schemas.
Frontend JSON Schemas — Comment Reactions
frontend/schemas/modelsCommentReaction*.json, frontend/schemas/modelsCreateCommentReactionRequest.json, frontend/schemas/modelsDeleteCommentReactionRequest.json, frontend/schemas/modelsCommentReactionUsersResponse.json, frontend/schemas/modelsCommentReactionsSummaryResponse.json
Added schemas for CommentReaction, CommentReactionSummary, CommentReactionUser, Create/Delete requests, users response, and reactions summary response.
Frontend Generated Types / Zod Schemas
frontend/types/schema.gen.ts, frontend/types/types.gen.ts
Regenerated types and Zod schemas: added time_of_day enum and fields on activity types; added start_date/end_date to trip types; added all comment-reaction request/response/query/mutation types and schemas; extended getActivitiesByTripID query params with time_of_day and date.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • in-mai-space

Dates marked on maps and plans align,
Emoji reactions tally and shine,
Morning, afternoon, evening sign—
Schemas, types, and docs combine.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Trip Dates' directly and clearly describes the main change in the pull request, which introduces start_date and end_date fields to the Trip model across backend and frontend layers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aahil/add-trip-dates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Covers happy paths (create/get/list/update with dates), validation
(end before start rejected on both create and update), and the
no-dates case (fields omitted from response when not set).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@aahiltn aahiltn requested a review from Bartavius April 2, 2026 01:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/docs/swagger.json (1)

1593-1627: ⚠️ Potential issue | 🟠 Major

Add format: date to date-typed fields in Go struct annotations.

The date query parameter, start_date, and end_date fields in Trip and related models are missing the format: "date" specification in the generated swagger.json. Add the format tag to the Go struct field annotations (consistent with DateRange's existing pattern) so swag generates the proper OpenAPI schema with type: "string" and format: "date".

Affected locations
  • Lines 1593-1627: date query parameter in getActivitiesByTripID
  • Lines 6099-6107, 7183-7194, 7218-7229, 7435-7443: start_date and end_date fields in model definitions
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/docs/swagger.json` around lines 1593 - 1627, The OpenAPI schema is
missing the date format for date-typed fields; update the Go struct field
annotations and operation param docs to include format:"date" for the relevant
fields: add the format tag for the query parameter named "date" in the
getActivitiesByTripID handler docs, and add format:"date" to the struct tags for
start_date and end_date on the Trip and related models (e.g., the Trip struct
and DateRange-related structs referenced in swagger generation) so swag
generates type: "string" with format: "date".
frontend/types/schema.gen.ts (1)

1128-1136: ⚠️ Potential issue | 🟠 Major

Add format: date annotation to trip date fields in the upstream OpenAPI specification.

The start_date and end_date fields in CreateTripRequest and related trip schemas are currently defined as plain strings in the OpenAPI spec, but they should use format: date to enforce ISO 8601 date validation. This matches the Go backend models which use time.Time and the pattern already established elsewhere in the spec. Without this annotation, the generated frontend schemas accept invalid dates like 2026-13-40, and the TypeScript types lack proper date validation.

Update backend/docs/swagger.json and backend/docs/swagger.yaml to add format: date to these fields, then regenerate the frontend types.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/types/schema.gen.ts` around lines 1128 - 1136, The generated schema
modelsCreateTripRequestSchema allows invalid dates because start_date and
end_date are plain strings in the OpenAPI spec; update the upstream OpenAPI
definitions for CreateTripRequest (and any related trip schemas) in
backend/docs/swagger.json and backend/docs/swagger.yaml to add "format": "date"
for the start_date and end_date properties (matching the Go time.Time usage),
then regenerate the frontend types so modelsCreateTripRequestSchema (and related
schemas) use zod date-format validation; ensure the CreateTripRequest schema
name and the start_date/end_date property keys are updated consistently in both
JSON and YAML before running the typegen.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/docs/docs.go`:
- Around line 1628-1633: Add explicit "format: date" metadata to all date fields
and the query param so the OpenAPI spec marks them as dates: update the
struct/annotation definitions for models.CreateTripRequest.start_date,
models.CreateTripRequest.end_date, models.UpdateTripRequest.start_date,
models.UpdateTripRequest.end_date, models.Trip.start_date, models.Trip.end_date,
models.TripAPIResponse.start_date, models.TripAPIResponse.end_date to include
the OpenAPI format=date (e.g., via your project's Swagger/swag annotations or
struct tags for format) and update the handler/doc annotation for the
/api/v1/trips/{tripID}/activities query parameter named "date" to include
format: date; then regenerate the docs so the generated OpenAPI JSON/YAML
includes "type: string" and "format: date" for these fields.

In `@backend/docs/swagger.json`:
- Around line 195-451: The swagger docs are missing security declarations
because the handler comment blocks in
backend/internal/controllers/comment_reactions.go for AddReaction,
RemoveReaction, GetReactionSummary, and GetReactionUsers need an `@Security`
BearerAuth annotation; update each function's top-of-function swag comment (the
block that contains `@Summary/`@Description/@Router) to include a line "@Security
BearerAuth" so swag will generate the BearerAuth security requirement for those
endpoints.

In `@backend/docs/swagger.yaml`:
- Around line 570-576: The Trip schema fields start_date and end_date are
declared as type: string but lack a date format; update models.Trip,
models.TripAPIResponse, and models.UpdateTripRequest to mirror models.DateRange
by adding format: date (and optional example values) to both start_date and
end_date so API consumers know the expected YYYY-MM-DD date format; locate the
definitions for models.Trip, models.TripAPIResponse, and
models.UpdateTripRequest and add format: date under each start_date/end_date
entry (and add example: "2023-05-01" if desired) for consistency.

In `@backend/internal/migrations/20260401000000_add_trip_dates.sql`:
- Around line 2-4: Add a schema-level CHECK constraint to the ALTER TABLE
statement on trips to prevent invalid ranges; modify the migration that adds
start_date and end_date to also add a named constraint (e.g.,
trips_end_after_start_chk) such as CHECK (start_date IS NULL OR end_date IS NULL
OR end_date > start_date) so rows with both dates present must satisfy end_date
> start_date while allowing NULLs during migration.

In `@backend/internal/models/trips.go`:
- Around line 16-17: Replace the pointer time.Time fields StartDate and EndDate
in the Trips model with a custom Date type (e.g., type Date struct) that
serializes to/from "YYYY-MM-DD" for JSON and avoids timezone shifts; implement
json.Marshaler and json.Unmarshaler on that Date to emit/parse ISO date-only
strings, and also implement sql.Scanner and driver.Valuer so Bun can read/write
the DATE column; update all usages (StartDate, EndDate and any other trip/date
fields called out) to use *Date instead of *time.Time, matching the DateRange
string-style precedent in activity.go.

In `@backend/internal/services/trips.go`:
- Around line 230-232: The current validation only compares req.StartDate and
req.EndDate when both are present, so partial updates can break ordering; before
that check in trips.go, load the existing trip (e.g., via the service/repo
method used elsewhere such as GetByID/GetTrip) and merge current values with the
incoming request values (use existingTrip.StartDate/EndDate when req.StartDate
or req.EndDate is nil) and then validate that mergedStart and mergedEnd satisfy
mergedEnd.After(mergedStart); update the code paths that return errs.BadRequest
to use the merged dates so partial updates cannot produce end_date < start_date.

In `@frontend/schemas/modelsCommentReactionUser.json`:
- Line 4: The JSON schema for profile_picture_url currently requires a string
but the backend model uses a pointer (*string) allowing null; update the schema
entry for "profile_picture_url" in
frontend/schemas/modelsCommentReactionUser.json to accept nulls (e.g., make the
type allow "null" or set nullable true) so it matches
backend/internal/models/comment_reactions.go's *string behavior and prevents
validation errors from null API responses.

In `@frontend/schemas/modelsCreateActivityRequest.json`:
- Around line 45-59: Remove the redundant allOf wrapper and duplicated enum in
the time_of_day property: replace the current object that nests type/enum inside
allOf with a single schema entry that directly defines "type": "string", the
"enum": ["morning","afternoon","evening"], and the
x-enum-varnames/x-readme-ref-name metadata; apply the same change to the
corresponding time_of_day field in modelsUpdateActivityRequest.json so both
request schemas match the simpler pattern used by modelsActivity.json,
modelsActivityAPIResponse.json, modelsSearchActivitiesResult.json, and
modelsActivityCursorPageResult.json.

In `@frontend/schemas/modelsCreateTripRequest.json`:
- Around line 9-11: Update the JSON schema for trip date fields so they validate
ISO dates: modify the "start_date" and "end_date" properties in
modelsCreateTripRequest.json to include "format": "date" in addition to "type":
"string" (e.g., keep the "name" constraints unchanged) so the schema enforces
ISO date format validation for those fields.

---

Outside diff comments:
In `@backend/docs/swagger.json`:
- Around line 1593-1627: The OpenAPI schema is missing the date format for
date-typed fields; update the Go struct field annotations and operation param
docs to include format:"date" for the relevant fields: add the format tag for
the query parameter named "date" in the getActivitiesByTripID handler docs, and
add format:"date" to the struct tags for start_date and end_date on the Trip and
related models (e.g., the Trip struct and DateRange-related structs referenced
in swagger generation) so swag generates type: "string" with format: "date".

In `@frontend/types/schema.gen.ts`:
- Around line 1128-1136: The generated schema modelsCreateTripRequestSchema
allows invalid dates because start_date and end_date are plain strings in the
OpenAPI spec; update the upstream OpenAPI definitions for CreateTripRequest (and
any related trip schemas) in backend/docs/swagger.json and
backend/docs/swagger.yaml to add "format": "date" for the start_date and
end_date properties (matching the Go time.Time usage), then regenerate the
frontend types so modelsCreateTripRequestSchema (and related schemas) use zod
date-format validation; ensure the CreateTripRequest schema name and the
start_date/end_date property keys are updated consistently in both JSON and YAML
before running the typegen.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 224aa54e-55d3-46cf-bc4e-ca95a5293773

📥 Commits

Reviewing files that changed from the base of the PR and between e0ed34a and ac18440.

📒 Files selected for processing (33)
  • backend/docs/docs.go
  • backend/docs/swagger.json
  • backend/docs/swagger.yaml
  • backend/internal/migrations/20260401000000_add_trip_dates.sql
  • backend/internal/models/trips.go
  • backend/internal/repository/trips.go
  • backend/internal/services/trips.go
  • frontend/api/activities/useGetActivitiesByTripID.ts
  • frontend/api/activities/useGetActivitiesByTripIDSuspense.ts
  • frontend/api/index.ts
  • frontend/index.ts
  • frontend/schemas/modelsActivity.json
  • frontend/schemas/modelsActivityAPIResponse.json
  • frontend/schemas/modelsActivityCursorPageResult.json
  • frontend/schemas/modelsActivityTimeOfDay.json
  • frontend/schemas/modelsCommentReaction.json
  • frontend/schemas/modelsCommentReactionSummary.json
  • frontend/schemas/modelsCommentReactionUser.json
  • frontend/schemas/modelsCommentReactionUsersResponse.json
  • frontend/schemas/modelsCommentReactionsSummaryResponse.json
  • frontend/schemas/modelsCreateActivityRequest.json
  • frontend/schemas/modelsCreateCommentReactionRequest.json
  • frontend/schemas/modelsCreateTripRequest.json
  • frontend/schemas/modelsDeleteCommentReactionRequest.json
  • frontend/schemas/modelsSearchActivitiesResult.json
  • frontend/schemas/modelsSearchTripsResult.json
  • frontend/schemas/modelsTrip.json
  • frontend/schemas/modelsTripAPIResponse.json
  • frontend/schemas/modelsTripCursorPageResult.json
  • frontend/schemas/modelsUpdateActivityRequest.json
  • frontend/schemas/modelsUpdateTripRequest.json
  • frontend/types/schema.gen.ts
  • frontend/types/types.gen.ts

Comment on lines +1628 to +1633
{
"type": "string",
"description": "Filter by calendar date (YYYY-MM-DD); activity must have a date range containing this day",
"name": "date",
"in": "query"
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether generated swagger marks trip/date filters as date-formatted.
python - <<'PY'
import json
from pathlib import Path

p = Path("backend/docs/swagger.json")
if not p.exists():
    print("backend/docs/swagger.json not found")
    raise SystemExit(0)

doc = json.loads(p.read_text())
checks = [
    ("definitions", "models.CreateTripRequest", "start_date"),
    ("definitions", "models.CreateTripRequest", "end_date"),
    ("definitions", "models.UpdateTripRequest", "start_date"),
    ("definitions", "models.UpdateTripRequest", "end_date"),
    ("definitions", "models.Trip", "start_date"),
    ("definitions", "models.Trip", "end_date"),
    ("definitions", "models.TripAPIResponse", "start_date"),
    ("definitions", "models.TripAPIResponse", "end_date"),
]

for _, model, field in checks:
    prop = (
        doc.get("definitions", {})
           .get(model, {})
           .get("properties", {})
           .get(field)
    )
    if prop is None:
        print(f"MISSING {model}.{field}")
        continue
    print(f"{model}.{field}: type={prop.get('type')} format={prop.get('format')}")

params = (
    doc.get("paths", {})
       .get("/api/v1/trips/{tripID}/activities", {})
       .get("get", {})
       .get("parameters", [])
)
for prm in params:
    if prm.get("name") == "date":
        print(f"query date param: type={prm.get('type')} format={prm.get('format')}")
PY

Repository: GenerateNU/toggo

Length of output: 551


Add explicit date format to date fields in the OpenAPI specification.

The date-related fields in the API specification lack explicit format metadata. All instances of start_date, end_date, and the date query parameter are documented as plain strings without format: date. This omission weakens the API contract and can cause inconsistencies in SDK generation and client-side validation.

Update the source annotations or models to include format: date for these fields, then regenerate the documentation.

Affected fields:

  • models.CreateTripRequest.start_date
  • models.CreateTripRequest.end_date
  • models.UpdateTripRequest.start_date
  • models.UpdateTripRequest.end_date
  • models.Trip.start_date
  • models.Trip.end_date
  • models.TripAPIResponse.start_date
  • models.TripAPIResponse.end_date
  • /api/v1/trips/{tripID}/activities query parameter date
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/docs/docs.go` around lines 1628 - 1633, Add explicit "format: date"
metadata to all date fields and the query param so the OpenAPI spec marks them
as dates: update the struct/annotation definitions for
models.CreateTripRequest.start_date, models.CreateTripRequest.end_date,
models.UpdateTripRequest.start_date, models.UpdateTripRequest.end_date,
models.Trip.start_date, models.Trip.end_date, models.TripAPIResponse.start_date,
models.TripAPIResponse.end_date to include the OpenAPI format=date (e.g., via
your project's Swagger/swag annotations or struct tags for format) and update
the handler/doc annotation for the /api/v1/trips/{tripID}/activities query
parameter named "date" to include format: date; then regenerate the docs so the
generated OpenAPI JSON/YAML includes "type: string" and "format: date" for these
fields.

Comment on lines +195 to +451
"/api/v1/comments/{commentID}/reactions": {
"get": {
"description": "Retrieves aggregated emoji reactions for a comment",
"produces": [
"application/json"
],
"tags": [
"comment-reactions"
],
"summary": "Get reactions summary for a comment",
"operationId": "getCommentReactionsSummary",
"parameters": [
{
"type": "string",
"description": "Comment ID",
"name": "commentID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.CommentReactionsSummaryResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
}
}
},
"post": {
"description": "Adds an emoji reaction to a comment",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"comment-reactions"
],
"summary": "Add a reaction to a comment",
"operationId": "addCommentReaction",
"parameters": [
{
"type": "string",
"description": "Comment ID",
"name": "commentID",
"in": "path",
"required": true
},
{
"description": "Create reaction request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.CreateCommentReactionRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/models.CommentReaction"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"409": {
"description": "Conflict",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"422": {
"description": "Unprocessable Entity",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
}
}
},
"delete": {
"description": "Removes the current user's emoji reaction from a comment",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"comment-reactions"
],
"summary": "Remove a reaction from a comment",
"operationId": "removeCommentReaction",
"parameters": [
{
"type": "string",
"description": "Comment ID",
"name": "commentID",
"in": "path",
"required": true
},
{
"description": "Delete reaction request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.DeleteCommentReactionRequest"
}
}
],
"responses": {
"204": {
"description": "No Content"
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"422": {
"description": "Unprocessable Entity",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
}
}
}
},
"/api/v1/comments/{commentID}/reactions/{emoji}/users": {
"get": {
"description": "Retrieves users who reacted with a specific emoji on a comment",
"produces": [
"application/json"
],
"tags": [
"comment-reactions"
],
"summary": "Get users who reacted with an emoji",
"operationId": "getCommentReactionUsers",
"parameters": [
{
"type": "string",
"description": "Comment ID",
"name": "commentID",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Emoji (URL-encoded)",
"name": "emoji",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.CommentReactionUsersResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/errs.APIError"
}
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check the comment_reactions controller to verify auth enforcement
fd -t f "comment_reactions.go" backend/

Repository: GenerateNU/toggo

Length of output: 250


🏁 Script executed:

# Search for security declarations in swagger.json
rg '"security"' backend/docs/swagger.json | head -20

Repository: GenerateNU/toggo

Length of output: 149


🏁 Script executed:

# Check if other endpoints use security declarations
rg -A 3 'operationId.*:' backend/docs/swagger.json | grep -A 3 'security' | head -30

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Look for patterns of existing protected endpoints in swagger.json
rg -B 5 '"401"' backend/docs/swagger.json | grep -E '(operationId|security)' | head -40

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Read the comment reactions controller
cat -n backend/internal/controllers/comment_reactions.go | head -100

Repository: GenerateNU/toggo

Length of output: 3892


🏁 Script executed:

# Get more context on security declarations in swagger.json
rg -B 10 '"security"' backend/docs/swagger.json | head -60

Repository: GenerateNU/toggo

Length of output: 1093


🏁 Script executed:

# Search for endpoints that protect with 401 and use security
rg -A 20 'operationId.*Comment' backend/docs/swagger.json | grep -E '(operationId|"security"|"401")' | head -40

Repository: GenerateNU/toggo

Length of output: 515


🏁 Script executed:

# Check a known protected endpoint to see security pattern
rg -B 5 -A 25 'operationId.*:.*createUser' backend/docs/swagger.json

Repository: GenerateNU/toggo

Length of output: 1185


🏁 Script executed:

# Check rest of comment_reactions.go for `@Security` annotations
cat -n backend/internal/controllers/comment_reactions.go | grep -E '(@|func)' | head -30

Repository: GenerateNU/toggo

Length of output: 1807


🏁 Script executed:

# Get the full security block structure and definition in swagger.json
rg -A 5 '"security": \[' backend/docs/swagger.json | head -40

Repository: GenerateNU/toggo

Length of output: 1042


🏁 Script executed:

# Check if BearerAuth is defined in the spec
rg -A 5 'securityDefinitions|BearerAuth|bearer' backend/docs/swagger.json | head -50

Repository: GenerateNU/toggo

Length of output: 1093


🏁 Script executed:

# Look at a comment endpoint that doesn't have reactions to see if it has security
rg -A 30 'operationId.*createComment' backend/docs/swagger.json | head -50

Repository: GenerateNU/toggo

Length of output: 1263


🏁 Script executed:

# Check if createComment in swagger.json has security declaration
rg -B 10 'operationId.*createComment' backend/docs/swagger.json | grep -E '(security|operationId)' | head -10

Repository: GenerateNU/toggo

Length of output: 107


🏁 Script executed:

# Check the RemoveReaction handler to verify auth enforcement
sed -n '92,120p' backend/internal/controllers/comment_reactions.go

Repository: GenerateNU/toggo

Length of output: 761


🏁 Script executed:

# Look for GetCommentReactionsSummary to verify auth there too
rg -A 25 'GetCommentReactionsSummary|getSummary' backend/internal/controllers/comment_reactions.go | head -40

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Find GetCommentReactionsSummary or equivalent in the controller
rg -n 'Summary|Get.*Reaction' backend/internal/controllers/comment_reactions.go | head -20

Repository: GenerateNU/toggo

Length of output: 742


🏁 Script executed:

# Get the full file to see all handlers
wc -l backend/internal/controllers/comment_reactions.go

Repository: GenerateNU/toggo

Length of output: 113


🏁 Script executed:

# Read more of the file to find the summary handler
sed -n '100,180p' backend/internal/controllers/comment_reactions.go

Repository: GenerateNU/toggo

Length of output: 2608


🏁 Script executed:

# Check if createComment handler also enforces auth
rg -A 30 'func.*CreateComment' backend/internal/controllers/comment.go | head -50

Repository: GenerateNU/toggo

Length of output: 139


🏁 Script executed:

# Verify the swagger definitions section has BearerAuth defined
rg -A 10 'securityDefinitions' backend/docs/swagger.json | head -20

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Find the comment controller file
fd -t f 'comment.*\.go' backend/internal/controllers/ | head -10

Repository: GenerateNU/toggo

Length of output: 150


🏁 Script executed:

# Search for createComment in controllers directory
rg -l 'createComment|CreateComment' backend/internal/controllers/

Repository: GenerateNU/toggo

Length of output: 150


🏁 Script executed:

# Check swagger.json for securityDefinitions
rg 'securityDefinitions|swagger|version' backend/docs/swagger.json | head -10

Repository: GenerateNU/toggo

Length of output: 106


🏁 Script executed:

# Check comments.go for CreateComment handler and its `@Security` annotation
rg -A 30 '@Summary.*[Cc]reate.*comment|func.*CreateComment' backend/internal/controllers/comments.go | head -50

Repository: GenerateNU/toggo

Length of output: 1360


🏁 Script executed:

# Check if any handlers in comments.go have `@Security` annotations
rg '@Security' backend/internal/controllers/comments.go

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check comment_reactions.go for `@Security` annotations
rg '@Security' backend/internal/controllers/comment_reactions.go

Repository: GenerateNU/toggo

Length of output: 42


Add @Security BearerAuth annotations to the comment reaction handler functions in the source code.

All three comment reaction handlers (AddReaction, RemoveReaction, GetReactionSummary, GetReactionUsers) enforce authentication by checking c.Locals("userID") and returning 401 when it is absent. However, the swagger annotations lack @Security BearerAuth, so the generated swagger.json does not declare security requirements. This causes Swagger UI and generated API clients to treat these endpoints as public. The fix must be applied to the Go handler comments in backend/internal/controllers/comment_reactions.go where the swag tool will pick up the annotation during code generation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/docs/swagger.json` around lines 195 - 451, The swagger docs are
missing security declarations because the handler comment blocks in
backend/internal/controllers/comment_reactions.go for AddReaction,
RemoveReaction, GetReactionSummary, and GetReactionUsers need an `@Security`
BearerAuth annotation; update each function's top-of-function swag comment (the
block that contains `@Summary/`@Description/@Router) to include a line "@Security
BearerAuth" so swag will generate the BearerAuth security requirement for those
endpoints.

Comment on lines +570 to +576
end_date:
type: string
name:
minLength: 1
type: string
start_date:
type: string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Trip date fields lack format specification.

The start_date and end_date fields are typed as plain string without a format: date annotation. Compare with models.DateRange (lines 596-608) which specifies format: date and includes example values. This inconsistency may confuse API consumers about the expected date format.

Proposed fix
       end_date:
+        description: ISO 8601 date format (YYYY-MM-DD)
+        example: "2024-01-15"
+        format: date
         type: string
       name:
         minLength: 1
         type: string
       start_date:
+        description: ISO 8601 date format (YYYY-MM-DD)
+        example: "2024-01-01"
+        format: date
         type: string

Apply similar changes to models.Trip, models.TripAPIResponse, and models.UpdateTripRequest for consistency.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
end_date:
type: string
name:
minLength: 1
type: string
start_date:
type: string
end_date:
description: ISO 8601 date format (YYYY-MM-DD)
example: "2024-01-15"
format: date
type: string
name:
minLength: 1
type: string
start_date:
description: ISO 8601 date format (YYYY-MM-DD)
example: "2024-01-01"
format: date
type: string
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/docs/swagger.yaml` around lines 570 - 576, The Trip schema fields
start_date and end_date are declared as type: string but lack a date format;
update models.Trip, models.TripAPIResponse, and models.UpdateTripRequest to
mirror models.DateRange by adding format: date (and optional example values) to
both start_date and end_date so API consumers know the expected YYYY-MM-DD date
format; locate the definitions for models.Trip, models.TripAPIResponse, and
models.UpdateTripRequest and add format: date under each start_date/end_date
entry (and add example: "2023-05-01" if desired) for consistency.

Comment on lines +2 to +4
ALTER TABLE trips
ADD COLUMN start_date DATE,
ADD COLUMN end_date DATE;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Apr 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Enforce date-range integrity in the database, not only in service logic.

end_date > start_date is currently not protected at the schema level. Add a CHECK constraint so invalid ranges cannot be inserted outside the service path.

Proposed fix
 ALTER TABLE trips
 ADD COLUMN start_date DATE,
-ADD COLUMN end_date DATE;
+ADD COLUMN end_date DATE,
+ADD CONSTRAINT trips_date_range_check
+  CHECK (start_date IS NULL OR end_date IS NULL OR end_date > start_date);
 
 CREATE INDEX idx_trips_dates ON trips(start_date, end_date);
 
 -- +goose Down
 DROP INDEX IF EXISTS idx_trips_dates;
+ALTER TABLE trips DROP CONSTRAINT IF EXISTS trips_date_range_check;
 ALTER TABLE trips DROP COLUMN IF EXISTS end_date;
 ALTER TABLE trips DROP COLUMN IF EXISTS start_date;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/internal/migrations/20260401000000_add_trip_dates.sql` around lines 2
- 4, Add a schema-level CHECK constraint to the ALTER TABLE statement on trips
to prevent invalid ranges; modify the migration that adds start_date and
end_date to also add a named constraint (e.g., trips_end_after_start_chk) such
as CHECK (start_date IS NULL OR end_date IS NULL OR end_date > start_date) so
rows with both dates present must satisfy end_date > start_date while allowing
NULLs during migration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

meh nah

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@aahiltn, understood. The service-layer validation in trips.go will continue to enforce the date ordering. No changes needed.

Comment on lines +16 to +17
StartDate *time.Time `bun:"start_date" json:"start_date,omitempty"`
EndDate *time.Time `bun:"end_date" json:"end_date,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Go, how does encoding/json marshal time.Time by default, and what is the recommended approach for date-only (YYYY-MM-DD) API fields to avoid timezone day shifts?

💡 Result:

By default, encoding/json marshals time.Time to a quoted string in RFC 3339 format (e.g., "2006-01-02T15:04:05Z" or with nanoseconds and timezone offset if present), via time.Time's MarshalJSON method which uses time.RFC3339Nano but trims trailing zeros in fractional seconds. For date-only (YYYY-MM-DD) API fields, use a custom type wrapping time.Time that implements json.Marshaler and json.Unmarshaler, formatting to/from "2006-01-02" in UTC to avoid timezone-induced day shifts. Example: type Date struct { time.Time } func (d Date) MarshalJSON ([]byte, error) { return json.Marshal(d.Time.UTC.Format("2006-01-02")) } func (d *Date) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err } t, err := time.Parse("2006-01-02", s) if err != nil { return err } d.Time = t return nil } Use as DateField Date json:"date_field" in structs. This ensures consistent date representation regardless of the original time.Time's location, preventing day boundary issues from timezone offsets.

Citations:


🏁 Script executed:

# First, examine the trips.go file to verify the structure at specified lines
head -100 backend/internal/models/trips.go | cat -n

Repository: GenerateNU/toggo

Length of output: 4052


🏁 Script executed:

# Search for any existing date-only types or custom date handling in the codebase
fd -e go . backend --type f --exec rg -l "type.*Date|MarshalJSON|UnmarshalJSON" {} \; | head -20

Repository: GenerateNU/toggo

Length of output: 95


🏁 Script executed:

# Check if there are any custom time-related types already defined
rg "type.*time\.Time" backend --type go -A 2 | head -50

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check the activity.go file for any date-related patterns
cat backend/internal/models/activity.go | grep -A 5 -B 5 "Date\|MarshalJSON\|UnmarshalJSON" | head -40

Repository: GenerateNU/toggo

Length of output: 2032


🏁 Script executed:

# Search more broadly for any custom types that might handle dates
rg "type\s+\w+\s+struct" backend --type go -A 10 | grep -B 5 -A 5 "Date\|time" | head -80

Repository: GenerateNU/toggo

Length of output: 5643


🏁 Script executed:

# Check if there are any custom marshaling implementations in the entire codebase
find backend -name "*.go" -type f -exec rg -l "MarshalJSON|UnmarshalJSON" {} \;

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check the database schema or migrations to understand how dates are stored
find . -name "*.go" -path "*/migrations/*" -o -name "*migration*" | head -10

Repository: GenerateNU/toggo

Length of output: 130


🏁 Script executed:

# Check the migration files to see how dates are stored in the database
ls -la backend/internal/migrations/ | head -20

Repository: GenerateNU/toggo

Length of output: 1644


🏁 Script executed:

# Look at the migration schema for the trips table
rg "trips\|start_date\|end_date" backend/internal/migrations/ --type go -B 3 -A 3 | head -80

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check if there's any custom date handling in the database layer or handlers
rg "StartDate\|EndDate" backend/internal --type go -B 2 -A 2 | grep -v "test\|mock" | head -100

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check the create_trip.sql migration to see the schema
cat backend/internal/migrations/20260123213356_create_trip.sql

Repository: GenerateNU/toggo

Length of output: 999


🏁 Script executed:

# Look for any API handlers or services that use StartDate/EndDate
find backend -name "*.go" -type f -exec grep -l "StartDate\|EndDate" {} \; | grep -v mock | grep -v test

Repository: GenerateNU/toggo

Length of output: 164


🏁 Script executed:

# Check one of the handlers to see how these dates are processed
rg "StartDate|EndDate" backend/internal/handlers --type go -B 5 -A 5 | head -50

Repository: GenerateNU/toggo

Length of output: 125


🏁 Script executed:

# List the backend structure to find where handlers/routes are
ls -la backend/internal/ | grep -v total

Repository: GenerateNU/toggo

Length of output: 1205


🏁 Script executed:

# Search for HTTP handlers or routes that might use StartDate/EndDate
find backend -name "*.go" -type f -exec grep -l "CreateTrip\|UpdateTrip\|POST\|PUT" {} \; | head -10

Repository: GenerateNU/toggo

Length of output: 1151


🏁 Script executed:

# Check the routes file if it exists
find backend -name "*route*" -o -name "*handler*" | head -10

Repository: GenerateNU/toggo

Length of output: 172


🏁 Script executed:

# Look at the trips service to understand how dates are used
head -150 backend/internal/services/trips.go | cat -n

Repository: GenerateNU/toggo

Length of output: 5475


🏁 Script executed:

# Check if there are other migrations that add start_date and end_date to trips
ls -1 backend/internal/migrations/ | xargs -I {} sh -c 'grep -l "start_date\|end_date\|alter.*trips" backend/internal/migrations/{} 2>/dev/null'

Repository: GenerateNU/toggo

Length of output: 123


🏁 Script executed:

# Check the trip repository to see how dates are queried/stored
cat backend/internal/repository/trips.go | head -100

Repository: GenerateNU/toggo

Length of output: 3452


🏁 Script executed:

# Look at the controllers to see how the API returns dates
grep -A 20 "CreateTrip\|UpdateTrip" backend/internal/controllers/trips.go | head -60

Repository: GenerateNU/toggo

Length of output: 1897


🏁 Script executed:

# Check the migration file that adds trip dates
cat backend/internal/migrations/20260401000000_add_trip_dates.sql

Repository: GenerateNU/toggo

Length of output: 362


🏁 Script executed:

# Look for any test files that show how dates are being used/expected
find backend -name "*trip*test*" -o -name "*test*trip*" | head -5

Repository: GenerateNU/toggo

Length of output: 144


🏁 Script executed:

# Check if there's a utility or helper for date handling
rg "date\|Date" backend/internal/utilities --type go -l

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check the trips test file to see how dates are being tested
cat backend/internal/tests/trips_test.go | head -150

Repository: GenerateNU/toggo

Length of output: 3185


🏁 Script executed:

# Search for any JSON marshaling or API tests that show the actual output format
rg "start_date\|end_date" backend/internal/tests --type go -B 3 -A 3 | head -60

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check if there's any documentation or API examples that show expected date format
find . -name "*.md" -o -name "*.yaml" -o -name "*.yml" | xargs grep -l "start_date\|end_date" 2>/dev/null | head -5

Repository: GenerateNU/toggo

Length of output: 87


🏁 Script executed:

# Look at the OpenAPI/Swagger docs if available
head -200 backend/docs/docs.go | grep -A 5 -B 5 "start_date\|end_date"

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check if there are any integration tests or examples that show actual JSON output
find . -name "*.json" -o -name "examples*" | head -10

Repository: GenerateNU/toggo

Length of output: 425


🏁 Script executed:

# Check the swagger documentation for start_date and end_date format
grep -A 10 -B 5 "start_date\|end_date" backend/docs/swagger.yaml | head -60

Repository: GenerateNU/toggo

Length of output: 1141


🏁 Script executed:

# Also check swagger.json
grep -A 5 -B 5 "start_date" backend/docs/swagger.json | head -40

Repository: GenerateNU/toggo

Length of output: 1099


🏁 Script executed:

# Look for DateRange pattern from activity.go in the models again to understand if it's used
rg "DateRange" backend/internal --type go -B 2 -A 5

Repository: GenerateNU/toggo

Length of output: 6909


Use a date-only type for start_date and end_date to prevent timezone day shifts in API responses.

The database schema stores these as DATE type, but the model uses *time.Time. Go's default JSON marshaling converts time.Time to RFC 3339 format (e.g., "2006-01-02T15:04:05Z07:00"), which can shift the calendar day by one due to timezone offset. The codebase already has a precedent for this: the DateRange type in activity.go uses string fields with ISO 8601 date format. Create a custom Date type with json.Marshaler and json.Unmarshaler implementations to serialize/deserialize as "YYYY-MM-DD" in UTC.

Affects lines 16-17, 28-29, 38-39, 68-69, 81-82.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/internal/models/trips.go` around lines 16 - 17, Replace the pointer
time.Time fields StartDate and EndDate in the Trips model with a custom Date
type (e.g., type Date struct) that serializes to/from "YYYY-MM-DD" for JSON and
avoids timezone shifts; implement json.Marshaler and json.Unmarshaler on that
Date to emit/parse ISO date-only strings, and also implement sql.Scanner and
driver.Valuer so Bun can read/write the DATE column; update all usages
(StartDate, EndDate and any other trip/date fields called out) to use *Date
instead of *time.Time, matching the DateRange string-style precedent in
activity.go.

Comment on lines +230 to +232
if req.StartDate != nil && req.EndDate != nil && !req.EndDate.After(*req.StartDate) {
return nil, errs.BadRequest(errors.New("end date must be after start date"))
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Partial update may violate date ordering constraint.

This validation only checks when both StartDate and EndDate are provided in the update request. A partial update could set end_date before an existing start_date (or vice versa) because the service does not fetch the current trip values to cross-validate.

Example: Trip has start_date=2026-04-10. User sends end_date=2026-04-05. Validation passes since req.StartDate is nil, resulting in end_date < start_date in the database.

Proposed fix

Fetch the existing trip before validation and merge with request values:

+	// Fetch existing trip for cross-validation of partial updates
+	existingTrip, err := s.Trip.Find(ctx, tripID)
+	if err != nil {
+		return nil, err
+	}
+
+	effectiveStartDate := existingTrip.StartDate
+	if req.StartDate != nil {
+		effectiveStartDate = req.StartDate
+	}
+	effectiveEndDate := existingTrip.EndDate
+	if req.EndDate != nil {
+		effectiveEndDate = req.EndDate
+	}
+
+	if effectiveStartDate != nil && effectiveEndDate != nil && !effectiveEndDate.After(*effectiveStartDate) {
-	if req.StartDate != nil && req.EndDate != nil && !req.EndDate.After(*req.StartDate) {
		return nil, errs.BadRequest(errors.New("end date must be after start date"))
	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/internal/services/trips.go` around lines 230 - 232, The current
validation only compares req.StartDate and req.EndDate when both are present, so
partial updates can break ordering; before that check in trips.go, load the
existing trip (e.g., via the service/repo method used elsewhere such as
GetByID/GetTrip) and merge current values with the incoming request values (use
existingTrip.StartDate/EndDate when req.StartDate or req.EndDate is nil) and
then validate that mergedStart and mergedEnd satisfy
mergedEnd.After(mergedStart); update the code paths that return errs.BadRequest
to use the merged dates so partial updates cannot produce end_date < start_date.

{
"type": "object",
"properties": {
"profile_picture_url": { "type": "string" },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Allow profile_picture_url to be nullable to match backend responses.

Line 4 currently requires a string, but backend/internal/models/comment_reactions.go uses *string for profile_picture_url. A null value from the API will violate this schema.

Proposed fix
-    "profile_picture_url": { "type": "string" },
+    "profile_picture_url": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"profile_picture_url": { "type": "string" },
"profile_picture_url": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/schemas/modelsCommentReactionUser.json` at line 4, The JSON schema
for profile_picture_url currently requires a string but the backend model uses a
pointer (*string) allowing null; update the schema entry for
"profile_picture_url" in frontend/schemas/modelsCommentReactionUser.json to
accept nulls (e.g., make the type allow "null" or set nullable true) so it
matches backend/internal/models/comment_reactions.go's *string behavior and
prevents validation errors from null API responses.

Comment on lines +45 to +59
"time_of_day": {
"enum": ["morning", "afternoon", "evening"],
"allOf": [
{
"type": "string",
"enum": ["morning", "afternoon", "evening"],
"x-enum-varnames": [
"ActivityTimeOfDayMorning",
"ActivityTimeOfDayAfternoon",
"ActivityTimeOfDayEvening"
],
"x-readme-ref-name": "models.ActivityTimeOfDay"
}
]
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if other activity request schemas use the same allOf pattern
fd -e json . frontend/schemas | xargs grep -l "time_of_day" | xargs grep -l "allOf" 2>/dev/null || echo "No other schemas use allOf for time_of_day"

# Compare structure in update request schema
cat frontend/schemas/modelsUpdateActivityRequest.json 2>/dev/null | grep -A 15 "time_of_day" || echo "modelsUpdateActivityRequest.json not found or no time_of_day field"

Repository: GenerateNU/toggo

Length of output: 593


🏁 Script executed:

#!/bin/bash
# Check the time_of_day structure in modelsActivity.json
echo "=== modelsActivity.json time_of_day ==="
fd -e json -name "modelsActivity.json" frontend/schemas -exec cat {} \; 2>/dev/null | grep -A 15 "time_of_day" || echo "Not found"

echo -e "\n=== modelsSearchActivitiesResult.json time_of_day ==="
fd -e json -name "modelsSearchActivitiesResult.json" frontend/schemas -exec cat {} \; 2>/dev/null | grep -A 15 "time_of_day" || echo "Not found"

echo -e "\n=== List all JSON schema files with 'Activity' in name ==="
fd -e json -name "*Activity*.json" frontend/schemas

Repository: GenerateNU/toggo

Length of output: 482


🏁 Script executed:

#!/bin/bash
# Fix fd syntax - look for files with Activity in the name
echo "=== All Activity-related JSON files in frontend/schemas ==="
fd "Activity" frontend/schemas --type f --extension json

echo -e "\n=== Search for all time_of_day occurrences in frontend/schemas ==="
rg "time_of_day" frontend/schemas -A 12

Repository: GenerateNU/toggo

Length of output: 7128


Remove unnecessary allOf wrapper and deduplicate enum in time_of_day field.

The time_of_day field uses an allOf wrapper with the enum duplicated at lines 46 and 50. Other activity schemas—modelsActivity.json, modelsActivityAPIResponse.json, modelsSearchActivitiesResult.json, and modelsActivityCursorPageResult.json—all define this field with a simpler structure that omits allOf. Align the request schema with this pattern to maintain consistency:

Proposed simplified structure
     "time_of_day": {
-      "enum": ["morning", "afternoon", "evening"],
-      "allOf": [
-        {
-          "type": "string",
-          "enum": ["morning", "afternoon", "evening"],
-          "x-enum-varnames": [
-            "ActivityTimeOfDayMorning",
-            "ActivityTimeOfDayAfternoon",
-            "ActivityTimeOfDayEvening"
-          ],
-          "x-readme-ref-name": "models.ActivityTimeOfDay"
-        }
-      ]
+      "type": "string",
+      "enum": ["morning", "afternoon", "evening"],
+      "x-enum-varnames": [
+        "ActivityTimeOfDayMorning",
+        "ActivityTimeOfDayAfternoon",
+        "ActivityTimeOfDayEvening"
+      ],
+      "x-readme-ref-name": "models.ActivityTimeOfDay"
     },

Note: modelsUpdateActivityRequest.json uses the same allOf pattern and should be updated identically.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"time_of_day": {
"enum": ["morning", "afternoon", "evening"],
"allOf": [
{
"type": "string",
"enum": ["morning", "afternoon", "evening"],
"x-enum-varnames": [
"ActivityTimeOfDayMorning",
"ActivityTimeOfDayAfternoon",
"ActivityTimeOfDayEvening"
],
"x-readme-ref-name": "models.ActivityTimeOfDay"
}
]
},
"time_of_day": {
"type": "string",
"enum": ["morning", "afternoon", "evening"],
"x-enum-varnames": [
"ActivityTimeOfDayMorning",
"ActivityTimeOfDayAfternoon",
"ActivityTimeOfDayEvening"
],
"x-readme-ref-name": "models.ActivityTimeOfDay"
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/schemas/modelsCreateActivityRequest.json` around lines 45 - 59,
Remove the redundant allOf wrapper and duplicated enum in the time_of_day
property: replace the current object that nests type/enum inside allOf with a
single schema entry that directly defines "type": "string", the "enum":
["morning","afternoon","evening"], and the x-enum-varnames/x-readme-ref-name
metadata; apply the same change to the corresponding time_of_day field in
modelsUpdateActivityRequest.json so both request schemas match the simpler
pattern used by modelsActivity.json, modelsActivityAPIResponse.json,
modelsSearchActivitiesResult.json, and modelsActivityCursorPageResult.json.

Comment on lines +9 to +11
"end_date": { "type": "string" },
"name": { "type": "string", "minLength": 1 },
"start_date": { "type": "string" }
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Apr 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Constrain trip date fields to ISO date format in the schema.

Lines 9 and 11 should use format: "date"; currently any string passes schema validation.

Proposed fix
-    "end_date": { "type": "string" },
+    "end_date": { "type": "string", "format": "date" },
@@
-    "start_date": { "type": "string" }
+    "start_date": { "type": "string", "format": "date" }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/schemas/modelsCreateTripRequest.json` around lines 9 - 11, Update
the JSON schema for trip date fields so they validate ISO dates: modify the
"start_date" and "end_date" properties in modelsCreateTripRequest.json to
include "format": "date" in addition to "type": "string" (e.g., keep the "name"
constraints unchanged) so the schema enforces ISO date format validation for
those fields.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@coderabbitai What is the established pattern? Do other dates currently use string? Or stricter validation?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how date fields are defined across all frontend schema files
rg -n '"date"' frontend/schemas/ --type json -C2

echo "---"
# Also check for format: date usage
rg -n 'format' frontend/schemas/ --type json -C2

echo "---"
# Check other date fields like created_at, updated_at
rg -n 'created_at|updated_at|_date' frontend/schemas/ --type json -C1

Length of output: 30913


@aahiltn, the pattern is clear and consistent. Every date-only field in this codebase (e.g., activity start/end ranges in modelsDateRange.json, modelsActivity.json, modelsCreateActivityRequest.json, etc.) uses the stricter form:

{
  "description": "ISO 8601 date format (YYYY-MM-DD)",
  "type": "string",
  "format": "date",
  "example": "2024-01-01"
}

Plain { "type": "string" } is only used for timestamp fields like created_at and updated_at.

The new start_date/end_date fields in modelsCreateTripRequest.json (and the same fields added to modelsUpdateTripRequest.json, modelsTrip.json, modelsTripAPIResponse.json, modelsSearchTripsResult.json, modelsTripCursorPageResult.json) are inconsistent with this established pattern. The fix applies across all six of those files:

"end_date": {
  "description": "ISO 8601 date format (YYYY-MM-DD)",
  "type": "string",
  "format": "date",
  "example": "2024-01-05"
},
"start_date": {
  "description": "ISO 8601 date format (YYYY-MM-DD)",
  "type": "string",
  "format": "date",
  "example": "2024-01-01"
}

🧠 Learnings used
Learnt from: in-mai-space
Repo: GenerateNU/toggo PR: 100
File: frontend/schemas/modelsUpdateUserRequest.json:6-6
Timestamp: 2026-01-27T23:34:50.227Z
Learning: In the frontend of the toggo project, timezone values are automatically retrieved from device settings using `Intl.DateTimeFormat().resolvedOptions().timeZone` rather than being user-entered, so client-side schema validation for timezone format is not critical since the browser API returns valid IANA timezone strings.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/internal/tests/trips_test.go`:
- Around line 530-548: The test currently only checks for existence of
"start_date" and "end_date" after creating a trip; update the assertions to
verify the actual values match the input payload (similar to TestTripCurrency).
After you create the trip and capture tripID (resp["id"]), in the GET request
chain (the testkit.New(...).Request(...).AssertStatus(...)) replace or augment
AssertFieldExists("start_date")/AssertFieldExists("end_date") with
AssertField("start_date", expectedStart) and AssertField("end_date",
expectedEnd), where expectedStart/expectedEnd are the original date strings used
when calling the creation endpoint (or extracted from the creation request
variables), so the GET response is validated against the exact expected values.
- Around line 609-625: Add a new subtest in trips_test.go (similar to the
existing t.Run "end date before start date is rejected on create") that
constructs a CreateTripRequest where StartDate and EndDate are the same (set
both to startDate), sends the POST to "/api/v1/trips" via
testkit.New(...).Request(...), and asserts http.StatusBadRequest; also assert
the validation error message contains "end date must be after start date" to
document that same-day trips are intentionally rejected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 06629ed1-8ec3-4dd9-bf61-ddf918bc4cc9

📥 Commits

Reviewing files that changed from the base of the PR and between ac18440 and 3bf32ab.

📒 Files selected for processing (1)
  • backend/internal/tests/trips_test.go

Comment on lines +530 to +548
}).
AssertStatus(http.StatusCreated).
AssertFieldExists("start_date").
AssertFieldExists("end_date").
GetBody()

tripID := resp["id"].(string)

// Dates persist on GET
testkit.New(t).
Request(testkit.Request{
App: app,
Route: fmt.Sprintf("/api/v1/trips/%s", tripID),
Method: testkit.GET,
UserID: &ownerID,
}).
AssertStatus(http.StatusOK).
AssertFieldExists("start_date").
AssertFieldExists("end_date")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider asserting actual date values, not just field existence.

The test verifies that start_date and end_date fields exist but does not confirm the returned values match the input. A serialization or storage bug could produce incorrect dates while this test passes. Compare with TestTripCurrency which asserts specific values like AssertField("currency", "EUR").

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/internal/tests/trips_test.go` around lines 530 - 548, The test
currently only checks for existence of "start_date" and "end_date" after
creating a trip; update the assertions to verify the actual values match the
input payload (similar to TestTripCurrency). After you create the trip and
capture tripID (resp["id"]), in the GET request chain (the
testkit.New(...).Request(...).AssertStatus(...)) replace or augment
AssertFieldExists("start_date")/AssertFieldExists("end_date") with
AssertField("start_date", expectedStart) and AssertField("end_date",
expectedEnd), where expectedStart/expectedEnd are the original date strings used
when calling the creation endpoint (or extracted from the creation request
variables), so the GET response is validated against the exact expected values.

Comment on lines +609 to +625
t.Run("end date before start date is rejected on create", func(t *testing.T) {
testkit.New(t).
Request(testkit.Request{
App: app,
Route: "/api/v1/trips",
Method: testkit.POST,
UserID: &ownerID,
Body: models.CreateTripRequest{
Name: "Bad Date Trip",
BudgetMin: 100,
BudgetMax: 500,
StartDate: &endDate, // end before start
EndDate: &startDate,
},
}).
AssertStatus(http.StatusBadRequest)
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the date validation logic in the service
ast-grep --pattern $'if $_ != nil && $_ != nil && !$_.After($_) {
  $$$
}'

Repository: GenerateNU/toggo

Length of output: 628


🏁 Script executed:

# Search for tests that might cover same-day or equal-date scenarios
rg -A 5 -B 5 "StartDate.*EndDate|EndDate.*StartDate" backend/internal/tests/trips_test.go

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check if there are any tests with equal dates (dates on same day)
rg "StartDate.*EndDate\s*\}" backend/internal/tests/trips_test.go -A 2 -B 2

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Look for any spec or requirements files that define trip date behavior
fd -e md -e txt -e go | xargs rg -l "same.day|same-day|equal.*date" 2>/dev/null | head -20

Repository: GenerateNU/toggo

Length of output: 42


🏁 Script executed:

# Check the trips service for any comments about date requirements
sed -n '55,75p' backend/internal/services/trips.go
sed -n '225,245p' backend/internal/services/trips.go

Repository: GenerateNU/toggo

Length of output: 1513


🏁 Script executed:

# Get a comprehensive view of all date-related tests in the trips_test.go file
grep -n "test.*[Dd]ate\|StartDate\|EndDate" backend/internal/tests/trips_test.go | head -30

Repository: GenerateNU/toggo

Length of output: 411


🏁 Script executed:

# Look at the lines around the validation test to see the full context
sed -n '600,650p' backend/internal/tests/trips_test.go

Repository: GenerateNU/toggo

Length of output: 1373


Same-day trips are intentionally unsupported.

The service validation explicitly requires EndDate.After(StartDate) with the error message "end date must be after start date". Current tests cover valid dates (start before end) and invalid dates (end before start), but do not explicitly test the equal-date edge case. Consider adding a test case where startDate == endDate to document that same-day trips are intentionally rejected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/internal/tests/trips_test.go` around lines 609 - 625, Add a new
subtest in trips_test.go (similar to the existing t.Run "end date before start
date is rejected on create") that constructs a CreateTripRequest where StartDate
and EndDate are the same (set both to startDate), sends the POST to
"/api/v1/trips" via testkit.New(...).Request(...), and asserts
http.StatusBadRequest; also assert the validation error message contains "end
date must be after start date" to document that same-day trips are intentionally
rejected.

ADD COLUMN start_date DATE,
ADD COLUMN end_date DATE;

CREATE INDEX idx_trips_dates ON trips(start_date, end_date);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

do we have search functionality that would need this index? i dont remember


/**
* @description Retrieves paginated activities for a trip, optionally filtered by category
* @description Retrieves paginated activities for a trip, optionally filtered by category, time of day, and/or date
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

im sure these docs will be regenerated but are they true? I don't think you touched activities in this one

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think Amogh forgot to generate docs for his PR

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