feat: Implement Persistence for User Problem Reports#306
feat: Implement Persistence for User Problem Reports#306AhmedAlian7 wants to merge 5 commits intoOneBusAway:mainfrom
Conversation
aaronbrethorst
left a comment
There was a problem hiding this comment.
Ahmed, great work: your implementation is well-structured and correctly scoped to write-only operations (no retrieval endpoints exposed). However, there are lint failures that must be fixed before merging.
Critical Issues
1. Lint Failures: Unchecked Error Return Values
Files: gtfsdb/problem_reports.go:167 and gtfsdb/problem_reports.go:212
The linter reports unchecked error return values for rows.Close():
gtfsdb/problem_reports.go:167:18: Error return value of `rows.Close` is not checked (errcheck)
gtfsdb/problem_reports.go:212:18: Error return value of `rows.Close` is not checked (errcheck)
Current code:
defer rows.Close()Suggested fix: While the error from rows.Close() is rarely actionable, we should follow the project's lint requirements. The common pattern is:
defer func() {
_ = rows.Close()
}()This explicitly discards the error, satisfying the linter while acknowledging we're intentionally not handling it.
Important Issues
2. Formatting Issue: Trailing Whitespace
File: internal/restapi/report_problem_with_stop_handler.go:42
There's a trailing tab character on the blank line after the DB initialization check. Running go fmt ./... will fix this.
Fit and Finish
3. Positive: Correctly Scoped to Write-Only Operations
I want to call out that the PR correctly implements only the persistence layer without exposing retrieval endpoints via HTTP. While the database layer includes GetProblemReportsByTrip and GetProblemReportsByStop queries (which is fine for future internal use), no HTTP handlers expose these methods to external callers.
This is the correct approach. Retrieval endpoints would need careful consideration around authentication, authorization, rate limiting, and data privacy before being exposed publicly.
4. Good Test Coverage
The tests properly cover:
- End-to-end happy path for both trip and stop reports
- Missing ID validation (empty ID returns 400)
- Minimal parameters (only required fields)
- Invalid coordinates are handled gracefully
5. Clean Helper Functions
The exported helper functions in gtfsdb/helpers.go (ToNullString, ParseNullFloat, ParseNullBool) are well-implemented and follow existing patterns in the codebase.
Required Actions Before Merge
- Fix lint errors in
gtfsdb/problem_reports.go(lines 167 and 212) - Run
go fmt ./...to fix formatting
Thank you for this contribution! The implementation is well-designed and follows the project patterns. Just need those lint fixes and we're good to go.
|
Thanks for the detailed review, Aron! I've addressed the linting failures and run |
Description
closes #292
Previously, the
report-problem-with-stopandreport-problem-with-tripAPI endpoints only logged problem reports without persisting them to the database. This meant all user-submitted reports were lost on application restart, making it impossible to analyze patterns, respond to user feedback, or track transit issues over time.This PR adds database persistence for problem reports while maintaining the existing logging behavior for real-time observability.
Changes
Database Schema (
gtfsdb/schema.sql)problem_reports_triptable with fields:id(auto-increment primary key)trip_id,service_date,vehicle_id,stop_id(trip context)code(problem type)user_comment,user_lat,user_lon,user_location_accuracy(user input)user_on_vehicle,user_vehicle_number(trip-specific fields)created_at,submitted_at(timestamps)problem_reports_stoptable with similar fields for stop-specific reports.trip_id,stop_id, andcreated_atfor efficient querying.SQL Queries (
gtfsdb/query.sql)CreateProblemReportTrip/CreateProblemReportStop: Insert new reports.GetProblemReportsByTrip/GetProblemReportsByStop: Retrieve reports by ID.GetProblemReportsTripByDateRange/GetProblemReportsStopByDateRange: Filter by date.GetProblemReportsTripByCode/GetProblemReportsStopByCode: Filter by problem type.GetRecentProblemReportsTrip/GetRecentProblemReportsStop: Paginated recent reports.Manual Go Implementation (
gtfsdb/problem_reports.go)ProblemReportsTrip,ProblemReportsStop.CreateProblemReportTripParams,CreateProblemReportStopParams.Queriesstruct.Handler Updates
report_problem_with_trip_handler.go: Updated to parse all trip-specific fields and store reports.report_problem_with_stop_handler.go: Updated to parse location fields and store reports.Shared Helpers (
gtfsdb/helpers.go)Consolidated duplicate helper functions into a shared location:
ToNullString(string) sql.NullString: Converts empty strings to NULL.ParseNullFloat(string) sql.NullFloat64: Parses floats with NULL for invalid values.ParseNullBool(string) sql.NullInt64: Parses booleans to 0/1 with NULL fallback.Testing
report_problem_with_trip_handler_test.goTestReportProblemWithTrip_MinimalParams: Verifies handler works with only required parameters.tripId).report_problem_with_stop_handler_test.goTestReportProblemWithStop_MinimalParams: Verifies handler works with minimal parameters.TestReportProblemWithStop_InvalidCoordinates: Verifies graceful handling of invalid lat/lon values.stopId).go build ./...passesmake lintpassesFollow-up Work