Skip to content

feat: add OpenAPI/swagger, Playwright E2E, sqlc, and CI tooling upgrades#6

Merged
afa7789 merged 8 commits into
mainfrom
tooling-upgrade
May 10, 2026
Merged

feat: add OpenAPI/swagger, Playwright E2E, sqlc, and CI tooling upgrades#6
afa7789 merged 8 commits into
mainfrom
tooling-upgrade

Conversation

@afa7789
Copy link
Copy Markdown
Owner

@afa7789 afa7789 commented May 8, 2026

adicionando mais tooling p/ o projeto

Summary by CodeRabbit

Release Notes

  • New Features

    • Added interactive API documentation interface for exploring backend endpoints.
    • Implemented end-to-end testing framework for critical user workflows.
  • Chores

    • Enhanced CI/CD pipeline with security scanning and automated semantic versioning.
    • Added commit message validation and automated dependency update management.

@afa7789 afa7789 requested a review from Copilot May 8, 2026 16:47
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Warning

Rate limit exceeded

@afa7789 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 58 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 644b8b64-7b07-4ca8-b3a4-2171ad423f99

📥 Commits

Reviewing files that changed from the base of the PR and between f49f095 and e462cbb.

⛔ Files ignored due to path filters (2)
  • backend/go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
📒 Files selected for processing (30)
  • .github/workflows/ci.yml
  • Makefile
  • backend/cmd/server/main.go
  • backend/docs/swagger/docs.go
  • backend/docs/swagger/swagger.json
  • backend/docs/swagger/swagger.yaml
  • backend/go.mod
  • backend/internal/domain/entity.go
  • backend/internal/domain/repository.go
  • backend/internal/handlers/blog.go
  • backend/internal/handlers/coupon.go
  • backend/internal/handlers/legal.go
  • backend/internal/handlers/security.go
  • backend/internal/handlers/user.go
  • backend/internal/handlers/waitlist.go
  • backend/internal/infrastructure/adapter.go
  • backend/internal/infrastructure/sqlc/blog_posts.sql.go
  • backend/internal/infrastructure/sqlc/products.sql.go
  • backend/internal/infrastructure/sqlc/querier.go
  • backend/internal/infrastructure/sqlc/queries/blog_posts.sql
  • backend/internal/infrastructure/sqlc/queries/products.sql
  • backend/internal/infrastructure/sqlc/queries/users.sql
  • backend/internal/infrastructure/sqlc/users.sql.go
  • backend/internal/testutil/mocks.go
  • docker-compose.yml
  • frontend/e2e/basic.spec.ts
  • frontend/package.json
  • frontend/playwright.config.ts
  • frontend/vite.config.ts
  • renovate.json
📝 Walkthrough

Walkthrough

This PR introduces comprehensive API documentation through Swagger/OpenAPI 2.0 specifications with godoc annotations across all handler methods, generates a type-safe database access layer via sqlc for core tables (blog posts, products, categories, users), establishes end-to-end testing infrastructure with Playwright, implements Git commit standards via hooks and linting, and configures automated CI/CD workflows for security scanning, E2E testing, and semantic release versioning.

Changes

Swagger API Documentation

