Skip to content

Conversation

@plutov
Copy link
Owner

@plutov plutov commented Jul 17, 2025

  • Dump sqlite for simplicity
  • Use sqlc

TODO:

  • Still need to migrate all changes to sqlc.

Summary by CodeRabbit

  • New Features

    • Introduced a new database abstraction layer and strong typing for survey-related entities, improving database interactions and reliability.
    • Added support for creating surveys directly in PostgreSQL.
  • Refactor

    • Migrated all backend storage from SQLite to PostgreSQL, removing all SQLite support and dependencies.
    • Updated the storage layer to use a more efficient PostgreSQL driver for improved performance and context management.
    • Simplified service initialization to always use PostgreSQL storage.
  • Documentation

    • Updated documentation to reflect PostgreSQL as the sole supported database, removing all references to SQLite.
    • Simplified environment variable and deployment instructions to focus on PostgreSQL usage.
  • Chores

    • Cleaned up configuration files and dependencies to remove SQLite references and streamline PostgreSQL integration.
    • Updated environment configuration to use PostgreSQL connection strings and removed SQLite volume mounts.

@plutov plutov self-assigned this Jul 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 17, 2025

Walkthrough

This change removes all support for SQLite as a backend database, transitioning the project to use only PostgreSQL. All code, configuration, documentation, and migration logic related to SQLite are deleted or replaced. The Go backend now uses the pgx driver and sqlc-generated code for PostgreSQL interactions, and the storage layer is refactored accordingly. The documentation and deployment instructions are updated to reflect PostgreSQL as the sole supported database.

Changes

File(s) / Path(s) Change Summary
.gitignore Removed ignore rule for api/sqlite3/.
README.md, compose.yaml Removed all references to SQLite; updated docs and environment for PostgreSQL only.
api/go.mod Switched dependencies from SQLite to PostgreSQL (pgx); removed SQLite-related modules.
api/migrations/sqlite/000001_schema.up.sql, api/pkg/storage/sqlite.go Deleted SQLite schema and all SQLite storage backend code.
api/pkg/services/services.go Removed database type switch; always uses Postgres storage.
api/pkg/storage/interface.go Minor formatting: removed blank lines in interface declarations.
api/pkg/storage/postgres.go Refactored to use pgx and sqlc-generated queries; removed standard SQL driver usage.
api/pkg/db/db.go, api/pkg/db/extend.go, api/pkg/db/models.go, api/pkg/db/queries/surveys.sql, api/pkg/db/surveys.sql.go Added sqlc-generated code, type models, and helper for PostgreSQL.
api/sqlc.yaml Added sqlc configuration for PostgreSQL code generation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant API
    participant PostgresDB

    User->>API: Sends request (e.g., create survey)
    API->>PostgresDB: Executes sqlc-generated query via pgx
    PostgresDB-->>API: Returns result (survey data)
    API-->>User: Responds with survey info
Loading

Poem

Oh, the days of SQLite are gone,
Now Postgres stands alone and strong!
With pgx and sqlc we hop,
Our database code is tip-top.
No more switching, no more fuss—
Just one backend, swift as us!
🐇💾✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 4

🔭 Outside diff range comments (3)
api/pkg/storage/postgres.go (3)

158-165: Potential SQL injection risk with dynamic field names

