Skip to content

feat: VPN batch version#639

Open
OneLastChanc3 wants to merge 3 commits into
bobadilla-tech:mainfrom
OneLastChanc3:vpn-batch
Open

feat: VPN batch version#639
OneLastChanc3 wants to merge 3 commits into
bobadilla-tech:mainfrom
OneLastChanc3:vpn-batch

Conversation

@OneLastChanc3
Copy link
Copy Markdown
Contributor

@OneLastChanc3 OneLastChanc3 commented May 18, 2026

  • add POST /v1/networking/ip/vpn/batch endpoint
  • support VPN/proxy/Tor detection for multiple IPs in a single request (max 50)
    -add testing for service and transport_http
    -add documentation

Summary by CodeRabbit

  • New Features

    • Added batch IP detection endpoint for VPN/proxy checking, allowing simultaneous verification of up to 50 IP addresses per request with results in input order.
  • Documentation

    • Updated API specifications and documentation with complete details for the batch endpoint, including request validation rules and response field definitions.

Review Change Stack

@OneLastChanc3 OneLastChanc3 requested a review from a team as a code owner May 18, 2026 07:02
@OneLastChanc3 OneLastChanc3 requested a review from crydafan May 18, 2026 07:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

📝 Walkthrough

Walkthrough

This PR adds a batch endpoint (POST /v1/networking/ip/vpn/batch) to the VPN IP detection service. The implementation includes request/response types with validation, a concurrent batch-checking method in the service layer, HTTP transport wiring, comprehensive test coverage, and API documentation across dashboard configs and user-facing docs.

Changes

Batch VPN/Proxy Detection Feature

Layer / File(s) Summary
Batch request/response types
apps/api/services/networking/ip/vpn/type.go
BatchRequest and BatchResponse structures with IsData() marker methods added for type safety and validation constraints (max 50 IPs).
Service batch implementation and unit tests
apps/api/services/networking/ip/vpn/service.go, apps/api/services/networking/ip/vpn/service_test.go
CheckBatch method spawns concurrent goroutines to parse and check each IP, aggregates results while preserving input order, handles invalid IPs by returning zeroed fields. Three test functions validate result count, input order preservation, and handling of invalid/empty IP entries.
HTTP endpoint registration and integration tests
apps/api/services/networking/ip/vpn/transport_http.go, apps/api/services/networking/ip/vpn/transport_http_test.go
POST /ip/vpn/batch route registered via httpx.HandleBatch, passes request to CheckBatch, and returns batch response. Six HTTP tests cover happy path with mixed IPv4/IPv6, JSON validation, empty input rejection, invalid IP handling, order preservation, and 50-IP size limit enforcement.
API catalog and documentation
apps/dashboard/config/api_catalog.yml, apps/dashboard/config/api_docs/vpn-detection.yml, docs/apis/places/timezone.md
Endpoint count incremented to 2 in catalog. Batch endpoint documented in API schema with request body, per-IP response fields (detection booleans, threat scores, ASN org), error cases, and operational notes. User-facing docs added with example request/response and validation rules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • crydafan

Poem

🐰 In the burrow of batches, a rabbit did code,
Fifty IPs checked on a concurrent road,
Order preserved like carrots in rows,
VPN detection flows where the batch goes! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: VPN batch version' directly describes the main change—adding batch VPN/proxy detection functionality across multiple files and a new endpoint.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch vpn-batch

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

Codecov Report

❌ Patch coverage is 0% with 47 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
apps/api/services/networking/ip/vpn/service.go 0.00% 33 Missing ⚠️
...s/api/services/networking/ip/vpn/transport_http.go 0.00% 13 Missing ⚠️
apps/api/services/networking/ip/vpn/type.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@UltiRequiem UltiRequiem changed the title Vpn batch feat: VPN batch version May 18, 2026