Layer / File(s) Summary
Swagger Specification
backend/docs/swagger/docs.go, swagger.json, swagger.yaml
Complete Swagger 2.0 API specification documenting 40+ endpoints across admin, auth, store, blog, payments, user, and waitlist routes with schema definitions, security schemes, and Bearer token authentication.
Server Integration
backend/cmd/server/main.go, backend/go.mod
Fiber server registers /swagger/* endpoint serving Swagger UI; adds gofiber/contrib/swagger dependency and upgrades gofiber/fiber/v2.
Handler Documentation
backend/internal/handlers/admin.go, auth.go, blog.go, coupon.go, envconfig.go, handler.go, jobs.go, legal.go, payment.go, security.go, store.go, tools.go, user.go, waitlist.go
All handler methods annotated with Swagger godoc comments documenting endpoints, HTTP methods, request/response schemas, path/query parameters, and Bearer auth requirements. Coupon handler adds AdminDeleteCoupon returning 405 Method Not Allowed.
Build Integration
Makefile
Adds swagger target running swag init and sqlc target running sqlc generate; updates check target to include sqlc validation.

Type-Safe Database Layer

Layer / File(s) Summary
sqlc Configuration
backend/sqlc.yaml
Configures sqlc for PostgreSQL code generation with pgx/v5 driver, migrations as schema source, and JSON tag/interface generation options.
SQL Query Definitions
backend/internal/infrastructure/sqlc/queries/blog_posts.sql, categories.sql, products.sql, users.sql
SQL queries for CRUD operations and filtering: blog posts (get/list/count/create/update/delete with status filtering), categories (list/create/update/delete), products (get/list/count/create/update/delete with category and active filters), users (get/list/count/create/update/delete/verify email/update Stripe ID).
Generated Models
backend/internal/infrastructure/sqlc/models.go
sqlc-generated domain model structs (25 entities: BlogPost, Product, User, Category, Order, etc.) with pgtype.* fields for PostgreSQL compatibility and JSON serialization tags.
Database Interface
backend/internal/infrastructure/sqlc/db.go, querier.go
DBTX interface abstracting database operations (Exec/Query/QueryRow); Querier interface documenting all generated query methods; transaction support via WithTx.
Query Methods
backend/internal/infrastructure/sqlc/blog_posts.sql.go, categories.sql.go, products.sql.go, users.sql.go
Generated methods on *Queries for all SQL operations with proper parameter binding, row scanning, error handling, and slice iteration with rows.Err() checks.

End-to-End Testing & CI/CD

Layer / File(s) Summary
E2E Framework
e2e/playwright.config.ts
Playwright configuration with Docker Compose orchestration, 30s test timeout/1 retry, health check polling on /healthz, Chromium browser, and test tracing.
E2E Tests
e2e/basic.spec.ts
Smoke tests verifying /healthz endpoint responds 200 and frontend body element renders.
Frontend Integration
frontend/package.json
Adds e2e npm script running Playwright tests and @playwright/test dev dependency.
CI Workflows
.github/workflows/ci.yml
Security job runs govulncheck and gitleaks; build job adds sqlc diff check; e2e job boots Docker Compose, waits for /healthz, runs Playwright tests, uploads report on failure; release job runs semantic-release on main after all jobs pass.

Development Standards & Configuration

Layer / File(s) Summary
Git Hooks
lefthook.yml, commitlint.config.js
Lefthook commit-msg hook runs commitlint to enforce conventional commit format via @commitlint/config-conventional.
Root Configuration
package.json, .gitignore, .releaserc
Root package.json marks project private with ES modules; .gitignore adds node_modules/ and e2e test output directories; .releaserc configures semantic-release on main branch with commit analyzer, release notes, and GitHub publishing plugins.
Automation & Dependencies
renovate.json
Renovate Bot auto-merges minor/patch updates and devDependencies, runs gomodTidy after updates.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Hop along the docs, from Swagger springs flow,
sqlc tables bloom where database seeds grow,
E2E tests hop through each path we must know,
Commit hooks and releases make CI just glow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the primary changes: adding OpenAPI/Swagger documentation, Playwright E2E tests, sqlc for SQL code generation, and CI/tooling upgrades across the project.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tooling-upgrade

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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds additional project tooling across the repo: dependency automation (Renovate), commit workflow enforcement (Husky + commitlint), backend code generation (sqlc + Swagger/OpenAPI), Playwright E2E tests, and CI pipeline upgrades to run these checks.

Changes:

  • Add Renovate configuration plus semantic-release configuration and CI release job.
  • Add Playwright E2E scaffolding (config + basic tests) and wire E2E into CI.
  • Add sqlc configuration + generated DB access layer and add Swagger/OpenAPI generation + UI route; upgrade backend dependencies accordingly.

Reviewed changes

Copilot reviewed 41 out of 45 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
renovate.json Configure Renovate dependency updates and automerge rules.
package.json Add root-level tooling deps (husky/commitlint) and scripts.
package-lock.json Lockfile for root Node tooling dependencies.
Makefile Add targets for vulncheck/swagger/sqlc/e2e and include sqlc in check.
frontend/package.json Add Playwright dependency and an e2e script.
frontend/bun.lock Lockfile updates for Playwright installation via Bun.
e2e/playwright.config.ts New Playwright config to run against Docker Compose environment.
e2e/basic.spec.ts Basic E2E smoke tests (health + frontend load).
commitlint.config.js Configure commitlint conventional commits rules.
backend/sqlc.yaml Configure sqlc code generation for Postgres schema/queries.
backend/internal/infrastructure/sqlc/db.go Generated sqlc DB wrapper and query struct.
backend/internal/infrastructure/sqlc/models.go Generated sqlc models for DB tables.
backend/internal/infrastructure/sqlc/querier.go Generated sqlc Querier interface.
backend/internal/infrastructure/sqlc/users.sql.go Generated sqlc queries for users.
backend/internal/infrastructure/sqlc/products.sql.go Generated sqlc queries for products.
backend/internal/infrastructure/sqlc/categories.sql.go Generated sqlc queries for categories.
backend/internal/infrastructure/sqlc/blog_posts.sql.go Generated sqlc queries for blog posts.
backend/internal/infrastructure/sqlc/queries/users.sql Source SQL for user queries.
backend/internal/infrastructure/sqlc/queries/products.sql Source SQL for product queries (with optional filters).
backend/internal/infrastructure/sqlc/queries/categories.sql Source SQL for category queries.
backend/internal/infrastructure/sqlc/queries/blog_posts.sql Source SQL for blog post queries (with status filter).
backend/internal/handlers/waitlist.go Add Swagger annotations for waitlist routes.
backend/internal/handlers/user.go Add Swagger annotations for user routes.
backend/internal/handlers/tools.go Add Swagger annotations for admin tools route.
backend/internal/handlers/store.go Add Swagger annotations for store and admin store routes.
backend/internal/handlers/security.go Add Swagger annotations for security settings routes.
backend/internal/handlers/payment.go Add Swagger annotations for payment routes.
backend/internal/handlers/legal.go Replace inline comments with Swagger annotations for legal routes.
backend/internal/handlers/jobs.go Add Swagger annotations for jobs admin routes.
backend/internal/handlers/handler.go Add Swagger annotations for feature flag routes.
backend/internal/handlers/envconfig.go Replace inline comments with Swagger annotations for env/config routes.
backend/internal/handlers/coupon.go Add Swagger annotations for coupon routes.
backend/internal/handlers/blog.go Add Swagger annotations for blog routes (public + admin).
backend/internal/handlers/auth.go Add Swagger annotations for auth routes.
backend/internal/handlers/admin.go Add Swagger annotations for admin routes (upload, users, banners, etc.).
backend/go.mod Add Swagger/sqlc-related deps and bump Fiber patch version.
backend/go.sum Dependency checksum updates for new/updated backend modules.
backend/docs/swagger/swagger.yaml Generated Swagger spec output checked into repo.
backend/cmd/server/main.go Add Swagger metadata annotations and mount Swagger UI route.
.releaserc Add semantic-release configuration.
.husky/pre-commit Add pre-commit hook.
.husky/commit-msg Add commit-msg hook for commitlint.
.gitignore Ignore root node_modules and Playwright output directories.
.github/workflows/ci.yml Add security job, sqlc diff check, E2E job, and release job.
Comments suppressed due to low confidence (1)

.github/workflows/ci.yml:145

  • The release job uses @semantic-release/github with GITHUB_TOKEN, but the workflow does not declare any permissions. On newer GitHub defaults, GITHUB_TOKEN is read-only and semantic-release will fail to create releases/tags without contents: write (and often issues/pull-requests: write). Consider adding an explicit permissions: block (workflow-wide or for the release job).
  release:
    needs: [security, build, e2e]
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install semantic-release
        run: npm install -g semantic-release @semantic-release/commit-analyzer @semantic-release/release-notes-generator @semantic-release/github

      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: semantic-release


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/cmd/server/main.go Outdated
Comment on lines +122 to +127
// Swagger UI
app.Get("/swagger/*", swagger.New(swagger.Config{
BasePath: "/",
FilePath: "docs/swagger/swagger.json",
Path: "/swagger",
}))
Comment thread Makefile Outdated
cd backend && sqlc generate

e2e:
npx playwright test --config e2e/playwright.config.ts
Comment on lines +9 to +16
-- name: ListBlogPosts :many
SELECT id, title, slug, content, excerpt, cover_image, status, author_id, created_at, published_at, metadata
FROM blog_posts
WHERE ($1 = '' OR status = $1)
ORDER BY created_at DESC LIMIT $2 OFFSET $3;

-- name: CountBlogPosts :one
SELECT COUNT(*) FROM blog_posts WHERE ($1 = '' OR status = $1);
Comment on lines +6 to +15
SELECT id, name, description, price, stock, is_pre_sale, pre_sale_available_at, images, category_id, is_active, created_at, updated_at
FROM products
WHERE ($1::uuid IS NULL OR category_id = $1)
AND ($2 = false OR is_active = true)
ORDER BY created_at DESC LIMIT $3 OFFSET $4;

-- name: CountProducts :one
SELECT COUNT(*) FROM products
WHERE ($1::uuid IS NULL OR category_id = $1)
AND ($2 = false OR is_active = true);
@afa7789
Copy link
Copy Markdown
Owner Author

afa7789 commented May 8, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 8, 2026

@copilot apply changes based on the comments in this thread

Applied the requested review-thread changes in commit f49f095.

  • Swagger now serves from embedded/generated spec content at runtime (no filesystem dependency).
  • make e2e now runs via frontend toolchain (cd frontend && bun run e2e) to use pinned Playwright.
  • sqlc query params were explicitly cast ($1::text, $2::boolean) and generated sqlc types were updated accordingly.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 127.0.0.11
    • Triggering command: REDACTED, pid is -1 (packet block)
  • grafana.com
    • Triggering command: /usr/share/grafana/bin/grafana grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning mpile pkg/mod/golang.o/usr/local/go/src/crypto/x509/cert_pool.go 2410�� ae69c1b1:Makefile mpile sh -p uXNTOwq6krh3J/vx/usr/local/bin/docker-entrypoint.sh l/linux_amd64/copostgres 2410614/b387/importcfg (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of afa7789 May 8, 2026 17:01
@afa7789
Copy link
Copy Markdown
Owner Author

afa7789 commented May 8, 2026

@copilot consegue arrumar os erros de CI/CD não, ia ser interessante:
CI / build (pull_request)
CI / build (pull_request)Failing after 3m
CI / e2e (pull_request)
CI / e2e (pull_request)Failing after 1m
CI / security (pull_request)
CI / security (pull_request)Failing after 41s

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

Caution

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

⚠️ Outside diff range comments (4)
backend/internal/handlers/blog.go (1)

455-562: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

OpenAI API endpoint and request structure do not match documented patterns.

The implementation uses https://api.openai.com/v1/responses (line 512), which is not the standard Chat Completions endpoint (/v1/chat/completions). The request structure also deviates: it uses input instead of messages, and expects output_text in the response instead of choices. The model name "gpt-5.4-mini" (line 455) does not match documented OpenAI model naming.

While OpenAI's Responses API exists as a newer interface, the request format here (with text.format.json_schema, role "developer", and input_text types) does not align with standard patterns. The README explicitly marks AI content generation as an "OpenAI placeholder," indicating this implementation is incomplete.

Clarify which OpenAI API version/endpoint this should use, or update the implementation to match the intended API spec. If this is intentionally experimental, add documentation explaining the deviation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/blog.go` around lines 455 - 562, The handler uses a
mismatched OpenAI contract: it posts to "https://api.openai.com/v1/responses"
with a custom payload (model "gpt-5.4-mini", "input" array, and
"text.format.json_schema") but then parses a Chat-style response
("output_text"/"output" instead of "choices"), causing incompatibility; decide
whether to target the Responses API or Chat Completions API, then update the
request and parsing accordingly — if you choose Chat Completions, replace the
payload to use "messages" (roles + content), use a valid model name, POST to
"/v1/chat/completions" and parse "choices[].message.content"; if you choose
Responses, align the payload to Responses API docs (use "input" as string or
appropriate array, correct "modalities"/"format" usage) and parse the official
Responses fields (not "output_text"/"output"); also update the model string
("gpt-5.4-mini") to a documented model or document the experimental choice.
Ensure consistency between the payload creation (the variable building the
payload) and the response unmarshalling (the anonymous struct using
OutputText/Output).
backend/internal/handlers/coupon.go (2)

100-108: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid shipping a documented DELETE coupon endpoint that is hardcoded to fail.

This creates a guaranteed-failure API surface (/admin/coupons/{id}) and misleading Swagger docs. Either implement deletion in the repository layer or remove the route/docs until it exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/coupon.go` around lines 100 - 108, The
AdminDeleteCoupon handler is exposing a documented DELETE endpoint but always
returns MethodNotAllowed; either implement deletion in the repository or remove
the route/docs—add a Delete(ctx, id) (or similar) method to CouponRepository and
have CouponHandler.AdminDeleteCoupon parse the coupon id from fiber.Ctx and call
that repository Delete, returning appropriate 200/204 or 404/500 responses, or
if deletion is not supported remove the swagger comment block and the route
registration so AdminDeleteCoupon is not advertised. Ensure you update
references to CouponRepository and AdminDeleteCoupon accordingly.

31-58: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject negative subtotal before validation/discount logic.

A negative subtotal can produce invalid discount/final totals and should be treated as bad input.

Suggested guard
 if err := c.BodyParser(&req); err != nil {
 	return fiber.NewError(fiber.StatusBadRequest, "invalid body")
 }
 if req.Code == "" {
 	return fiber.NewError(fiber.StatusBadRequest, "code required")
 }
+if req.Subtotal < 0 {
+	return fiber.NewError(fiber.StatusBadRequest, "subtotal must be non-negative")
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/coupon.go` around lines 31 - 58, Before any coupon
validation logic, add a guard to reject negative request subtotals: after
parsing the body (the c.BodyParser(&req) block) validate req.Subtotal and return
a fiber.BadRequest error if req.Subtotal is less than 0. Place this check before
using req.Subtotal in downstream checks (e.g., the MinPurchase comparison) so
functions/methods like h.coupons.FindByCode and the coupon.* validations never
run with a negative subtotal; use the same error style (fiber.NewError with
fiber.StatusBadRequest and an explanatory message).
Makefile (1)

1-7: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add e2e to .PHONY to avoid target/file collisions.

e2e (Line 135) is invokable but not declared phony, so a same-named file can suppress execution.

Suggested patch
 .PHONY: up down logs backend frontend build deploy ngrok \
 	test test-backend test-frontend \
 	lint lint-backend lint-frontend \
 	fmt fmt-backend fmt-frontend \
 	typecheck tidy vet \
 	deadcode deadcode-backend deadcode-frontend \
-	vulncheck swagger sqlc check ci clean help
+	vulncheck swagger sqlc e2e check ci clean help

Also applies to: 135-136

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 1 - 7, The Makefile's .PHONY list is missing the e2e
target, so a file named "e2e" could block the target; update the .PHONY
declaration to include "e2e" (add e2e to the existing .PHONY line that currently
lists up down logs backend frontend ... help) so the e2e target (defined later)
is always treated as phony and cannot be shadowed by a file.
🧹 Nitpick comments (6)
renovate.json (1)

10-13: ⚡ Quick win

Consider restricting automerge for devDependencies to non-major updates.

The current configuration will automerge all devDependencies updates, including major version bumps. Major updates in dev tools (linters, test frameworks, build tools) can introduce breaking changes that require code modifications.

🔧 Suggested refinement
   {
     "matchDepTypes": ["devDependencies"],
+    "matchUpdateTypes": ["minor", "patch"],
     "automerge": true
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@renovate.json` around lines 10 - 13, The current rule enables "automerge":
true for all "matchDepTypes": ["devDependencies"] including majors; change it to
a packageRules entry that only automerges non-major updates by replacing the
simple object with a "packageRules" array and an entry like { "matchDepTypes":
["devDependencies"], "matchUpdateTypes": ["minor","patch"], "automerge": true }
so major updates remain manual; update the JSON to use "packageRules" and
"matchUpdateTypes" alongside the existing keys ("matchDepTypes" and "automerge")
to scope automerge to patch/minor only.
backend/internal/handlers/user.go (1)

73-79: ⚡ Quick win

Consider adding response schema documentation.

The @Success annotation is missing response type documentation. Adding @Success 200 {object} profileResponse would provide complete API documentation and improve the generated Swagger spec.

📝 Suggested enhancement
 // UpdateProfile godoc
 // `@Summary`     Update user profile
 // `@Tags`        User
 // `@Accept`      json
 // `@Produce`     json
+// `@Success`     200 {object} profileResponse
 // `@Security`    BearerAuth
 // `@Router`      /user/profile [put]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/user.go` around lines 73 - 79, The OpenAPI comment
block for the UpdateProfile handler is missing a success response schema; update
the handler comment (the block above UpdateProfile) to include a `@Success` line
such as "@Success 200 {object} profileResponse" and ensure a corresponding
profileResponse type (struct) exists and is documented so the Swagger generator
can include the response schema for UpdateProfile.
e2e/basic.spec.ts (1)

8-11: ⚡ Quick win

Strengthen frontend smoke assertion beyond <body> visibility.

body being visible is too permissive and can pass on broken/error pages. At minimum, assert successful navigation response plus one app-specific UI marker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/basic.spec.ts` around lines 8 - 11, The test "frontend loads" is too
weak—replace the single body visibility check with two stronger assertions:
capture the result of page.goto('/') (using the returned Response from
page.goto) and assert the navigation succeeded (response exists and status <
400), and then assert an application-specific UI marker is present (use
page.locator with a stable selector such as a data-test-id or a unique visible
text, e.g., the app root or welcome heading) instead of just 'body'; update the
test function test('frontend loads', async ({ page }) => { ... }) to perform
both checks via page.goto and page.locator/expect.
backend/internal/handlers/legal.go (1)

93-99: ⚡ Quick win

Document the {id} path parameter and response types for admin update/delete routes.

Both /admin/legal/{id} endpoints are missing explicit documentation for the path parameter and response types, resulting in incomplete OpenAPI specs. Add @Param id path string true "Legal page ID" and @Success annotations to both the AdminUpdate and AdminDelete functions.

Suggested annotation patch
 // AdminUpdate godoc
 // `@Summary`     Update a legal page (admin)
 // `@Tags`        Admin
 // `@Accept`      json
 // `@Produce`     json
 // `@Security`    BearerAuth
+// `@Param`       id path string true "Legal page ID"
+// `@Success`     200 {object} domain.LegalPage
 // `@Router`      /admin/legal/{id} [put]

 // AdminDelete godoc
 // `@Summary`     Delete a legal page (admin)
 // `@Tags`        Admin
 // `@Security`    BearerAuth
+// `@Param`       id path string true "Legal page ID"
+// `@Success`     200 {object} map[string]bool
 // `@Router`      /admin/legal/{id} [delete]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/legal.go` around lines 93 - 99, Add OpenAPI
annotations to the admin update/delete handlers: in the godoc comment blocks for
AdminUpdate and AdminDelete, add a path parameter annotation `@Param id path
string true "Legal page ID"` and appropriate `@Success` annotations indicating
the response type(s) (e.g., `@Success 200 {object} models.Legal` for a
successful update and `@Success 204` or `@Success 200 {object} models.Message`
for delete as appropriate). Place these annotations alongside the existing
`@Summary`, `@Tags`, `@Accept`, `@Produce`, `@Security`, and `@Router` lines so
the OpenAPI generator picks up the `{id}` param and response schemas.
backend/internal/infrastructure/sqlc/products.sql.go (1)

20-23: ⚡ Quick win

Name query args in SQL to generate clearer params than Column1/Column2

Lines 20-23 and 115-120 expose ambiguous generated fields, which makes call sites error-prone. Define named args in backend/internal/infrastructure/sqlc/queries/products.sql (e.g., sqlc.arg(category_id), sqlc.arg(active_only)) and regenerate.

Suggested source-query change (then re-run sqlc)
-WHERE ($1::uuid IS NULL OR category_id = $1)
-  AND ($2::boolean = false OR is_active = true)
+WHERE (sqlc.arg(category_id)::uuid IS NULL OR category_id = sqlc.arg(category_id))
+  AND (sqlc.arg(active_only)::boolean = false OR is_active = true)

-ORDER BY created_at DESC LIMIT $3 OFFSET $4
+ORDER BY created_at DESC
+LIMIT sqlc.arg(limit) OFFSET sqlc.arg(offset)

Also applies to: 115-120

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/infrastructure/sqlc/products.sql.go` around lines 20 - 23,
The generated param struct CountProductsParams (fields Column1 and Column2) is
ambiguous; update the SQL file
backend/internal/infrastructure/sqlc/queries/products.sql to use explicit sqlc
argument names (e.g., replace anonymous args with sqlc.arg(category_id) and
sqlc.arg(active_only) or similarly descriptive names used in the query), then
re-run sqlc to regenerate the Go types so the struct and any other occurrences
(including the other instance around lines 115-120) become meaningful (e.g.,
CategoryID, ActiveOnly) and update call sites to use the new field names.
backend/internal/infrastructure/sqlc/blog_posts.sql.go (1)

18-18: ⚡ Quick win

Use named sqlc arguments to avoid placeholder param names in generated API

Line 18 (dollar_1) and Lines 129-133 (Column1) make the generated methods harder to use safely. Prefer naming parameters in backend/internal/infrastructure/sqlc/queries/blog_posts.sql (e.g., sqlc.arg(status)), then regenerate to get semantic fields/method params.

Suggested source-query change (then re-run sqlc)
-SELECT COUNT(*) FROM blog_posts WHERE ($1::text = '' OR status = $1::text)
+SELECT COUNT(*) FROM blog_posts
+WHERE (sqlc.arg(status)::text = '' OR status = sqlc.arg(status)::text)

-WHERE ($1::text = '' OR status = $1::text)
-ORDER BY created_at DESC LIMIT $2 OFFSET $3
+WHERE (sqlc.arg(status)::text = '' OR status = sqlc.arg(status)::text)
+ORDER BY created_at DESC
+LIMIT sqlc.arg(limit) OFFSET sqlc.arg(offset)

Also applies to: 129-133

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/infrastructure/sqlc/blog_posts.sql.go` at line 18, The
generated methods use anonymous placeholders (dollar_1 in CountBlogPosts and
Column1 fields) because the SQL query lacks named sqlc arguments; edit the
source SQL in backend/internal/infrastructure/sqlc/queries/blog_posts.sql to use
named arguments (e.g., sqlc.arg(status) or sqlc.arg(your_param_name) in the
WHERE/VALUES), then re-run sqlc to regenerate the Go code so the generated
method signatures and struct fields use semantic names instead of
dollar_1/Column1 (target symbols: CountBlogPosts and any generated Column1
types).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 97-103: The "Wait for health" step currently loops against
/healthz but can silently continue if the endpoint never becomes healthy; change
the step so the loop fails fast when retries are exhausted by returning a
non-zero exit code. Update the for-loop logic in the "Wait for health" step (the
block using for i in $(seq 1 30) and curl -s http://localhost/healthz) to detect
success and, if no successful probe occurred after all retries, print a clear
error (e.g. "health check failed: /healthz not ready") and exit 1 so the
workflow stops immediately on a persistent health failure.
- Around line 67-69: The CI installs sqlc using a floating tag ("sqlc@latest"),
which makes builds non-deterministic; update the workflow to pin sqlc to the
specific version that matches the checked-in generated code (replace the "go
install github.com/sqlc-dev/sqlc/cmd/sqlc@latest" step with a fixed version like
"sqlc@vX.Y.Z"), ensuring the sqlc diff check remains but uses the pinned release
so CI is deterministic; verify the chosen version is the one that generated the
committed code before committing.

In `@backend/cmd/server/main.go`:
- Around line 123-129: The swagger route is being registered unconditionally
(app.Get("/swagger/*", swagger.New(...))) which exposes API schema in prod; wrap
the registration in an environment check (e.g., if !isProd or config.Environment
!= "production") or register it behind an admin-auth middleware (e.g., use
existing requireAdmin or create an adminAuth middleware) so the swagger endpoint
is only available in non-production or to authenticated admins; update the code
that calls swagger.New and uses swaggerdocs.SwaggerInfo.ReadDoc() accordingly to
only run when the env check passes or when the route is protected.

In `@backend/docs/swagger/swagger.yaml`:
- Around line 17-20: OpenAPI schema wrongly documents byte/JSON fields (e.g.,
metadata, shipping_address, images, address) as array<integer>, breaking SDKs;
to fix, update the Go struct definitions to add swaggertype:"string" tags on the
[]byte fields (e.g., the fields named metadata, shipping_address, images,
address) so swaggo generates them as string in the swagger.yaml, or if you
cannot edit the structs, create a .swaggo overrides file containing a
replacement rule mapping []byte to string and pass that file to swaggo via
--overridesFile when regenerating the docs; regenerate the swagger.yaml after
applying one of these changes.

In `@backend/internal/handlers/waitlist.go`:
- Line 21: The Swagger `@Param` inline object syntax must be replaced with named
request structs: create a WaitlistRequest struct with fields Email string
`json:"email"` and Name string `json:"name,omitempty"`, and a
SecurityUpdateRequest (or SecurityRequest) struct with field Value string
`json:"value"`, then update the `@Param` annotations that currently use
object{email=string,name=string} and object{value=string} to reference these
types (e.g., `@Param` body body WaitlistRequest true "Email and optional name" and
`@Param` body body SecurityUpdateRequest true "...") so swaggo/swag can generate
proper schemas; ensure the handler functions that expect these bodies (the
waiter handler and the security update handler) use or bind to the new structs.

In `@backend/internal/infrastructure/sqlc/queries/users.sql`:
- Around line 21-23: ListUsers currently selects password_hash; remove
password_hash from the SELECT projection in the ListUsers query (the SQL
statement named ListUsers) so it returns id, email, name, role, email_verified,
email_verified_at, stripe_customer_id, created_at, updated_at only, then re-run
sqlc/codegen and update any call sites expecting password_hash on the generated
ListUsers result type (e.g., repository/ListUsers methods) to use the new shape;
ensure no logging or downstream handlers access password_hash from ListUsers
results.

In `@e2e/basic.spec.ts`:
- Around line 3-6: The test named "health endpoint returns 200" currently uses
expect(res.ok()).toBeTruthy(), which accepts any 2xx; change the assertion to
check the exact status code by using the response object `res` returned from
`request.get('/healthz')` and assert `res.status()` equals 200 (i.e., replace
the `res.ok()` assertion with an explicit `res.status() === 200` check).

---

Outside diff comments:
In `@backend/internal/handlers/blog.go`:
- Around line 455-562: The handler uses a mismatched OpenAI contract: it posts
to "https://api.openai.com/v1/responses" with a custom payload (model
"gpt-5.4-mini", "input" array, and "text.format.json_schema") but then parses a
Chat-style response ("output_text"/"output" instead of "choices"), causing
incompatibility; decide whether to target the Responses API or Chat Completions
API, then update the request and parsing accordingly — if you choose Chat
Completions, replace the payload to use "messages" (roles + content), use a
valid model name, POST to "/v1/chat/completions" and parse
"choices[].message.content"; if you choose Responses, align the payload to
Responses API docs (use "input" as string or appropriate array, correct
"modalities"/"format" usage) and parse the official Responses fields (not
"output_text"/"output"); also update the model string ("gpt-5.4-mini") to a
documented model or document the experimental choice. Ensure consistency between
the payload creation (the variable building the payload) and the response
unmarshalling (the anonymous struct using OutputText/Output).

In `@backend/internal/handlers/coupon.go`:
- Around line 100-108: The AdminDeleteCoupon handler is exposing a documented
DELETE endpoint but always returns MethodNotAllowed; either implement deletion
in the repository or remove the route/docs—add a Delete(ctx, id) (or similar)
method to CouponRepository and have CouponHandler.AdminDeleteCoupon parse the
coupon id from fiber.Ctx and call that repository Delete, returning appropriate
200/204 or 404/500 responses, or if deletion is not supported remove the swagger
comment block and the route registration so AdminDeleteCoupon is not advertised.
Ensure you update references to CouponRepository and AdminDeleteCoupon
accordingly.
- Around line 31-58: Before any coupon validation logic, add a guard to reject
negative request subtotals: after parsing the body (the c.BodyParser(&req)
block) validate req.Subtotal and return a fiber.BadRequest error if req.Subtotal
is less than 0. Place this check before using req.Subtotal in downstream checks
(e.g., the MinPurchase comparison) so functions/methods like
h.coupons.FindByCode and the coupon.* validations never run with a negative
subtotal; use the same error style (fiber.NewError with fiber.StatusBadRequest
and an explanatory message).

In `@Makefile`:
- Around line 1-7: The Makefile's .PHONY list is missing the e2e target, so a
file named "e2e" could block the target; update the .PHONY declaration to
include "e2e" (add e2e to the existing .PHONY line that currently lists up down
logs backend frontend ... help) so the e2e target (defined later) is always
treated as phony and cannot be shadowed by a file.

---

Nitpick comments:
In `@backend/internal/handlers/legal.go`:
- Around line 93-99: Add OpenAPI annotations to the admin update/delete
handlers: in the godoc comment blocks for AdminUpdate and AdminDelete, add a
path parameter annotation `@Param id path string true "Legal page ID"` and
appropriate `@Success` annotations indicating the response type(s) (e.g.,
`@Success 200 {object} models.Legal` for a successful update and `@Success 204`
or `@Success 200 {object} models.Message` for delete as appropriate). Place
these annotations alongside the existing `@Summary`, `@Tags`, `@Accept`,
`@Produce`, `@Security`, and `@Router` lines so the OpenAPI generator picks up
the `{id}` param and response schemas.

In `@backend/internal/handlers/user.go`:
- Around line 73-79: The OpenAPI comment block for the UpdateProfile handler is
missing a success response schema; update the handler comment (the block above
UpdateProfile) to include a `@Success` line such as "@Success 200 {object}
profileResponse" and ensure a corresponding profileResponse type (struct) exists
and is documented so the Swagger generator can include the response schema for
UpdateProfile.

In `@backend/internal/infrastructure/sqlc/blog_posts.sql.go`:
- Line 18: The generated methods use anonymous placeholders (dollar_1 in
CountBlogPosts and Column1 fields) because the SQL query lacks named sqlc
arguments; edit the source SQL in
backend/internal/infrastructure/sqlc/queries/blog_posts.sql to use named
arguments (e.g., sqlc.arg(status) or sqlc.arg(your_param_name) in the
WHERE/VALUES), then re-run sqlc to regenerate the Go code so the generated
method signatures and struct fields use semantic names instead of
dollar_1/Column1 (target symbols: CountBlogPosts and any generated Column1
types).

In `@backend/internal/infrastructure/sqlc/products.sql.go`:
- Around line 20-23: The generated param struct CountProductsParams (fields
Column1 and Column2) is ambiguous; update the SQL file
backend/internal/infrastructure/sqlc/queries/products.sql to use explicit sqlc
argument names (e.g., replace anonymous args with sqlc.arg(category_id) and
sqlc.arg(active_only) or similarly descriptive names used in the query), then
re-run sqlc to regenerate the Go types so the struct and any other occurrences
(including the other instance around lines 115-120) become meaningful (e.g.,
CategoryID, ActiveOnly) and update call sites to use the new field names.

In `@e2e/basic.spec.ts`:
- Around line 8-11: The test "frontend loads" is too weak—replace the single
body visibility check with two stronger assertions: capture the result of
page.goto('/') (using the returned Response from page.goto) and assert the
navigation succeeded (response exists and status < 400), and then assert an
application-specific UI marker is present (use page.locator with a stable
selector such as a data-test-id or a unique visible text, e.g., the app root or
welcome heading) instead of just 'body'; update the test function test('frontend
loads', async ({ page }) => { ... }) to perform both checks via page.goto and
page.locator/expect.

In `@renovate.json`:
- Around line 10-13: The current rule enables "automerge": true for all
"matchDepTypes": ["devDependencies"] including majors; change it to a
packageRules entry that only automerges non-major updates by replacing the
simple object with a "packageRules" array and an entry like { "matchDepTypes":
["devDependencies"], "matchUpdateTypes": ["minor","patch"], "automerge": true }
so major updates remain manual; update the JSON to use "packageRules" and
"matchUpdateTypes" alongside the existing keys ("matchDepTypes" and "automerge")
to scope automerge to patch/minor only.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ebebfc13-3c39-4573-b7c2-16b2a611e79f

📥 Commits

Reviewing files that changed from the base of the PR and between 923bfc2 and f49f095.

⛔ Files ignored due to path filters (3)
  • backend/go.sum is excluded by !**/*.sum
  • frontend/bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (42)
  • .github/workflows/ci.yml
  • .gitignore
  • .releaserc
  • Makefile
  • backend/cmd/server/main.go
  • backend/docs/swagger/docs.go
  • backend/docs/swagger/swagger.json
  • backend/docs/swagger/swagger.yaml
  • backend/go.mod
  • backend/internal/handlers/admin.go
  • backend/internal/handlers/auth.go
  • backend/internal/handlers/blog.go
  • backend/internal/handlers/coupon.go
  • backend/internal/handlers/envconfig.go
  • backend/internal/handlers/handler.go
  • backend/internal/handlers/jobs.go
  • backend/internal/handlers/legal.go
  • backend/internal/handlers/payment.go
  • backend/internal/handlers/security.go
  • backend/internal/handlers/store.go
  • backend/internal/handlers/tools.go
  • backend/internal/handlers/user.go
  • backend/internal/handlers/waitlist.go
  • backend/internal/infrastructure/sqlc/blog_posts.sql.go
  • backend/internal/infrastructure/sqlc/categories.sql.go
  • backend/internal/infrastructure/sqlc/db.go
  • backend/internal/infrastructure/sqlc/models.go
  • backend/internal/infrastructure/sqlc/products.sql.go
  • backend/internal/infrastructure/sqlc/querier.go
  • backend/internal/infrastructure/sqlc/queries/blog_posts.sql
  • backend/internal/infrastructure/sqlc/queries/categories.sql
  • backend/internal/infrastructure/sqlc/queries/products.sql
  • backend/internal/infrastructure/sqlc/queries/users.sql
  • backend/internal/infrastructure/sqlc/users.sql.go
  • backend/sqlc.yaml
  • commitlint.config.js
  • e2e/basic.spec.ts
  • e2e/playwright.config.ts
  • frontend/package.json
  • lefthook.yml
  • package.json
  • renovate.json

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread backend/cmd/server/main.go Outdated
Comment thread backend/docs/swagger/swagger.yaml Outdated
Comment thread backend/internal/handlers/waitlist.go Outdated
Comment thread backend/internal/infrastructure/sqlc/queries/users.sql
Comment thread frontend/e2e/basic.spec.ts
Copy link
Copy Markdown
Contributor