Using fmt.Sprintf to build queries with dynamic field names can lead to SQL injection if the field parameter is not properly validated. Consider using a whitelist approach or a map of allowed fields.

 func (p *Postgres) GetSurveyByField(field string, value interface{}) (*types.Survey, error) {
+	// Whitelist allowed fields to prevent SQL injection
+	allowedFields := map[string]bool{
+		"id": true,
+		"uuid": true,
+		"url_slug": true,
+		// add other allowed fields
+	}
+	if !allowedFields[field] {
+		return nil, fmt.Errorf("invalid field name: %s", field)
+	}
+
 	query := fmt.Sprintf(`SELECT
 		s.id, s.uuid, s.created_at,
 		s.parse_status, s.delivery_status,
 		s.error_log, s.name, s.config, s.url_slug
 	FROM surveys AS s
 	WHERE s.%s=$1;`, field)

253-259: Remove incorrect nil check for QueryRow result

pgx.QueryRow never returns nil. It returns a Row that defers error handling until Scan is called. The nil check is unnecessary and will never be true.

 	row := p.conn.QueryRow(p.ctx, query, session.Status, session.SurveyUUID, session.IPAddr)
-	if row == nil {
-		return fmt.Errorf("unable to create survey session")
-	}
 
 	return row.Scan(&session.ID, &session.UUID)

The error from the query will be returned by Scan if the query fails.


373-389: Validate sort parameters to prevent SQL injection

The dynamic ORDER BY clause using fmt.Sprintf with filter.SortBy and filter.Order could lead to SQL injection if these values come from user input.

Add validation for the sort parameters:

 func (p *Postgres) GetSurveySessionsWithAnswers(surveyUUID string, filter *types.SurveySessionsFilter) ([]types.SurveySession, int, error) {
+	// Validate sort parameters
+	allowedSortFields := map[string]bool{
+		"created_at": true,
+		"completed_at": true,
+		"status": true,
+		// add other allowed fields
+	}
+	if !allowedSortFields[filter.SortBy] {
+		return nil, 0, fmt.Errorf("invalid sort field: %s", filter.SortBy)
+	}
+	
+	allowedOrders := map[string]bool{
+		"ASC": true,
+		"DESC": true,
+	}
+	if !allowedOrders[strings.ToUpper(filter.Order)] {
+		return nil, 0, fmt.Errorf("invalid sort order: %s", filter.Order)
+	}
+
 	query := fmt.Sprintf(`WITH limited_sessions AS (
🧹 Nitpick comments (4)
api/pkg/db/extend.go (1)

9-24: Consider using standard UUID library for better maintainability.

The implementation is correct and efficient, but consider using a standard UUID library like github.com/google/uuid for better maintainability and error handling.

+import (
+	"github.com/google/uuid"
+)
+
-func EncodeUUID(uuid pgtype.UUID) string {
-	src := uuid.Bytes
-	var buf [36]byte
-
-	hex.Encode(buf[0:8], src[:4])
-	buf[8] = '-'
-	hex.Encode(buf[9:13], src[4:6])
-	buf[13] = '-'
-	hex.Encode(buf[14:18], src[6:8])
-	buf[18] = '-'
-	hex.Encode(buf[19:23], src[8:10])
-	buf[23] = '-'
-	hex.Encode(buf[24:], src[10:])
-
-	return string(buf[:])
-}
+func EncodeUUID(pgUUID pgtype.UUID) string {
+	if !pgUUID.Valid {
+		return ""
+	}
+	u, err := uuid.FromBytes(pgUUID.Bytes[:])
+	if err != nil {
+		return ""
+	}
+	return u.String()
+}

Note: This would require adding the UUID dependency back to go.mod.

README.md (1)

321-327: Migration instructions simplified appropriately.

The migration section correctly reflects the single-database approach with unified migration directory structure.

Consider adding a language specification to the fenced code block to improve documentation clarity:

-```
+```bash
 cd api
 migrate create -dir migrations -ext sql -seq name
-```
+```
api/pkg/storage/postgres.go (2)

261-274: Improve NULL handling in SQL query

Instead of string concatenation for NULL/NOW(), consider using parameterized queries with proper null handling.

 func (p *Postgres) UpdateSurveySessionStatus(sessionUUID string, newStatus types.SurveySessionStatus) error {
-	completedAt := "NULL"
-	if newStatus == types.SurveySessionStatus_Completed {
-		completedAt = "NOW()"
-	}
-
-	query := fmt.Sprintf(`UPDATE surveys_sessions
-		SET status = $1, completed_at = %s
-		WHERE uuid = $2;`, completedAt)
-
-	_, err := p.conn.Exec(p.ctx, query, newStatus, sessionUUID)
+	var query string
+	var args []interface{}
+	
+	if newStatus == types.SurveySessionStatus_Completed {
+		query = `UPDATE surveys_sessions SET status = $1, completed_at = NOW() WHERE uuid = $2`
+		args = []interface{}{newStatus, sessionUUID}
+	} else {
+		query = `UPDATE surveys_sessions SET status = $1, completed_at = NULL WHERE uuid = $2`
+		args = []interface{}{newStatus, sessionUUID}
+	}
+	
+	_, err := p.conn.Exec(p.ctx, query, args...)
 
 	return err
 }

455-463: Use database timestamp instead of application-generated timestamp

Generating timestamps in the application can lead to inconsistencies, especially in distributed systems. Use the database's NOW() function instead.

 func (p *Postgres) StoreWebhookResponse(sessionId int, responseStatus int, response string) error {
 	query := `INSERT INTO surveys_webhook_responses
-		(created_at, session_id, response_status, response)
-		VALUES ($1, $2, $3, $4);`
+		(created_at, session_id, response_status, response)
+		VALUES (NOW(), $1, $2, $3);`
 
-	createdAtStr := time.Now().UTC().Format(types.DateTimeFormat)
-	_, err := p.conn.Exec(p.ctx, query, createdAtStr, sessionId, responseStatus, response)
+	_, err := p.conn.Exec(p.ctx, query, sessionId, responseStatus, response)
 	return err
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 082b445 and ee4a327.

⛔ Files ignored due to path filters (1)
  • api/go.sum is excluded by !**/*.sum
📒 Files selected for processing (15)
  • .gitignore (0 hunks)
  • README.md (2 hunks)
  • api/go.mod (2 hunks)
  • api/migrations/sqlite/000001_schema.up.sql (0 hunks)
  • api/pkg/db/db.go (1 hunks)
  • api/pkg/db/extend.go (1 hunks)
  • api/pkg/db/models.go (1 hunks)
  • api/pkg/db/queries/surveys.sql (1 hunks)
  • api/pkg/db/surveys.sql.go (1 hunks)
  • api/pkg/services/services.go (1 hunks)
  • api/pkg/storage/interface.go (0 hunks)
  • api/pkg/storage/postgres.go (18 hunks)
  • api/pkg/storage/sqlite.go (0 hunks)
  • api/sqlc.yaml (1 hunks)
  • compose.yaml (1 hunks)
💤 Files with no reviewable changes (4)
  • .gitignore
  • api/pkg/storage/interface.go
  • api/migrations/sqlite/000001_schema.up.sql
  • api/pkg/storage/sqlite.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
api/pkg/db/surveys.sql.go (3)
api/pkg/db/models.go (3)
  • NullSurveyParseStatuses (118-121)
  • NullSurveyDeliveryStatuses (75-78)
  • Survey (183-193)
api/pkg/db/db.go (1)
  • Queries (24-26)
api/pkg/surveys/manage.go (1)
  • CreateSurvey (13-40)
🪛 Checkov (3.2.334)
compose.yaml

[MEDIUM] 11-12: Basic Auth Credentials

(CKV_SECRET_4)

🪛 markdownlint-cli2 (0.17.2)
README.md

325-325: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 GitHub Check: Lint Go
api/pkg/storage/postgres.go

[failure] 253-253:
SA4023(related information): the lhs of the comparison is the 1st return value of this function call (staticcheck)

🪛 GitHub Actions: Tests
api/pkg/storage/postgres.go

[error] 253-253: golangci-lint staticcheck SA4023: the lhs of the comparison is the 1st return value of this function call

🔇 Additional comments (18)
api/go.mod (3)

3-3: LGTM: More specific Go version.

The change to a more specific Go version (1.24.4) is a good practice for reproducible builds.


25-26: LGTM: Proper pgx indirect dependencies added.

The addition of pgpassfile and pgservicefile indirect dependencies is expected with pgx/v5 for PostgreSQL connection management.


5-15: Confirmed safe removal of github.com/google/uuid dependency
Ripgrep searches for both the import path and common uuid calls (New, Parse, Must) returned no matches, so removing this module will not break the build.

api/pkg/db/queries/surveys.sql (1)

1-6: LGTM: Well-structured sqlc query.

The CreateSurvey query is properly formatted for sqlc with correct parameter placeholders and RETURNING clause. The query structure is clean and follows PostgreSQL best practices.

api/sqlc.yaml (1)

1-12: LGTM: Properly configured sqlc setup.

The sqlc configuration is well-structured with appropriate settings for PostgreSQL migration:

  • Correct version and engine specification
  • Logical directory structure for queries and schema
  • Proper pgx/v5 integration matching go.mod dependencies
  • Clean package naming convention

This configuration aligns perfectly with the overall migration from SQLite to PostgreSQL.

api/pkg/services/services.go (2)

20-20: LGTM: Simplified storage initialization.

The removal of conditional database type selection aligns with the SQLite removal and simplifies the codebase. The unconditional PostgreSQL initialization is cleaner and more maintainable.


17-35: DATABASE_TYPE removal verified—no impact found.

  • No occurrences of DATABASE_TYPE in Go code, YAML, or Dockerfiles.
  • No remaining references to SQLite.
  • Documentation only mentions DATABASE_URL (Postgres), with no mention of database type selection.
compose.yaml (1)

11-11: Database configuration correctly updated for PostgreSQL migration.

The environment variable changes properly reflect the transition from SQLite to PostgreSQL-only support. The connection string format is correct and the removal of DATABASE_TYPE aligns with the simplified single-database approach.

README.md (3)

290-290: Documentation correctly updated to reflect PostgreSQL as the sole database.

The change from "optional" to required PostgreSQL deployment properly reflects the removal of SQLite support.


296-296: Environment variable documentation accurately updated.

The DATABASE_URL description now correctly specifies PostgreSQL connection string format, removing any SQLite references.


318-318: Tech stack section properly updated.

The backend description now accurately lists only PostgreSQL, removing SQLite references.

api/pkg/db/db.go (1)

14-32: Well-structured database abstraction layer.

The generated sqlc code provides a clean abstraction with proper context support and transaction handling. The DBTX interface correctly abstracts pgx connection types, and the WithTx method enables proper transaction scoping.

api/pkg/db/surveys.sql.go (3)

14-19: SQL query properly structured with complete column selection.

The INSERT query correctly uses parameterized inputs and returns all necessary columns including generated fields like id, uuid, and created_at.


21-28: Parameter struct uses appropriate nullable types.

The CreateSurveyParams struct correctly uses nullable enum types for optional fields and standard types for required fields, providing proper type safety.


30-52: Query method implements proper context handling and scanning.

The CreateSurvey method correctly uses context for request scoping and properly scans all returned columns into the Survey struct.

api/pkg/db/models.go (3)

14-54: Enum types properly implemented with nullable wrappers.

The CommonStatuses enum and its nullable wrapper correctly implement the Scanner and Valuer interfaces, providing proper database serialization with appropriate error handling.


56-139: Survey status enums follow consistent patterns.

Both SurveyDeliveryStatuses and SurveyParseStatuses enums maintain consistent implementation patterns with proper nullable wrappers and interface compliance.


183-227: Database table structs properly use PostgreSQL types.

The table structs correctly use pgtype for nullable fields and appropriate Go types for required fields, ensuring proper mapping to the PostgreSQL schema.

github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.5.4
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify pgx version for security vulnerabilities.

The addition of pgx/v5 v5.5.4 aligns with the PostgreSQL migration. However, please verify this version is secure and up-to-date.


🏁 Script executed:

#!/bin/bash
# Check for security advisories and latest version of pgx
echo "Checking pgx/v5 version and security..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: GO, package: "github.com/jackc/pgx/v5") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

# Check latest releases
gh api repos/jackc/pgx/releases/latest | jq '.tag_name'

Length of output: 992


To ensure v5.5.4 is the latest release in the Go module ecosystem, let’s fetch the @latest version from the Go proxy.


🏁 Script executed:

#!/bin/bash
# Check the latest pgx/v5 version from the Go module proxy
curl -s https://proxy.golang.org/github.com/jackc/pgx/v5/@latest | jq '.Version'

Length of output: 89


Bump pgx/v5 to the latest patch release (v5.7.5)

v5.5.4 addresses the HIGH and MODERATE security advisories (SQL injection overflow and pipeline panic), but the Go proxy shows v5.7.5 as the current latest. Upgrading will include additional bug-fixes and any further hardening.

• api/go.mod (line 9): change

- github.com/jackc/pgx/v5 v5.5.4
+ github.com/jackc/pgx/v5 v5.7.5
📝 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
github.com/jackc/pgx/v5 v5.5.4
github.com/jackc/pgx/v5 v5.7.5
🤖 Prompt for AI Agents
In api/go.mod at line 9, update the version of github.com/jackc/pgx/v5 from
v5.5.4 to the latest patch release v5.7.5 to include additional bug fixes and
security improvements. Replace the existing version string with the new version
number.

Comment on lines +9 to +24
func EncodeUUID(uuid pgtype.UUID) string {
src := uuid.Bytes
var buf [36]byte

hex.Encode(buf[0:8], src[:4])
buf[8] = '-'
hex.Encode(buf[9:13], src[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], src[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], src[8:10])
buf[23] = '-'
hex.Encode(buf[24:], src[10:])

return string(buf[:])
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation for robustness.

The function should handle invalid UUID inputs gracefully.

 func EncodeUUID(uuid pgtype.UUID) string {
+	if !uuid.Valid {
+		return ""
+	}
 	src := uuid.Bytes
 	var buf [36]byte
 
 	hex.Encode(buf[0:8], src[:4])
 	buf[8] = '-'
 	hex.Encode(buf[9:13], src[4:6])
 	buf[13] = '-'
 	hex.Encode(buf[14:18], src[6:8])
 	buf[18] = '-'
 	hex.Encode(buf[19:23], src[8:10])
 	buf[23] = '-'
 	hex.Encode(buf[24:], src[10:])
 
 	return string(buf[:])
 }
📝 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
func EncodeUUID(uuid pgtype.UUID) string {
src := uuid.Bytes
var buf [36]byte
hex.Encode(buf[0:8], src[:4])
buf[8] = '-'
hex.Encode(buf[9:13], src[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], src[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], src[8:10])
buf[23] = '-'
hex.Encode(buf[24:], src[10:])
return string(buf[:])
}
func EncodeUUID(uuid pgtype.UUID) string {
if !uuid.Valid {
return ""
}
src := uuid.Bytes
var buf [36]byte
hex.Encode(buf[0:8], src[:4])
buf[8] = '-'
hex.Encode(buf[9:13], src[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], src[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], src[8:10])
buf[23] = '-'
hex.Encode(buf[24:], src[10:])
return string(buf[:])
}
🤖 Prompt for AI Agents
In api/pkg/db/extend.go around lines 9 to 24, the EncodeUUID function lacks
input validation for the UUID parameter, which may cause issues if the input is
invalid. Add a check to verify that the UUID is valid before proceeding with
encoding, and handle invalid inputs gracefully by returning an empty string or
an error indicator to prevent unexpected behavior.

Comment on lines 23 to 28
type Postgres struct {
conn *sql.DB
addr string
conn *pgx.Conn
queries *db.Queries
addr string
ctx context.Context
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Avoid storing context in struct fields

Storing context in struct fields is an anti-pattern in Go. Context should be passed as the first parameter to methods that need it. This allows for proper cancellation, timeouts, and deadline propagation.

Remove the ctx field from the struct and pass context as a parameter to methods:

 type Postgres struct {
 	conn    *pgx.Conn
 	queries *db.Queries
 	addr    string
-	ctx     context.Context
 }

Then update methods to accept context as the first parameter, for example:

func (p *Postgres) UpdateSurvey(ctx context.Context, survey *types.Survey) error {
    // use ctx instead of p.ctx
}
🤖 Prompt for AI Agents
In api/pkg/storage/postgres.go around lines 23 to 28, the Postgres struct
incorrectly stores a context.Context as a field, which is an anti-pattern.
Remove the ctx field from the struct definition and update all methods of
Postgres to accept context.Context as their first parameter instead of relying
on the stored field. Modify method implementations to use the passed context
parameter for cancellation and timeout handling.

Comment on lines 38 to 42
var err error
p.conn, err = sql.Open("postgres", p.addr)
p.conn, err = pgx.Connect(context.Background(), p.addr)
if err != nil {
return err
log.Fatalf("cannot connect to postgres: %v", err)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Return error instead of calling log.Fatalf

Using log.Fatalf in a library method terminates the entire program, which prevents proper error handling by the caller. Return the error instead.

-	p.conn, err = pgx.Connect(context.Background(), p.addr)
-	if err != nil {
-		log.Fatalf("cannot connect to postgres: %v", err)
-	}
+	p.conn, err = pgx.Connect(context.Background(), p.addr)
+	if err != nil {
+		return fmt.Errorf("cannot connect to postgres: %v", err)
+	}
📝 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
var err error
p.conn, err = sql.Open("postgres", p.addr)
p.conn, err = pgx.Connect(context.Background(), p.addr)
if err != nil {
return err
log.Fatalf("cannot connect to postgres: %v", err)
}
var err error
p.conn, err = pgx.Connect(context.Background(), p.addr)
if err != nil {
return fmt.Errorf("cannot connect to postgres: %v", err)
}
🤖 Prompt for AI Agents
In api/pkg/storage/postgres.go around lines 38 to 42, replace the log.Fatalf
call with returning the error to the caller instead of terminating the program.
Modify the function signature to return an error if it does not already, and
propagate the connection error by returning it so the caller can handle it
properly.

Copy link

@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: 0

♻️ Duplicate comments (3)
api/go.mod (1)

9-9: Update pgx/v5 to the latest version for security and bug fixes.

As identified in the previous review, the current version v5.5.4 should be updated to v5.7.5 to include additional security improvements and bug fixes.

api/pkg/storage/postgres.go (2)

23-28: Context storage in struct remains an anti-pattern.

The issue of storing context in the struct field was identified in the previous review and still needs to be addressed. Context should be passed as parameters to methods for proper cancellation and timeout handling.


38-42: Return error instead of calling log.Fatalf.

As identified in the previous review, using log.Fatalf terminates the program and prevents proper error handling by the caller. This should return the error instead.

🧹 Nitpick comments (1)
ui/src/components/app/SurveyResponsesPage.tsx (1)

305-305: Consider using optional chaining for safer property access.

The current conditional rendering can be simplified and made safer using optional chaining.

-                      <Table.Cell>{question && question.label}</Table.Cell>
+                      <Table.Cell>{question?.label}</Table.Cell>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee4a327 and 5647451.

⛔ Files ignored due to path filters (1)
  • api/go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • api/go.mod (1 hunks)
  • api/pkg/storage/postgres.go (18 hunks)
  • ui/src/components/app/SurveyResponsesPage.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
ui/src/components/app/SurveyResponsesPage.tsx

[error] 305-305: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (4)
ui/src/components/app/SurveyResponsesPage.tsx (1)

1-329: LGTM! Formatting standardization looks good.

The indentation has been consistently standardized to 2 spaces throughout the file. These formatting-only changes improve code consistency without affecting functionality.

api/go.mod (1)

3-15: LGTM! Dependency updates align with PostgreSQL migration.

The dependency changes properly reflect the migration from SQLite to PostgreSQL:

  • Removed SQLite-specific dependencies (google/uuid, mattn/go-sqlite3)
  • Added PostgreSQL driver (jackc/pgx/v5)
  • Updated Go version to a more specific patch release
  • Updated testify to latest version

These changes support the architectural shift to PostgreSQL-only backend.

api/pkg/storage/postgres.go (2)

1-110: Excellent architectural improvement with sqlc integration.

The refactoring to use pgx driver and sqlc-generated queries is well-implemented:

  • Proper use of typed parameters with nullable wrappers
  • Clean separation of concerns with db.Queries
  • Correct error handling and marshaling in CreateSurvey
  • Proper assignment of generated IDs and UUIDs back to the struct

This represents a significant improvement in type safety and maintainability.


64-78: Migration logic simplified appropriately.

The migration logic has been properly simplified to use a unified migrations directory, removing the complexity of SQLite-specific migration handling. This aligns well with the PostgreSQL-only approach.

@plutov plutov merged commit 05060db into main Aug 3, 2025
4 checks passed
@plutov plutov deleted the sqlc branch August 3, 2025 19:18
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.

2 participants