httpx.JSON(w, http.StatusOK, result)
}))
r.Post("/ip/vpn/batch", httpx.Guard(svc, func(w http.ResponseWriter, r *http.Request) {
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.

r.Post("/ip/vpn/batch", httpx.Guard(svc, func(w http.ResponseWriter, r *http.Request) {
var req BatchRequest

if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
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.

Use struct validation, do not manually validate here

@UltiRequiem
Copy link
Copy Markdown
Member

@copilot resolve the merge conflicts in this pull request

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

🤖 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 `@apps/api/services/networking/ip/vpn/service.go`:
- Around line 64-73: The current batch worker converts all errors from s.CheckIP
into a fallback item (item / IPCheckResponse), which swallows systemic context
errors; change the error handling in the goroutine that calls s.CheckIP so that
if err is context.Canceled or context.DeadlineExceeded (or ctx.Err() != nil) you
propagate that as a top-level error instead of sending an item fallback (e.g.,
return a sentinel via an error channel or set a shared error variable),
otherwise continue sending the fallback item for non-context errors; also, in
the fan-in/collector section that aggregates results, check ctx.Err() (or the
error channel) before returning the final success payload and surface ctx.Err()
as the returned error when present.

In `@apps/api/services/networking/ip/vpn/type.go`:
- Line 38: The struct tag on BatchRequest.IPs currently enforces per-item
validation (`dive,required,ip`) causing BindAndValidate to reject requests with
any malformed IP; update the tag to only validate the slice itself (e.g. change
`validate:"required,min=1,max=50,dive,required,ip"` to
`validate:"required,min=1,max=50,dive"`) so malformed or empty IP strings pass
initial binding and svc.CheckBatch can return per-item errors as intended;
modify the BatchRequest type's IPs field accordingly.

In `@apps/dashboard/config/api_docs/vpn-detection.yml`:
- Around line 145-193: The docs for the batch VPN detection response are missing
the data.total field returned by httpx.HandleBatch; update the response_example
JSON to include "total": <number> alongside "results" under "data", and add a
corresponding response_fields entry (name: total, type: integer, description:
Total number of input IPs / total results) so the OpenAPI example and field list
match the runtime behavior from HandleBatch.

In `@docs/apis/places/timezone.md`:
- Around line 166-189: The file contains duplicated sections titled "###
Response Fields" and "### Validation Rules" (including the table of fields like
`results`, `ip`, `is_vpn`, `score`, `fraud_score`, `asn_org`), causing MD024
lint warnings; remove the redundant duplicate block so only one copy of the "###
Response Fields" table and one "### Validation Rules" list remain, ensuring the
canonical section contains the full field list and validation bullets and that
any references to `results` or the validation constraints point to that single
section.
🪄 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: 01570c57-3064-4569-b0d3-414e680040a9

📥 Commits

Reviewing files that changed from the base of the PR and between ffac5a6 and 5b0761b.

📒 Files selected for processing (8)
  • apps/api/services/networking/ip/vpn/service.go
  • apps/api/services/networking/ip/vpn/service_test.go
  • apps/api/services/networking/ip/vpn/transport_http.go
  • apps/api/services/networking/ip/vpn/transport_http_test.go
  • apps/api/services/networking/ip/vpn/type.go
  • apps/dashboard/config/api_catalog.yml
  • apps/dashboard/config/api_docs/vpn-detection.yml
  • docs/apis/places/timezone.md

Comment on lines +64 to +73
result, err := s.CheckIP(ctx, ip)
if err != nil {
ch <- item{
index: index,
result: IPCheckResponse{
IP: raw,
},
}
return
}
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 | ⚡ Quick win

Don’t swallow systemic context errors in batch processing.

At Line 64-73, CheckIP errors are always converted to item fallbacks. For context.Canceled/context.DeadlineExceeded, this should return a top-level error instead of a successful batch payload.

🔧 Suggested adjustment
+import "errors"
...
-			result, err := s.CheckIP(ctx, ip)
+			result, err := s.CheckIP(ctx, ip)
 			if err != nil {
+				if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+					ch <- item{
+						index: index,
+						result: IPCheckResponse{}, // marker slot; handled after fan-in
+					}
+					return
+				}
 				ch <- item{
 					index: index,
 					result: IPCheckResponse{
 						IP: raw,
 					},
 				}
 				return
 			}

And in the fan-in section, surface ctx.Err() if set before returning success.

🤖 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 `@apps/api/services/networking/ip/vpn/service.go` around lines 64 - 73, The
current batch worker converts all errors from s.CheckIP into a fallback item
(item / IPCheckResponse), which swallows systemic context errors; change the
error handling in the goroutine that calls s.CheckIP so that if err is
context.Canceled or context.DeadlineExceeded (or ctx.Err() != nil) you propagate
that as a top-level error instead of sending an item fallback (e.g., return a
sentinel via an error channel or set a shared error variable), otherwise
continue sending the fallback item for non-context errors; also, in the
fan-in/collector section that aggregates results, check ctx.Err() (or the error
channel) before returning the final success payload and surface ctx.Err() as the
returned error when present.

func (IPCheckResponse) IsData() {}

type BatchRequest struct {
IPs []string `json:"ips" validate:"required,min=1,max=50,dive,required,ip"`
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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify request validation currently enforces per-item IP format
rg -n 'type BatchRequest|validate:"' apps/api/services/networking/ip/vpn/type.go

# Verify tests/documentation expect partial success with invalid IP items
rg -n 'TestVPN_Batch_InvalidIPs|StatusOK|invalid-ip|Response preserves input order|Invalid IPs are included' \
  apps/api/services/networking/ip/vpn/transport_http_test.go \
  apps/api/services/networking/ip/vpn/service_test.go \
  apps/dashboard/config/api_docs/vpn-detection.yml \
  docs/apis/places/timezone.md

Repository: bobadilla-tech/requiems-api

Length of output: 1864


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the batch HTTP handler and its validation/binding logic
fd -a "transport_http.go" apps/api/services/networking/ip/vpn -t f | head -n 20
rg -n "Batch|CheckBatch|validate|validator|Bind|Decode|json.NewDecoder|httpx\." apps/api/services/networking/ip/vpn/transport_http.go

# Find the service method implementing batch partial-success behavior
rg -n "CheckBatch|BatchRequest|BatchResponse|Invalid IP|invalid-ip" apps/api/services/networking/ip/vpn -S

# Inspect the BatchRequest/BatchResponse helpers to see intended semantics
sed -n '1,220p' apps/api/services/networking/ip/vpn/type.go

Repository: bobadilla-tech/requiems-api

Length of output: 4886


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the batch handler implementation in this file
sed -n '1,140p' apps/api/services/networking/ip/vpn/transport_http.go
sed -n '140,260p' apps/api/services/networking/ip/vpn/transport_http.go

# Inspect tests that cover invalid batch items (what HTTP status + payload they expect)
sed -n '240,420p' apps/api/services/networking/ip/vpn/transport_http_test.go
sed -n '80,260p' apps/api/services/networking/ip/vpn/service_test.go

# Locate httpx.HandleBatch implementation in the repo (or module cache if vendored)
# Prefer searching in repository first.
rg -n "func HandleBatch" -S . || true
rg -n "HandleBatch\\[" -S . || true

# If not found in-repo, try to locate in go/pkg/mod by searching workspace (may be slow but bounded by ripgrep).
rg -n "HandleBatch\\[" -S "$(go env GOPATH 2>/dev/null)/pkg/mod" 2>/dev/null | head -n 20 || true

Repository: bobadilla-tech/requiems-api

Length of output: 6772


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' apps/api/platform/httpx/handler.go
sed -n '220,420p' apps/api/platform/httpx/handler.go

rg -n "validator|validate:\"|go-playground/validator|Bind|Decode|Validate" apps/api/platform/httpx -S

ls -R apps/api/platform/httpx | head -n 50

Repository: bobadilla-tech/requiems-api

Length of output: 11143


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' apps/api/platform/httpx/validate.go
sed -n '1,220p' apps/api/platform/httpx/binding.go
sed -n '1,200p' apps/api/platform/httpx/errors.go

# Inspect how ValidationError maps to HTTP status/message
rg -n "func ValidationError" -S apps/api/platform/httpx
sed -n '1,120p' apps/api/platform/httpx/errors.go

Repository: bobadilla-tech/requiems-api

Length of output: 5271


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect how test router is constructed / how HandleBatch is wired
sed -n '1,120p' apps/api/services/networking/ip/vpn/transport_http_test.go

# Inspect httpx.ValidationError mapping to status code
sed -n '1,120p' apps/api/platform/httpx/httpx.go

# Confirm BatchRequest validation tags in type.go (entire file small)
cat apps/api/services/networking/ip/vpn/type.go

Repository: bobadilla-tech/requiems-api

Length of output: 7419


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Run only the VPN batch invalid-IP HTTP test to see actual status code
go test ./apps/api/services/networking/ip/vpn -run '^TestVPN_Batch_InvalidIPs$' -count=1

# Also run the service-level invalid IP test (should not depend on request validation)
go test ./apps/api/services/networking/ip/vpn -run '^TestService_CheckBatch_InvalidIPs$' -count=1

Repository: bobadilla-tech/requiems-api

Length of output: 189


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ls
find . -maxdepth 4 -name "go.mod" -o -name "go.work" | sed 's|^\./||'
find . -maxdepth 3 -type f -name "go.mod" -print -exec sh -c 'echo "----"; cat {} | head -n 20' \;

Repository: bobadilla-tech/requiems-api

Length of output: 901


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

go test ./services/networking/ip/vpn -run '^TestVPN_Batch_InvalidIPs$' -count=1

Repository: bobadilla-tech/requiems-api

Length of output: 1224


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

cat > /tmp/validate_batchreq.go <<'EOF'
package main

import (
	"fmt"
	"requiems-api/platform/httpx"
)

type BatchRequest struct {
	IPs []string `json:"ips" validate:"required,min=1,max=50,dive,required,ip"`
}

func main() {
	req := BatchRequest{
		IPs: []string{"8.8.8.8", "invalid-ip", "", "999.999.999.999"},
	}
	err := httpx.Validate.Struct(req)
	fmt.Printf("err=%T %v\n", err, err)

	// If it's a validator.ValidationErrors, print details
	type VErr interface {
		error
	}
	_ = VErr(nil)
}
EOF

go run /tmp/validate_batchreq.go

Repository: bobadilla-tech/requiems-api

Length of output: 366


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api
go test ./services/networking/ip/vpn -run '^TestVPN_Batch_InvalidIPs$' -count=1 -v

Repository: bobadilla-tech/requiems-api

Length of output: 359


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,220p' apps/api/services/networking/ip/vpn/service.go
sed -n '220,420p' apps/api/services/networking/ip/vpn/service.go

Repository: bobadilla-tech/requiems-api

Length of output: 1607


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

cat > /tmp/validate_http_batch.go <<'EOF'
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"

	"requiems-api/platform/httpx"
	vpn "requiems-api/services/networking/ip/vpn"
)

func main() {
	h := httpx.HandleBatch(
		func(ctx interface{}, req vpn.BatchRequest) (httpx.BatchResponse[vpn.IPCheckResponse], error) {
			// Should never run if validation fails
			return httpx.BatchResponse[vpn.IPCheckResponse]{Results: []vpn.IPCheckResponse{}}, nil
		},
	)

	// ^ compile-time error because ctx type mismatch; rebuild below with correct signature.
	_ = h
	_ = json.Number("0")
	_ = bytes.NewBuffer(nil)
	fmt.Println("skip")
}
EOF

Repository: bobadilla-tech/requiems-api

Length of output: 53


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

cat > /tmp/validate_http_batch.go <<'EOF'
package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"

	"requiems-api/platform/httpx"
	vpn "requiems-api/services/networking/ip/vpn"
)

func main() {
	h := httpx.HandleBatch(
		func(ctx context.Context, req vpn.BatchRequest) (httpx.BatchResponse[vpn.IPCheckResponse], error) {
			return httpx.BatchResponse[vpn.IPCheckResponse]{Results: []vpn.IPCheckResponse{}}, nil
		},
	)

	body := []byte(`{
		"ips": ["8.8.8.8","invalid-ip","","999.999.999.999"]
	}`)

	req := httptest.NewRequest(http.MethodPost, "/ip/vpn/batch", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()

	h.ServeHTTP(w, req)

	fmt.Println("status:", w.Code)
	// Try decode error response (covers 422)
	var er httpx.ErrorResponse
	_ = json.NewDecoder(w.Body).Decode(&er)
	fmt.Printf("body: error=%q message=%q fields=%d\n", er.Error, er.Message, len(er.Fields))
}
EOF

go run /tmp/validate_http_batch.go

Repository: bobadilla-tech/requiems-api

Length of output: 135


🏁 Script executed:

#!/bin/bash
# Sanity-check current validation tags
rg -n 'type BatchRequest struct|validate:"required,min=1,max=50,dive,required,ip"' apps/api/services/networking/ip/vpn/type.go

# Ensure partial-success expectations exist (invalid IPs included, order preserved)
rg -n 'TestVPN_Batch_InvalidIPs|StatusOK|invalid-ip|Response preserves input order|Invalid IPs are included' \
  apps/api/services/networking/ip/vpn/transport_http_test.go \
  apps/api/services/networking/ip/vpn/service_test.go \
  apps/dashboard/config/api_docs/vpn-detection.yml \
  docs/apis/places/timezone.md

Repository: bobadilla-tech/requiems-api

Length of output: 1864


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

sed -n '90,220p' ../docs/apis/places/timezone.md
sed -n '130,290p' ../apps/dashboard/config/api_docs/vpn-detection.yml 2>/dev/null || true

Repository: bobadilla-tech/requiems-api

Length of output: 146


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cd apps/api

sed -n '100,220p' ../../docs/apis/places/timezone.md
sed -n '140,290p' ../../apps/dashboard/config/api_docs/vpn-detection.yml

Repository: bobadilla-tech/requiems-api

Length of output: 7056


Relax /ip/vpn/batch request validation to enable per-item partial success

apps/api/services/networking/ip/vpn/type.go sets BatchRequest.IPs to validate:"required,min=1,max=50,dive,required,ip". httpx.HandleBatch runs BindAndValidate before calling svc.CheckBatch, so any malformed/empty element causes the entire request to fail with a validation error (422), contradicting the documented behavior that invalid IPs are returned in-band with zeroed detection fields.

🔧 Proposed fix
 type BatchRequest struct {
-	IPs []string `json:"ips" validate:"required,min=1,max=50,dive,required,ip"`
+	IPs []string `json:"ips" validate:"required,min=1,max=50"`
 }
📝 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
IPs []string `json:"ips" validate:"required,min=1,max=50,dive,required,ip"`
type BatchRequest struct {
IPs []string `json:"ips" validate:"required,min=1,max=50"`
}
🤖 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 `@apps/api/services/networking/ip/vpn/type.go` at line 38, The struct tag on
BatchRequest.IPs currently enforces per-item validation (`dive,required,ip`)
causing BindAndValidate to reject requests with any malformed IP; update the tag
to only validate the slice itself (e.g. change
`validate:"required,min=1,max=50,dive,required,ip"` to
`validate:"required,min=1,max=50,dive"`) so malformed or empty IP strings pass
initial binding and svc.CheckBatch can return per-item errors as intended;
modify the BatchRequest type's IPs field accordingly.

Comment on lines +145 to +193
response_example: |
{
"data": {
"results": [
{
"ip": "8.8.8.8",
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"is_hosting": true,
"score": 1,
"threat": 1,
"fraud_score": 0,
"asn_org": "GOOGLE-ASN"
},
{
"ip": "1.1.1.1",
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"is_hosting": true,
"score": 1,
"threat": 1,
"fraud_score": 0,
"asn_org": "CLOUDFLARE-ASN"
},
{
"ip": "invalid-ip",
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"is_hosting": false,
"score": 0,
"threat": 0,
"fraud_score": 0,
"asn_org": ""
}
]
},
"metadata": {
"timestamp": "2026-01-01T00:00:00Z"
}
}

response_fields:
- name: results
type: array
description: List of IP detection results (preserves input order)

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 | 🟡 Minor | ⚡ Quick win

Batch response docs are missing data.total.

httpx.HandleBatch returns data.total alongside data.results. The new docs should include it in both response_example and response_fields to match runtime behavior.

🤖 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 `@apps/dashboard/config/api_docs/vpn-detection.yml` around lines 145 - 193, The
docs for the batch VPN detection response are missing the data.total field
returned by httpx.HandleBatch; update the response_example JSON to include
"total": <number> alongside "results" under "data", and add a corresponding
response_fields entry (name: total, type: integer, description: Total number of
input IPs / total results) so the OpenAPI example and field list match the
runtime behavior from HandleBatch.

Comment on lines +166 to +189
### Response Fields

| Field | Type | Description |
| ------------- | ------- | ------------------------------------------------------- |
| `results` | array | List of IP detection results (preserves input order) |
| `ip` | string | IP address analyzed |
| `is_vpn` | boolean | True if IP belongs to a VPN provider |
| `is_proxy` | boolean | True if IP is a proxy |
| `is_tor` | boolean | True if IP is a Tor exit node |
| `is_hosting` | boolean | True if IP belongs to a data-centre or hosting provider |
| `score` | integer | Threat score (Tor +3, VPN +2, Proxy +2, Hosting +1) |
| `threat` | integer | 0=None, 1=Low, 2-3=Medium, 4-5=High, 6+=Critical |
| `fraud_score` | integer | Fraud risk score from 0 to 100 |
| `asn_org` | string | ASN organization name |

---

### Validation Rules

- Maximum 50 IPs per request
- At least 1 IP required
- Invalid IPs do not fail the request
- Response preserves input order
- Each IP is evaluated independently
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 | 🟡 Minor | ⚡ Quick win

Duplicate sections should be removed (MD024 warning).

Line 166-189 repeats the same ### Response Fields and ### Validation Rules content, which triggers duplicate-heading lint warnings and adds noise.

🧹 Suggested cleanup
-### Response Fields
-
-| Field         | Type    | Description                                             |
-| ------------- | ------- | ------------------------------------------------------- |
-| `results`     | array   | List of IP detection results (preserves input order)    |
-| `ip`          | string  | IP address analyzed                                     |
-| `is_vpn`      | boolean | True if IP belongs to a VPN provider                    |
-| `is_proxy`    | boolean | True if IP is a proxy                                   |
-| `is_tor`      | boolean | True if IP is a Tor exit node                           |
-| `is_hosting`  | boolean | True if IP belongs to a data-centre or hosting provider |
-| `score`       | integer | Threat score (Tor +3, VPN +2, Proxy +2, Hosting +1)     |
-| `threat`      | integer | 0=None, 1=Low, 2-3=Medium, 4-5=High, 6+=Critical        |
-| `fraud_score` | integer | Fraud risk score from 0 to 100                          |
-| `asn_org`     | string  | ASN organization name                                   |
-
----
-
-### Validation Rules
-
-- Maximum 50 IPs per request
-- At least 1 IP required
-- Invalid IPs do not fail the request
-- Response preserves input order
-- Each IP is evaluated independently
📝 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
### Response Fields
| Field | Type | Description |
| ------------- | ------- | ------------------------------------------------------- |
| `results` | array | List of IP detection results (preserves input order) |
| `ip` | string | IP address analyzed |
| `is_vpn` | boolean | True if IP belongs to a VPN provider |
| `is_proxy` | boolean | True if IP is a proxy |
| `is_tor` | boolean | True if IP is a Tor exit node |
| `is_hosting` | boolean | True if IP belongs to a data-centre or hosting provider |
| `score` | integer | Threat score (Tor +3, VPN +2, Proxy +2, Hosting +1) |
| `threat` | integer | 0=None, 1=Low, 2-3=Medium, 4-5=High, 6+=Critical |
| `fraud_score` | integer | Fraud risk score from 0 to 100 |
| `asn_org` | string | ASN organization name |
---
### Validation Rules
- Maximum 50 IPs per request
- At least 1 IP required
- Invalid IPs do not fail the request
- Response preserves input order
- Each IP is evaluated independently
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 166-166: Multiple headings with the same content

(MD024, no-duplicate-heading)


[warning] 183-183: Multiple headings with the same content

(MD024, no-duplicate-heading)

🤖 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 `@docs/apis/places/timezone.md` around lines 166 - 189, The file contains
duplicated sections titled "### Response Fields" and "### Validation Rules"
(including the table of fields like `results`, `ip`, `is_vpn`, `score`,
`fraud_score`, `asn_org`), causing MD024 lint warnings; remove the redundant
duplicate block so only one copy of the "### Response Fields" table and one "###
Validation Rules" list remain, ensuring the canonical section contains the full
field list and validation bullets and that any references to `results` or the
validation constraints point to that single section.

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