Copilot AI commented May 8, 2026

@copilot consegue arrumar os erros de CI/CD não, ia ser interessante:
CI / build (pull_request)
CI / build (pul...

Consegui sim — corrigi os 3 pontos de CI/CD no commit 2d0570f.

  • build: corrigi formatação gofmt em backend/internal/handlers/blog.go.
  • e2e: corrigi erro de permissão (EACCES em frontend/node_modules) e passei a rodar E2E via dependência fixada do frontend (cd frontend && bun run e2e).
  • security: atualizei patch do Go no workflow (1.25.10) e dependências Go relevantes (incluindo Fiber/go-openapi) para reduzir falhas no govulncheck.

Não houve alteração de UI neste ajuste, então não há screenshot aplicável.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 127.0.0.11
    • Triggering command: REDACTED, pid is -1 (packet block)
  • grafana.com
    • Triggering command: /usr/share/grafana/bin/grafana grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning mpile rtcfg -p 9456c275:backend/go.mod om/valyala/fasthttp@v1.51.0/fast/tmp/go-build2369928219/b091/ pkg/mod/golang.org/toolchain@v0.-I -I sessions/70fc17a/usr/bin/runc mpile pkg/mod/golang.o/var/run/docker/runtime-runc/moby (dns block)
  • vuln.go.dev
    • Triggering command: /home/REDACTED/go/bin/govulncheck /home/REDACTED/go/bin/govulncheck ./... (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of afa7789 May 8, 2026 17:11
afa7789 added 4 commits May 9, 2026 21:01
… and improve error handling

- Updated sqlc dependency version in CI workflow to v1.31.1.
- Improved health check logic in CI workflow to provide clearer failure messages.
- Modified E2E test command to run from the frontend directory.
- Adjusted paths for uploading Playwright reports in CI workflow.
- Added Swagger UI endpoint conditionally based on environment.
- Enhanced Swagger documentation with parameters and response schemas for various endpoints.
- Updated entity definitions to include swaggertype annotations for JSON fields.
- Implemented Delete method in CouponRepository and corresponding handler for coupon deletion.
- Refactored AI generation logic in blog handler to align with OpenAI API changes.
- Added validation for subtotal in coupon validation handler.
- Updated user and product SQL queries to improve filtering and pagination.
- Added new request structs for security and waitlist handlers.
- Improved E2E tests for health endpoint and frontend loading.
- Adjusted frontend package.json for Playwright configuration.
- Created a new Playwright configuration file for better test management.
- Updated Renovate configuration to automate minor and patch updates for devDependencies.
- move e2e/basic.spec.ts into frontend/e2e/ so @playwright/test resolves
- update frontend/playwright.config.ts testDir to ./e2e and bump webServer timeout
- simplify e2e CI job: let playwright manage docker compose via webServer
- add backend healthcheck and make nginx depends_on backend service_healthy
- add nginx healthcheck for compose --wait readiness
- vitest: exclude e2e/** so playwright specs are not picked up
- backend healthcheck: use 127.0.0.1 (localhost resolved to ::1 inside the
  container, but Fiber listens on IPv4 only — caused 180s healthcheck timeout)
- nginx healthcheck: same IPv4 fix
- nginx depends_on: drop pgweb/grafana/prometheus from the readiness path
  (they are not needed for /healthz and slowed down --wait)
- playwright: bump webServer timeout to 300s for CI cold starts
- e2e/basic.spec.ts: use #app.first() — the page renders two #app elements
  (mount target + App.vue template root), so a bare locator is ambiguous

Verified locally: docker compose up -d --wait → all healthy in ~33s,
playwright run → 2/2 passing.
@afa7789 afa7789 merged commit 5a574d1 into main May 10, 2026
5 checks passed
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