Add public found item contact page#1487
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughAdds an unauthenticated "found" flow: backend repo methods and rate-limited API endpoints return owner contact for an entity or asset ID; frontend middleware redirects scanned label routes to a new /found page that fetches the contact and offers a mailto link; OpenAPI/Swagger and tests updated. ChangesFound Item Contact Flow
Sequence Diagram(s)sequenceDiagram
participant Client
participant Limiter as foundLabelLimiter
participant Handler as V1Controller
participant Repo as EntityRepository
participant DB as Database
Client->>Limiter: GET /api/v1/found/entities/{id}
Limiter->>Handler: allow -> HandleFoundEntityContact
Handler->>Repo: GetFoundEntityContact(id)
Repo->>DB: fetch entity/group, query UserGroup(RoleOwner)
DB-->>Repo: owner email, item id
Repo-->>Handler: FoundEntityContact
Handler-->>Client: 200 + JSON
Security Recommendations
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
941dc35 to
942348b
Compare
There was a problem hiding this comment.
Warning
CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.
Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.
Actionable comments posted: 4
🧹 Nitpick comments (6)
backend/app/api/app.go (1)
42-42: Security hardening: make this public limiter tunable and observable.Because these endpoints are unauthenticated and return contact emails, consider moving
60/minto config and adding metrics/alerts on 429 spikes to react quickly to scraping attempts.🤖 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/app/api/app.go` at line 42, Move the hardcoded 60/min into configuration and add observability: add a new config field (e.g., Options.FoundLabelRatePerMinute or FoundLabelRateLimit) and use it when constructing s.foundLabelLimiter via newSimpleRateLimiter instead of the literal 60; then instrument the rate limiter rejection path (where handlers return 429) to increment a metric/counter (e.g., found_label_rate_limited_total) and expose it to your metrics system so alerts can be created on spikes; reference s.foundLabelLimiter, newSimpleRateLimiter, and s.conf.Options.TrustProxy when making the change and update any config parsing/validation to ensure the value is tunable at runtime if supported.frontend/pages/found/[kind]/[id].vue (1)
11-13: ⚡ Quick winMove user-facing strings to translation keys.
This page introduces several hardcoded UI strings (title, headings, button labels, loading/error copy) that should be i18n-backed for consistency with localized UI.
As per coding guidelines
**/*.{ts,vue}: “Check for hardcoded strings in UI components that should be translatable.”Also applies to: 63-67, 73-85
🤖 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 `@frontend/pages/found/`[kind]/[id].vue around lines 11 - 13, The page currently uses hardcoded UI strings (e.g. the head title set via useHead("HomeBox | Found Item"), and the headings, button labels, and loading/error copy referenced around the noted ranges) — replace all of those with i18n translation keys by wiring up the vue-i18n APIs (e.g. import/use useI18n or $t) in the component, change literal strings in the script/template to calls like t('found.item.title') or $t('found.item.loading'), and add corresponding keys to the locale files; ensure the useHead title uses the translated value (t('found.item.title')) and update all button labels, headings, and loading/error messages to use the new keys (look for uses in the component methods and template such as useHead, template text nodes, and any button/alert text).docs/public/api/swagger-2.0.json (1)
1173-1180: ⚡ Quick winDocument abuse-control and miss-path responses for public contact endpoints.
For public email-revealing routes, add explicit
429(rate limit) and404/422responses in the OpenAPI contract so clients can implement safe handling and backoff behavior.Also applies to: 1201-1208
🤖 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/public/api/swagger-2.0.json` around lines 1173 - 1180, Update the operation responses that currently return "200" with "$ref": "#/definitions/repo.FoundEntityContact" (i.e., the public contact/email-revealing endpoints) to include explicit "429" and appropriate "404"/"422" response entries: add a "429" response with a short description like "Too Many Requests" and a schema pointing to your existing error model (e.g., "#/definitions/Error" or the project's validation/error definition), add a "404" response with description "Not Found" and an error schema, and add a "422" response with description "Unprocessable Entity" (validation error) and an error/validation schema; ensure these new response objects sit alongside the existing "200" response for the same operation(s) that reference repo.FoundEntityContact so clients can handle rate-limiting and missing/validation cases.docs/public/api/openapi-3.0.json (1)
5394-5404: 💤 Low value
repo.FoundEntityContactminimalism is 👌 — but consider markingownerEmailshape expectations.The DTO is appropriately spartan (just
itemIdandownerEmail), which is exactly the privacy contract the PR promises. Two tiny optional polish ideas at the swagger-source level:
- Add
format: "email"(or"uuid"foritemId) so generated clients get free validation/typing.- Add an
exampleblock to make the public docs self-explanatory.Not blocking; the contract is correct as-is.
Security recommendation: because this endpoint is unauthenticated and emits an email address keyed by a guessable-ish asset ID (small integer in many setups), please make sure the implementation also (a) is rate-limited per-IP and globally for the endpoint to deter scraping/enumeration of
ownerEmail, (b) logs are sanitized so the returned email isn't written to access logs at info level, and (c) consider whether a future iteration should return a tokenized "contact this owner" relay rather than the raw email. Out of scope for the doc, but worth tracking. 🛡️🤖 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/public/api/openapi-3.0.json` around lines 5394 - 5404, Update the OpenAPI schema for repo.FoundEntityContact by adding shape metadata: set "ownerEmail" to include format: "email" and set "itemId" to an appropriate format (e.g., "uuid" or "int64" per your actual ID type), and add an "example" object showing a realistic itemId and ownerEmail to improve generated-client validation and docs; reference the repo.FoundEntityContact schema and its properties ("ownerEmail", "itemId") when making these edits. Also, though not a doc change, ensure the implementation of the unauthenticated endpoint is tracked/fixed to enforce per-IP and global rate-limiting, sanitize logs to avoid writing returned emails at info level, and consider returning a relay/tokenized contact instead of raw ownerEmail in a future iteration.docs/public/api/swagger-2.0.yaml (1)
1990-1999: 💤 Low valueDuplicate enum value may cause confusion.
The
usergroup.Roleenum lists "user" twice (lines 1992-1993), similar to the pattern inauthroles.Role. While this appears to be a schema generation artifact where the default value is listed separately, it could be confusing for API consumers.Consider documenting why "user" appears twice, or ensure the OpenAPI generator is configured to avoid duplicate enum values.
🤖 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/public/api/swagger-2.0.yaml` around lines 1990 - 1999, The OpenAPI enum for usergroup.Role contains a duplicate "user" entry which can confuse clients; update the schema generation or the YAML so enum values are unique by removing the duplicate "user" entry (or post-process the generated enum) and ensure x-enum-varnames still map correctly (DefaultRole, RoleUser, RoleOwner); also check the similar authroles.Role generation to apply the same deduplication rule so both enums only list each value once.docs/public/api/openapi-3.0.yaml (1)
3881-3890: 💤 Low valueDuplicate enum value may cause confusion.
The
usergroup.Roleenum lists "user" twice (lines 3884-3885), matching the pattern in the Swagger 2.0 spec. While likely a schema generation artifact, this could confuse API consumers. Consider documenting why the default role is listed separately or adjusting the code generation to avoid duplicates.🤖 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/public/api/openapi-3.0.yaml` around lines 3881 - 3890, The usergroup.Role enum contains a duplicated value "user" which can confuse consumers; update the schema so the enum array contains unique values (e.g., ["user","owner"]) and ensure x-enum-varnames aligns with those values (e.g., DefaultRole/RoleUser/RoleOwner only if they map to distinct enum entries), or if the duplicate represents a modeled default, replace the duplicate with a documented sentinel (or remove the DefaultRole duplicate) and adjust the generator that produces usergroup.Role so it does not emit duplicate enum entries; locate this in the OpenAPI definition under the usergroup.Role schema and update the enum and x-enum-varnames accordingly.
🤖 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 `@docs/public/api/openapi-3.0.yaml`:
- Around line 756-793: The OpenAPI paths "/v1/found/assets/{id}" and
"/v1/found/entities/{id}" currently expose PII via the repo.FoundEntityContact
schema (ownerEmail); update the spec to eliminate or mask ownerEmail from that
schema (or replace it with a non-PII field like ownerContactMasked) and add
security requirements and rate limiting notes to both path definitions (e.g., a
security requirement referencing existing securitySchemes and a description of
rate-limiting/anti-scraping measures), add a privacy/security warning and link
to the privacy policy in the path summaries or descriptions, and add a
recommended alternative endpoint or mechanism (contact form/one-time token) in
the documentation for contacting owners; ensure the change updates the
components/schemas/repo.FoundEntityContact reference so no public response
returns raw ownerEmail.
In `@docs/public/api/swagger-2.0.yaml`:
- Around line 2883-2918: The two public GET paths (/v1/found/assets/{id} and
/v1/found/entities/{id}) expose PII via the repo.FoundEntityContact schema
(ownerEmail) and lack any security/rate-limit documentation; update these
endpoint specs to require authentication or a documented security scheme (add a
security: section), remove or replace ownerEmail in the response schema
repo.FoundEntityContact with a non-PII alternative (e.g., contactProxy,
maskedEmail, or token) and document the privacy implications, add X-RateLimit
response header definitions and a brief note linking to the privacy policy and
opt-out instructions, and if you cannot change behavior, add an explicit warning
in the endpoint descriptions that ownerEmail is PII and rate-limited
access/abuse logging is enforced.
In `@frontend/lib/api/public.ts`:
- Around line 40-49: In foundEntityContact and foundAssetContact, encode the id
before interpolating into the URL so reserved characters won't break the route;
replace direct interpolation of id in route(`/found/entities/${id}`) and
route(`/found/assets/${id}`) with an encoded value (use encodeURIComponent or
equivalent) so the generated path is safe for all id values.
In `@frontend/middleware/auth.ts`:
- Around line 35-43: The current regexes used with path.match (the itemMatch and
assetMatch checks in frontend/middleware/auth.ts) should be anchored to prevent
matching nested routes; change the patterns to require the end of the path
(allowing an optional trailing slash) — e.g. replace the item pattern with one
that enforces ^/item/([^/]+)(?:/)?$ and the assets pattern with
^/(?:a|assets)/([^/]+)(?:/)?$ so only top-level /item/:id or /assets/:id (with
optional trailing slash) get redirected, keeping the same
encodeURIComponent(itemMatch[1]) and encodeURIComponent(assetMatch[1]) usage.
---
Nitpick comments:
In `@backend/app/api/app.go`:
- Line 42: Move the hardcoded 60/min into configuration and add observability:
add a new config field (e.g., Options.FoundLabelRatePerMinute or
FoundLabelRateLimit) and use it when constructing s.foundLabelLimiter via
newSimpleRateLimiter instead of the literal 60; then instrument the rate limiter
rejection path (where handlers return 429) to increment a metric/counter (e.g.,
found_label_rate_limited_total) and expose it to your metrics system so alerts
can be created on spikes; reference s.foundLabelLimiter, newSimpleRateLimiter,
and s.conf.Options.TrustProxy when making the change and update any config
parsing/validation to ensure the value is tunable at runtime if supported.
In `@docs/public/api/openapi-3.0.json`:
- Around line 5394-5404: Update the OpenAPI schema for repo.FoundEntityContact
by adding shape metadata: set "ownerEmail" to include format: "email" and set
"itemId" to an appropriate format (e.g., "uuid" or "int64" per your actual ID
type), and add an "example" object showing a realistic itemId and ownerEmail to
improve generated-client validation and docs; reference the
repo.FoundEntityContact schema and its properties ("ownerEmail", "itemId") when
making these edits. Also, though not a doc change, ensure the implementation of
the unauthenticated endpoint is tracked/fixed to enforce per-IP and global
rate-limiting, sanitize logs to avoid writing returned emails at info level, and
consider returning a relay/tokenized contact instead of raw ownerEmail in a
future iteration.
In `@docs/public/api/openapi-3.0.yaml`:
- Around line 3881-3890: The usergroup.Role enum contains a duplicated value
"user" which can confuse consumers; update the schema so the enum array contains
unique values (e.g., ["user","owner"]) and ensure x-enum-varnames aligns with
those values (e.g., DefaultRole/RoleUser/RoleOwner only if they map to distinct
enum entries), or if the duplicate represents a modeled default, replace the
duplicate with a documented sentinel (or remove the DefaultRole duplicate) and
adjust the generator that produces usergroup.Role so it does not emit duplicate
enum entries; locate this in the OpenAPI definition under the usergroup.Role
schema and update the enum and x-enum-varnames accordingly.
In `@docs/public/api/swagger-2.0.json`:
- Around line 1173-1180: Update the operation responses that currently return
"200" with "$ref": "#/definitions/repo.FoundEntityContact" (i.e., the public
contact/email-revealing endpoints) to include explicit "429" and appropriate
"404"/"422" response entries: add a "429" response with a short description like
"Too Many Requests" and a schema pointing to your existing error model (e.g.,
"#/definitions/Error" or the project's validation/error definition), add a "404"
response with description "Not Found" and an error schema, and add a "422"
response with description "Unprocessable Entity" (validation error) and an
error/validation schema; ensure these new response objects sit alongside the
existing "200" response for the same operation(s) that reference
repo.FoundEntityContact so clients can handle rate-limiting and
missing/validation cases.
In `@docs/public/api/swagger-2.0.yaml`:
- Around line 1990-1999: The OpenAPI enum for usergroup.Role contains a
duplicate "user" entry which can confuse clients; update the schema generation
or the YAML so enum values are unique by removing the duplicate "user" entry (or
post-process the generated enum) and ensure x-enum-varnames still map correctly
(DefaultRole, RoleUser, RoleOwner); also check the similar authroles.Role
generation to apply the same deduplication rule so both enums only list each
value once.
In `@frontend/pages/found/`[kind]/[id].vue:
- Around line 11-13: The page currently uses hardcoded UI strings (e.g. the head
title set via useHead("HomeBox | Found Item"), and the headings, button labels,
and loading/error copy referenced around the noted ranges) — replace all of
those with i18n translation keys by wiring up the vue-i18n APIs (e.g. import/use
useI18n or $t) in the component, change literal strings in the script/template
to calls like t('found.item.title') or $t('found.item.loading'), and add
corresponding keys to the locale files; ensure the useHead title uses the
translated value (t('found.item.title')) and update all button labels, headings,
and loading/error messages to use the new keys (look for uses in the component
methods and template such as useHead, template text nodes, and any button/alert
text).
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 4e36a329-27c4-46e7-becf-167ddcbbccfa
⛔ Files ignored due to path filters (5)
backend/app/api/static/docs/docs.gois excluded by!backend/app/api/static/docs/**backend/app/api/static/docs/openapi-3.jsonis excluded by!backend/app/api/static/docs/**backend/app/api/static/docs/openapi-3.yamlis excluded by!backend/app/api/static/docs/**backend/app/api/static/docs/swagger.jsonis excluded by!backend/app/api/static/docs/**backend/app/api/static/docs/swagger.yamlis excluded by!backend/app/api/static/docs/**
📒 Files selected for processing (13)
backend/app/api/app.gobackend/app/api/handlers/v1/v1_ctrl_found_item.gobackend/app/api/routes.gobackend/internal/data/repo/repo_entities.gobackend/internal/data/repo/repo_entities_found_item_test.godocs/public/api/openapi-3.0.jsondocs/public/api/openapi-3.0.yamldocs/public/api/swagger-2.0.jsondocs/public/api/swagger-2.0.yamlfrontend/lib/api/public.tsfrontend/lib/api/types/data-contracts.tsfrontend/middleware/auth.tsfrontend/pages/found/[kind]/[id].vue
| "/v1/found/assets/{id}": | ||
| get: | ||
| tags: | ||
| - Entities | ||
| summary: Get found asset contact | ||
| parameters: | ||
| - description: Asset ID | ||
| name: id | ||
| in: path | ||
| required: true | ||
| schema: | ||
| type: string | ||
| responses: | ||
| "200": | ||
| description: OK | ||
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "#/components/schemas/repo.FoundEntityContact" | ||
| "/v1/found/entities/{id}": | ||
| get: | ||
| tags: | ||
| - Entities | ||
| summary: Get found item contact | ||
| parameters: | ||
| - description: Entity ID | ||
| name: id | ||
| in: path | ||
| required: true | ||
| schema: | ||
| type: string | ||
| responses: | ||
| "200": | ||
| description: OK | ||
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "#/components/schemas/repo.FoundEntityContact" |
There was a problem hiding this comment.
CRITICAL: Public endpoints expose owner email addresses (PII).
These unauthenticated endpoints return ownerEmail (PII) to anyone, creating the same critical security and privacy risks documented in the swagger-2.0.yaml review (lines 2883-2918).
Key risks:
- Email harvesting via ID enumeration
- GDPR/CCPA privacy violations
- No documented anti-scraping measures in the API spec
- Exposes users to spam and phishing attacks
Required actions:
- Document rate limiting in the OpenAPI spec
- Add security warnings and privacy policy references
- Consider safer alternatives (contact forms, one-time tokens, masked emails)
- Implement CAPTCHA or proof-of-work challenges
- Provide user opt-out mechanism
See the detailed security review on swagger-2.0.yaml lines 2883-2918 for full recommendations.
🤖 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/public/api/openapi-3.0.yaml` around lines 756 - 793, The OpenAPI paths
"/v1/found/assets/{id}" and "/v1/found/entities/{id}" currently expose PII via
the repo.FoundEntityContact schema (ownerEmail); update the spec to eliminate or
mask ownerEmail from that schema (or replace it with a non-PII field like
ownerContactMasked) and add security requirements and rate limiting notes to
both path definitions (e.g., a security requirement referencing existing
securitySchemes and a description of rate-limiting/anti-scraping measures), add
a privacy/security warning and link to the privacy policy in the path summaries
or descriptions, and add a recommended alternative endpoint or mechanism
(contact form/one-time token) in the documentation for contacting owners; ensure
the change updates the components/schemas/repo.FoundEntityContact reference so
no public response returns raw ownerEmail.
| /v1/found/assets/{id}: | ||
| get: | ||
| parameters: | ||
| - description: Asset ID | ||
| in: path | ||
| name: id | ||
| required: true | ||
| type: string | ||
| produces: | ||
| - application/json | ||
| responses: | ||
| "200": | ||
| description: OK | ||
| schema: | ||
| $ref: '#/definitions/repo.FoundEntityContact' | ||
| summary: Get found asset contact | ||
| tags: | ||
| - Entities | ||
| /v1/found/entities/{id}: | ||
| get: | ||
| parameters: | ||
| - description: Entity ID | ||
| in: path | ||
| name: id | ||
| required: true | ||
| type: string | ||
| produces: | ||
| - application/json | ||
| responses: | ||
| "200": | ||
| description: OK | ||
| schema: | ||
| $ref: '#/definitions/repo.FoundEntityContact' | ||
| summary: Get found item contact | ||
| tags: | ||
| - Entities |
There was a problem hiding this comment.
CRITICAL: Public endpoints expose owner email addresses (PII).
These endpoints are unauthenticated (no security section) and return ownerEmail, exposing personally identifiable information (PII) to anyone who can access the API.
Security & Privacy Risks:
- Email harvesting: Attackers can enumerate IDs to collect email addresses for spam, phishing, or targeted attacks
- Privacy violations: Exposing emails without explicit user consent may violate GDPR, CCPA, or other privacy regulations
- No anti-scraping measures: The OpenAPI spec shows no CAPTCHA, token requirements, or other anti-automation controls
- Minimal rate limiting visibility: While the PR mentions rate limiting, it's not documented in the API specification
Recommendations:
Must-have protections:
- Document rate limiting in the OpenAPI spec (X-RateLimit headers, limits, etc.)
- Add privacy policy reference explaining email exposure when generating QR labels
- Consider requiring user opt-in for public contact availability
Strongly recommended alternatives:
- Use a contact form/proxy that doesn't expose the raw email address
- Implement a one-time-use token system instead of direct ID lookups
- Add CAPTCHA or proof-of-work challenges to prevent automated scraping
- Return a masked/hashed contact method instead of the raw email
At minimum:
- Add security warnings to the endpoint documentation
- Implement aggressive rate limiting (e.g., 5 requests per IP per hour)
- Log all access attempts for abuse monitoring
- Provide users a way to disable public contact on their items
🤖 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/public/api/swagger-2.0.yaml` around lines 2883 - 2918, The two public
GET paths (/v1/found/assets/{id} and /v1/found/entities/{id}) expose PII via the
repo.FoundEntityContact schema (ownerEmail) and lack any security/rate-limit
documentation; update these endpoint specs to require authentication or a
documented security scheme (add a security: section), remove or replace
ownerEmail in the response schema repo.FoundEntityContact with a non-PII
alternative (e.g., contactProxy, maskedEmail, or token) and document the privacy
implications, add X-RateLimit response header definitions and a brief note
linking to the privacy policy and opt-out instructions, and if you cannot change
behavior, add an explicit warning in the endpoint descriptions that ownerEmail
is PII and rate-limited access/abuse logging is enforced.
Summary
/item/:id,/a/:id, and/assets/:idvisits to a public found-item pageFixes #13.
Privacy notes
The public response intentionally returns only
itemIdandownerEmail. It does not expose item names, notes, photos, attachments, locations, or other inventory details. Asset ID lookups return contact only when the asset ID resolves to exactly one entity.Testing
go test ./...go test ./app/api ./app/api/handlers/v1 ./internal/data/repopnpm exec eslint middleware/auth.ts lib/api/public.ts 'pages/found/[kind]/[id].vue' --max-warnings 0pnpm exec prettier --check --arrow-parens avoid --tab-width 2 --vue-indent-script-and-style --single-quote false --trailing-comma es5 --print-width 120 middleware/auth.ts lib/api/public.ts 'pages/found/[kind]/[id].vue'/item/:idredirects to/found/item/:idand signed-out/a/:idredirects to/found/asset/:id; both render the contact mailto link against a local backend.Known existing checks
pnpm run lint:cistill fails on existing unrelated lint errors outside this patch, for example unused variables in location/item pages andno-explicit-anyinlib/api/classes/items.ts.pnpm run typecheckstill fails on existing generated/ref type issues across the frontend, includingEntitySummary.location, severaluseAsyncDataref usages, and template field shape errors.Summary by CodeRabbit
New Features
Bug Fixes / UX
Rate Limiting
Documentation
Tests