feat: allow either permission id or slug in permission related requests. #3653
feat: allow either permission id or slug in permission related requests. #3653
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Skipped Deployments
|
📝 WalkthroughWalkthroughThis change is a comprehensive refactor and standardization of the API's permissions and roles management. It unifies empty response types, simplifies request and response schemas by using string lists instead of complex objects, and streamlines handler logic and database operations for permissions and roles. The update also introduces new batch database queries and enhances test coverage to align with the new models. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Handler
participant DB
participant AuditLog
Client->>API_Handler: Add/Remove/Set Permissions/Roles (with string lists)
API_Handler->>DB: Batch lookup permissions/roles by slugs/names
alt Missing permissions/roles
API_Handler->>DB: Create missing permissions (if authorized)
API_Handler->>AuditLog: Log permission creation
end
API_Handler->>DB: Bulk insert/delete key-permission or key-role associations
API_Handler->>AuditLog: Log assignment/removal
API_Handler->>DB: Invalidate key cache
API_Handler-->>Client: Response with updated permissions/roles (standardized format)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
make it a draft if you don’t want merges 🙂 |
|
also note to self on that one 😄 |
|
fair enough |
There was a problem hiding this comment.
Actionable comments posted: 14
🔭 Outside diff range comments (4)
go/apps/api/routes/v2_permissions_delete_permission/400_test.go (1)
38-39: Update test case names and comments for consistency.The test case names and comments still reference "permissionId" but the actual field is now "Permission". Consider updating for consistency.
- // Test case for missing required permissionId - t.Run("missing permissionId", func(t *testing.T) { + // Test case for missing required permission + t.Run("missing permission", func(t *testing.T) {- // Test case for empty permissionId - t.Run("empty permissionId", func(t *testing.T) { + // Test case for empty permission + t.Run("empty permission", func(t *testing.T) {Also applies to: 57-58
go/apps/api/openapi/spec/paths/v2/permissions/getPermission/V2PermissionsGetPermissionRequestBody.yaml (1)
19-19: Fix inconsistent field name in example.The example still uses the old field name
permissionIdbut should usepermissionto match the updated schema.- permissionId: perm_1234567890abcdef + permission: perm_1234567890abcdefgo/apps/api/routes/v2_permissions_delete_permission/handler.go (1)
111-133: Consider audit log field consistency.The audit log uses
permission.IDfor display butpermission.Slugfor the resource name. While functionally correct, this mixed usage might cause confusion during audit review.Consider standardizing to use either ID or slug consistently, or include both for clarity:
- Display: "Deleted " + permission.ID, + Display: "Deleted permission " + permission.Slug,go/apps/api/routes/v2_keys_update_key/handler.go (1)
91-106: Address the TODO: Implement proper permission checks for role operations.The TODO comment correctly identifies that the current permission check is insufficient. Users with
UpdateKeypermission can modify roles without specific role management permissions, which could lead to privilege escalation.Would you like me to implement the proper permission checks for role operations or create an issue to track this security gap?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (78)
go/apps/api/openapi/gen.go(13 hunks)go/apps/api/openapi/openapi-generated.yaml(15 hunks)go/apps/api/openapi/spec/common/EmptyResponse.yaml(1 hunks)go/apps/api/openapi/spec/common/KeyResponseData.yaml(1 hunks)go/apps/api/openapi/spec/common/permission.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/apis/deleteApi/V2ApisDeleteApiResponseBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/deleteKey/V2KeysDeleteKeyResponseBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyResponseBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyResponseData.yaml(0 hunks)go/apps/api/openapi/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionResponseBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleResponseBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/getPermission/V2PermissionsGetPermissionRequestBody.yaml(1 hunks)go/apps/api/routes/v2_keys_add_permissions/200_test.go(7 hunks)go/apps/api/routes/v2_keys_add_permissions/400_test.go(5 hunks)go/apps/api/routes/v2_keys_add_permissions/401_test.go(3 hunks)go/apps/api/routes/v2_keys_add_permissions/403_test.go(4 hunks)go/apps/api/routes/v2_keys_add_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_add_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_add_roles/handler.go(1 hunks)go/apps/api/routes/v2_keys_create_key/handler.go(3 hunks)go/apps/api/routes/v2_keys_delete_key/handler.go(1 hunks)go/apps/api/routes/v2_keys_remove_permissions/200_test.go(7 hunks)go/apps/api/routes/v2_keys_remove_permissions/400_test.go(1 hunks)go/apps/api/routes/v2_keys_remove_permissions/401_test.go(1 hunks)go/apps/api/routes/v2_keys_remove_permissions/403_test.go(2 hunks)go/apps/api/routes/v2_keys_remove_permissions/404_test.go(5 hunks)go/apps/api/routes/v2_keys_remove_permissions/handler.go(5 hunks)go/apps/api/routes/v2_keys_remove_roles/handler.go(1 hunks)go/apps/api/routes/v2_keys_set_permissions/200_test.go(7 hunks)go/apps/api/routes/v2_keys_set_permissions/400_test.go(1 hunks)go/apps/api/routes/v2_keys_set_permissions/401_test.go(1 hunks)go/apps/api/routes/v2_keys_set_permissions/403_test.go(4 hunks)go/apps/api/routes/v2_keys_set_permissions/404_test.go(7 hunks)go/apps/api/routes/v2_keys_set_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_set_roles/handler.go(2 hunks)go/apps/api/routes/v2_keys_update_credits/handler.go(0 hunks)go/apps/api/routes/v2_keys_update_key/handler.go(6 hunks)go/apps/api/routes/v2_permissions_create_permission/handler.go(2 hunks)go/apps/api/routes/v2_permissions_create_role/handler.go(2 hunks)go/apps/api/routes/v2_permissions_delete_permission/200_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_permission/400_test.go(1 hunks)go/apps/api/routes/v2_permissions_delete_permission/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_delete_permission/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_permission/404_test.go(3 hunks)go/apps/api/routes/v2_permissions_delete_permission/handler.go(1 hunks)go/apps/api/routes/v2_permissions_delete_role/handler.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/200_test.go(3 hunks)go/apps/api/routes/v2_permissions_get_permission/400_test.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_permission/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/404_test.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/handler.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/handler.go(0 hunks)go/apps/api/routes/v2_permissions_list_permissions/handler.go(0 hunks)go/apps/api/routes/v2_permissions_list_roles/handler.go(0 hunks)go/pkg/db/bulk_key_permission_insert.sql.go(2 hunks)go/pkg/db/bulk_ratelimit_override_insert.sql.go(1 hunks)go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go(1 hunks)go/pkg/db/key_permission_insert.sql_generated.go(3 hunks)go/pkg/db/permission_find_by_id_or_slug.sql_generated.go(1 hunks)go/pkg/db/permission_find_many_by_id_or_slug.sql_generated.go(1 hunks)go/pkg/db/plugins/bulk-insert/bulk_insert.go.tmpl(1 hunks)go/pkg/db/plugins/bulk-insert/generator.go(3 hunks)go/pkg/db/plugins/bulk-insert/parser.go(3 hunks)go/pkg/db/plugins/bulk-insert/template.go(1 hunks)go/pkg/db/querier_generated.go(4 hunks)go/pkg/db/queries/key_permission_delete_many_by_key_and_permission_ids.sql(1 hunks)go/pkg/db/queries/key_permission_insert.sql(1 hunks)go/pkg/db/queries/permission_find_by_id_or_slug.sql(1 hunks)go/pkg/db/queries/permission_find_many_by_id_or_slug.sql(1 hunks)go/pkg/zen/middleware_tracing.go(2 hunks)
💤 Files with no reviewable changes (5)
- go/apps/api/routes/v2_permissions_list_roles/handler.go
- go/apps/api/routes/v2_permissions_get_role/handler.go
- go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyResponseData.yaml
- go/apps/api/routes/v2_keys_update_credits/handler.go
- go/apps/api/routes/v2_permissions_list_permissions/handler.go
🧰 Additional context used
🧠 Learnings (52)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/common/KeyResponseData.yaml (4)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_permissions_delete_role/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
go/apps/api/routes/v2_permissions_delete_permission/400_test.go (2)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/routes/v2_keys_add_roles/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
go/apps/api/openapi/spec/paths/v2/keys/deleteKey/V2KeysDeleteKeyResponseBody.yaml (1)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_set_permissions/401_test.go (1)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/routes/v2_keys_create_key/handler.go (1)
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
go/apps/api/openapi/spec/paths/v2/permissions/getPermission/V2PermissionsGetPermissionRequestBody.yaml (2)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
go/pkg/db/queries/key_permission_delete_many_by_key_and_permission_ids.sql (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsResponseData.yaml (2)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_permissions_create_role/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
go/apps/api/routes/v2_keys_add_permissions/400_test.go (7)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
go/pkg/db/queries/key_permission_insert.sql (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3161
File: go/pkg/clickhouse/schema/databases/002_ratelimits/006_ratelimits_per_day_v1.sql:1-13
Timestamp: 2025-04-22T14:43:11.724Z
Learning: In the unkey project, the SQL files in clickhouse/schema/databases represent the current production schema and shouldn't be modified directly in PRs. Schema changes require dedicated migration scripts.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_set_permissions/400_test.go (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_keys_set_roles/handler.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
go/apps/api/routes/v2_keys_add_permissions/401_test.go (5)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/pkg/db/key_permission_insert.sql_generated.go (3)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_permissions_get_permission/400_test.go (2)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/plugins/bulk-insert/template.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/pkg/db/bulk_key_permission_insert.sql.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_permissions_get_permission/handler.go (1)
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/openapi/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionRequestBody.yaml (3)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_add_permissions/403_test.go (5)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/routes/v2_keys_add_permissions/200_test.go (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (4)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsResponseData.yaml (2)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_update_key/handler.go (8)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_remove_permissions/403_test.go (8)
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/pkg/db/plugins/bulk-insert/parser.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyResponseBody.yaml (2)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/pkg/db/plugins/bulk-insert/bulk_insert.go.tmpl (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
go/pkg/db/bulk_ratelimit_override_insert.sql.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
go/pkg/db/plugins/bulk-insert/generator.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_keys_remove_roles/handler.go (1)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (4)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (8)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsResponseData.yaml (2)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_permissions/handler.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/pkg/db/querier_generated.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_permissions_create_permission/handler.go (1)
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
go/apps/api/routes/v2_keys_add_permissions/handler.go (4)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_set_permissions/handler.go (4)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/openapi-generated.yaml (6)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
🧬 Code Graph Analysis (15)
go/apps/api/routes/v2_keys_add_permissions/401_test.go (2)
go/pkg/testutil/seed/seed.go (1)
CreateApiRequest(78-86)go/pkg/uid/uid.go (1)
TestPrefix(24-24)
go/pkg/db/key_permission_insert.sql_generated.go (2)
internal/db/src/types.ts (1)
InsertKeyPermission(41-41)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_permissions_get_permission/400_test.go (2)
go/pkg/rbac/query.go (1)
T(84-90)go/apps/api/routes/v2_permissions_get_permission/handler.go (1)
Request(17-17)
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (1)
go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/apps/api/routes/v2_permissions_delete_permission/401_test.go (1)
go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (1)
go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/apps/api/routes/v2_permissions_get_permission/handler.go (2)
go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (1)
FindPermissionByIdOrSlugParams(18-21)go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/apps/api/routes/v2_keys_add_permissions/403_test.go (3)
go/pkg/testutil/seed/seed.go (1)
CreateApiRequest(78-86)go/pkg/uid/uid.go (1)
TestPrefix(24-24)go/apps/api/routes/v2_keys_add_permissions/handler.go (1)
Request(25-25)
go/pkg/db/permission_find_many_by_id_or_slug.sql_generated.go (2)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/pkg/zen/middleware_tracing.go (1)
go/pkg/otel/tracing/trace.go (1)
RecordError(79-84)
go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (1)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_permissions_get_permission/200_test.go (3)
go/pkg/uid/uid.go (1)
PermissionPrefix(27-27)go/apps/api/openapi/gen.go (1)
Permission(366-386)go/pkg/testutil/http.go (1)
CallRoute(257-291)
go/apps/api/routes/v2_keys_add_permissions/404_test.go (2)
go/pkg/uid/uid.go (1)
PermissionPrefix(27-27)go/apps/api/routes/v2_keys_add_permissions/handler.go (1)
Request(25-25)
go/pkg/db/querier_generated.go (5)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (1)
DeleteManyKeyPermissionByKeyAndPermissionIDsParams(18-21)go/pkg/db/permission_find_many_by_id_or_slug.sql_generated.go (1)
FindManyPermissionsByIdOrSlugParams(19-22)go/pkg/db/models_generated.go (1)
Permission(744-752)go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (1)
FindPermissionByIdOrSlugParams(18-21)
go/apps/api/openapi/gen.go (2)
go/pkg/codes/unkey_data.go (1)
Data(87-128)go/pkg/db/models_generated.go (1)
Permission(744-752)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Test Go API Local / Test
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Build / Build
- GitHub Check: Test API / API Test Local
- GitHub Check: Test Packages / Test
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (152)
go/apps/api/routes/v2_permissions_get_permission/403_test.go (2)
59-59: Field name update aligns with API standardization.The change from
PermissionIdtoPermissioncorrectly reflects the unified permission identifier field that now accepts either ID or slug.
86-86: Consistent field name standardization.Good consistency in applying the same field name change across both test cases.
go/apps/api/routes/v2_permissions_delete_role/handler.go (2)
125-125: Good use of audit log constants.Replacing the hardcoded string with
auditlog.RoleDeleteEventimproves consistency and maintainability across the codebase.
135-135: Consistent use of resource type constants.Good consistency in applying the same constant-based approach for both event and resource type fields in the audit log.
go/apps/api/openapi/spec/common/KeyResponseData.yaml (1)
63-63: Improved API documentation clarity.The updated description accurately specifies that the array contains permission slugs, providing clearer guidance for API consumers.
go/pkg/db/queries/permission_find_by_id_or_slug.sql (1)
1-4: Well-designed query for unified permission lookup.The query correctly implements workspace-scoped permission lookup by either ID or slug, supporting the PR's objective to allow flexible permission identification.
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (2)
60-60: Field name standardization applied correctly.The change from
PermissionIdtoPermissionaligns with the unified permission identifier approach across the API.
95-95: Consistent field name update across test cases.Good consistency in applying the same field name standardization across both authorization error test scenarios.
go/apps/api/routes/v2_permissions_get_permission/404_test.go (1)
41-41: Field rename aligns with API contract changes.The field rename from
PermissionIdtoPermissioncorrectly reflects the API model change that allows endpoints to accept either permission ID or slug. The test logic remains intact and appropriate.Also applies to: 62-62
go/apps/api/routes/v2_keys_remove_roles/handler.go (1)
209-209: Good practice: Using constants instead of magic strings.Replacing hardcoded string literals with
auditlog.KeyResourceTypeandauditlog.RoleResourceTypeconstants improves maintainability and reduces the risk of typos in audit log entries.Also applies to: 216-216
go/pkg/db/plugins/bulk-insert/template.go (1)
27-28: Well-designed enhancement for bulk insert operations.The addition of
ValuesFieldsandUpdateFieldsprovides clear separation between fields used in the INSERT VALUES clause and the ON DUPLICATE KEY UPDATE clause. The descriptive comments make the purpose of each field clear.go/apps/api/routes/v2_keys_set_roles/handler.go (1)
228-228: Consistent audit log standardization.Replacing hardcoded resource type strings with
auditlog.KeyResourceTypeandauditlog.RoleResourceTypeconstants in both role removal and addition audit logs maintains consistency across the codebase and improves maintainability.Also applies to: 235-235, 272-272, 279-279
go/apps/api/openapi/spec/common/EmptyResponse.yaml (1)
4-4: Appropriate generalization for reusable schema.Changing the description from operation-specific "successful key deletion" to generic "successful operation" makes this EmptyResponse schema more reusable across different endpoints while maintaining the same semantic meaning.
go/apps/api/routes/v2_permissions_delete_permission/400_test.go (1)
60-60: Field name change aligns with API refactor.The change from
PermissionIdtoPermissionis consistent with the PR objective to allow either permission ID or slug in permission-related requests.go/apps/api/routes/v2_keys_add_roles/handler.go (1)
212-212: LGTM: Audit log constants improve consistency.Replacing hardcoded strings with
auditlog.KeyResourceTypeandauditlog.RoleResourceTypeconstants improves maintainability and ensures consistent resource type identifiers across the codebase.Also applies to: 219-219
go/apps/api/routes/v2_permissions_create_role/handler.go (1)
109-109: LGTM: Audit log constants improve consistency.Replacing hardcoded strings with
auditlog.RoleCreateEventandauditlog.RoleResourceTypeconstants improves maintainability and ensures consistent event and resource type identifiers across the codebase.Also applies to: 119-119
go/apps/api/routes/v2_permissions_get_permission/401_test.go (1)
26-26: Field name change aligns with API refactor.The change from
PermissionIdtoPermissionis consistent with the broader API standardization to allow either permission ID or slug in permission-related requests.go/pkg/zen/middleware_tracing.go (2)
7-7: LGTM: Import added for OpenTelemetry attributes.The import is correctly added to support the new span attribute functionality.
25-25: LGTM: Request ID attribute enhances observability.Adding the request ID as a span attribute improves traceability and correlation of requests across the system. The implementation correctly sets the attribute after span creation and before completion.
go/apps/api/routes/v2_permissions_delete_permission/401_test.go (1)
27-27: Field rename aligns with API standardization.The change from
PermissionIdtoPermissioncorrectly reflects the API update that allows either permission ID or slug to be provided in permission-related requests.go/apps/api/routes/v2_keys_delete_key/handler.go (1)
166-166: Response type standardization approved.The change to use
openapi.EmptyResponse{}standardizes empty success responses across the API, which improves consistency and maintainability.go/apps/api/routes/v2_permissions_delete_permission/200_test.go (1)
67-67: Consistent field rename across test cases.Both test cases correctly use the updated
Permissionfield name, maintaining consistency with the API model changes that allow either permission ID or slug.Also applies to: 126-126
go/pkg/db/queries/key_permission_delete_many_by_key_and_permission_ids.sql (1)
1-3: Well-implemented batch delete query.The SQL query correctly uses sqlc parameterization with
sqlc.arg()andsqlc.slice()for safe batch deletion of key-permission associations. This approach improves performance by replacing multiple individual delete operations with a single batch operation.go/apps/api/routes/v2_keys_remove_permissions/401_test.go (1)
59-60: Improved test structure with simplified request format.The changes improve the test in two ways:
- Using helper functions (
CreateApi,CreateKey) instead of manual database operations makes the test more maintainable- Simplifying the
Permissionsfield from complex objects to a simple string slice aligns with the API standardizationgo/pkg/db/queries/key_permission_insert.sql (1)
12-12: LGTM! Well-implemented upsert pattern.The addition of the
ON DUPLICATE KEY UPDATEclause transforms this into an efficient upsert operation that handles both new insertions and updates to existing key-permission associations. This supports the batch operations mentioned in the PR objectives while maintaining proper timestamp tracking.go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
47-47: LGTM! Field rename aligns with API model changes.The change from
PermissionIdtoPermissioncorrectly reflects the API model updates that allow either permission ID or slug. The test coverage remains comprehensive and tests important error scenarios.
68-68: Consistent field usage.Good consistency in using the renamed
Permissionfield across all test cases.
104-104: Proper test adaptation.The field rename is correctly applied to the already-deleted permission test case, maintaining the test's intent while conforming to the new API contract.
go/apps/api/routes/v2_keys_set_permissions/401_test.go (1)
79-81: LGTM! API simplification improves usability.The change from complex permission objects to a simple string array makes the API more intuitive while maintaining the same functionality. This aligns well with the PR objective to accept either permission ID or slug.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsResponseData.yaml (1)
15-15: LGTM! Good schema standardization.Replacing the inline permission object definition with a reference to the shared
Permission.yamlschema improves consistency and maintainability across the API while preserving the same semantic meaning.go/pkg/db/queries/permission_find_many_by_id_or_slug.sql (1)
1-4: LGTM! Well-designed batch permission lookup query.This query effectively supports the PR's core objective of accepting either permission IDs or slugs. The implementation correctly:
- Uses workspace scoping for security isolation
- Leverages sqlc.slice for safe parameterized batch queries
- Handles both ID and slug matching in a single efficient query
go/apps/api/routes/v2_permissions_create_permission/handler.go (2)
99-99: Good standardization of audit log event constants.Replacing the hardcoded string with
auditlog.PermissionCreateEventimproves maintainability and consistency across the codebase.
109-111: Appropriate audit log resource type standardization and field correction.The changes correctly:
- Use
auditlog.PermissionResourceTypeconstant for consistency- Set the resource
Nametoreq.Sluginstead ofreq.Name, which is more appropriate since slug serves as the unique identifier for permissionsgo/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleResponseBody.yaml (1)
4-9: Good API response standardization.Adding the required
dataproperty withEmptyResponsereference creates consistency across delete endpoints and provides a standardized response structure throughout the API.go/apps/api/routes/v2_keys_create_key/handler.go (4)
429-429: Good use of audit log resource type constants.Replacing hardcoded strings with
auditlog.KeyResourceTypeimproves consistency and maintainability.
436-436: Consistent audit log standardization.Using
auditlog.PermissionResourceTypeconstant aligns with the broader audit log standardization effort.
516-516: Proper audit log resource type constants for key and role.Both
auditlog.KeyResourceTypeandauditlog.RoleResourceTypeconstants are correctly used, maintaining consistency with the standardization pattern.Also applies to: 523-523
558-558: Complete audit log standardization for key creation.The use of
auditlog.KeyResourceTypeandauditlog.APIResourceTypeconstants completes the standardization of audit log resource types in this handler.Also applies to: 565-565
go/apps/api/openapi/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionResponseBody.yaml (1)
4-9: Consistent API response structure standardization.Adding the required
dataproperty withEmptyResponsereference maintains consistency with other delete endpoints and provides a unified response format across the API.go/apps/api/openapi/spec/paths/v2/keys/deleteKey/V2KeysDeleteKeyResponseBody.yaml (1)
4-4: LGTM! Good standardization of empty response format.The addition of
dataas a required property and the reference to the commonEmptyResponse.yamlschema aligns well with the API standardization effort mentioned in the PR objectives.Also applies to: 9-9
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (2)
35-35: LGTM! Proper RBAC permission scope added.Adding the
"rbac.*.remove_permission_from_key"permission ensures the root key has the necessary authorization for the permission removal operations being tested.
78-79: Excellent API simplification!The change from complex permission objects to simple string slices significantly improves the API's usability. The tests properly demonstrate that both permission IDs and names/slugs are accepted, which aligns perfectly with the PR objective of allowing "either permission id or slug in permission related requests."
Also applies to: 145-146, 222-223, 272-273, 361-362, 459-463
go/pkg/db/plugins/bulk-insert/parser.go (2)
14-17: LGTM! Clear addition for parameter separation.The new
ValuesPlaceholderCountfield provides a clean way to track the number of placeholders in the VALUES clause, which is essential for properly separating VALUES parameters from UPDATE parameters in bulk insert operations.
124-133: Simple and effective placeholder counting implementation.The
countPlaceholdersmethod is straightforward and correctly counts?characters in the values clause. The implementation is efficient and follows Go conventions.go/apps/api/openapi/spec/paths/v2/permissions/getPermission/V2PermissionsGetPermissionRequestBody.yaml (2)
3-3: LGTM! Good field name simplification.Renaming from
permissionIdtopermissionmakes the API more intuitive and aligns with the PR objective of accepting either permission ID or slug.Also applies to: 5-5
9-9: Improved regex pattern for flexible permission identifiers.The updated pattern
"^[a-zA-Z][a-zA-Z0-9._-]*$"is more flexible than the previous one, allowing dots and hyphens while still enforcing that identifiers start with a letter. This supports both permission IDs and slugs effectively.go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsResponseData.yaml (1)
15-15: Excellent schema standardization!Replacing the inline permission object definition with a reference to the common
Permission.yamlschema promotes consistency and reusability across the API. This aligns well with the broader API model simplification effort in this PR.go/pkg/db/bulk_key_permission_insert.sql.go (2)
12-12: LGTM: SQL query correctly implements upsert functionality.The addition of
ON DUPLICATE KEY UPDATE updated_at_m = ?enables efficient upsert operations for key-permission associations.
38-41: LGTM: Parameter handling correctly aligned with SQL query.The logic properly appends the
UpdatedAtparameter once after all value parameters, matching the single?placeholder in theON DUPLICATE KEY UPDATEclause.go/pkg/db/bulk_ratelimit_override_insert.sql.go (1)
43-48: LGTM: Consistent parameter handling pattern.The argument collection logic correctly follows the same pattern as the key permissions file, appending
UpdatedAtonce after all value parameters to match the SQL query structure.go/pkg/db/plugins/bulk-insert/bulk_insert.go.tmpl (2)
35-37: LGTM: Template correctly separates value and update fields.The template now properly distinguishes between
ValuesFields(for the VALUES clause) andUpdateFields(for ON DUPLICATE KEY UPDATE), appending only value fields per argument.
39-47: LGTM: Update fields handled correctly.The conditional logic properly appends
UpdateFieldsonly once after all value arguments, which aligns with the SQL requirement for ON DUPLICATE KEY UPDATE parameters.go/apps/api/routes/v2_permissions_get_permission/400_test.go (2)
37-51: LGTM: Test correctly updated for unified permission identifier.The test name and request structure properly reflect the API change to accept either permission ID or slug in the
Permissionfield.
53-67: LGTM: Consistent test pattern for empty permission field.The test correctly validates the empty permission identifier case using the new
Permissionfield name.go/apps/api/routes/v2_permissions_delete_permission/handler.go (2)
64-81: LGTM: Unified permission lookup with proper error handling.The handler correctly uses
FindPermissionByIdOrSlugto support both permission IDs and slugs, with appropriate workspace scoping and error handling.
84-106: LGTM: Deletion operations use resolved permission ID.The deletion operations correctly use
permission.IDfrom the resolved permission record rather than the raw request value, ensuring consistency.go/apps/api/routes/v2_keys_add_permissions/401_test.go (4)
15-15: LGTM: Import addition aligns with refactoring.The addition of the testutil/seed import is appropriate for the refactored test setup using helper functions.
36-44: LGTM: Cleaner test setup with helper functions.The refactoring from manual database inserts to the
CreateApihelper function improves test maintainability and reduces boilerplate code. The helper ensures consistent API creation across tests.
46-53: LGTM: Consistent use of helper functions.The
CreateKeyhelper function usage is consistent with the API creation pattern and simplifies the test setup.
66-67: LGTM: Simplified permission structure aligns with API changes.The change from a complex permission object structure to a simple string array aligns perfectly with the PR objective to allow either permission ID or slug in permission-related requests. This simplification makes the API more intuitive to use.
go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyResponseBody.yaml (2)
4-4: LGTM: Standardizes response structure.Making the
datafield required ensures consistency across API endpoints and aligns with the broader API standardization effort.
9-9: LGTM: Unified empty response schema.The change to reference the common
EmptyResponse.yamlschema reduces duplication and ensures consistent empty response structures across the API. This is a good architectural improvement.go/apps/api/routes/v2_permissions_get_permission/handler.go (1)
63-66: LGTM: Enhanced flexibility with proper security scoping.The change to
FindPermissionByIdOrSlugsuccessfully implements the PR objective of accepting either permission ID or slug. The workspace scoping is properly maintained through the query parameters, ensuring security while adding flexibility.The unified
req.Permissionfield name is more intuitive than the previousreq.PermissionId.go/apps/api/routes/v2_keys_set_permissions/400_test.go (2)
148-149: LGTM: Simplified permission structure in tests.The change from complex permission objects to a simple string array aligns with the API simplification objectives. Testing with an empty string is appropriate for validating the new string-based permission format.
162-162: LGTM: Updated error assertion for new validation.The change to expect generic "validate schema" errors is appropriate given the simplified permission structure and updated validation logic at the OpenAPI schema layer.
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (2)
37-37: LGTM: Appropriate RBAC permission for remove operations.The addition of "rbac.*.remove_permission_from_key" to the root key permissions is correct for testing the remove permissions endpoint. This ensures the test has the necessary authorization to perform the operation being tested.
59-60: LGTM: Consistent simplification across all test cases.The change from complex permission objects to simple string arrays is consistently applied across all test cases. This aligns with the API simplification and maintains the same test coverage while using the new, more intuitive permission format.
Also applies to: 97-98, 168-169, 239-240
go/apps/api/routes/v2_keys_update_key/handler.go (5)
109-110: Good practice: Audit log initialization inside transaction.Moving the audit log slice initialization inside the transaction ensures atomicity and prevents partial audit log creation if the transaction fails.
415-440: Excellent audit logging implementation for permission creation.The audit logging for permission creation is comprehensive with:
- Proper event type constants
- Detailed resource metadata
- Actor information including remote IP and user agent
Using
auditlog.PermissionResourceTypeconstant instead of string literals improves maintainability.
460-468: Correct timestamp handling for permission insertion.Using the same timestamp for both
CreatedAtandUpdatedAtduring initial insertion is the correct approach. Thesql.NullInt64wrapper properly handles the nullable field.
559-572: Good refactoring: Using resource type constants.Replacing string literals with
auditlog.KeyResourceTypeandauditlog.APIResourceTypeconstants improves code maintainability and reduces the risk of typos.
588-593: Good API standardization with EmptyResponse.Using
openapi.EmptyResponseinstead of an ad-hoc empty struct improves API consistency and maintainability across all endpoints.go/apps/api/routes/v2_keys_remove_permissions/403_test.go (2)
63-66: API simplification looks good.The change from complex permission objects to simple string arrays containing permission IDs aligns with the broader API simplification effort and improves usability.
141-144: Consistent API simplification.go/apps/api/routes/v2_keys_remove_permissions/400_test.go (1)
173-176: Consistent test update for API simplification.go/apps/api/openapi/spec/common/permission.yaml (1)
23-28: Minor description formatting change.The slug description was simplified to a single line. Based on the AI summary, the
createdAtfield was also removed from this schema, which aligns with the API simplification effort to remove unnecessary temporal data from responses.go/pkg/db/key_permission_insert.sql_generated.go (3)
10-10: Good addition of ON DUPLICATE KEY UPDATE clause.The addition of
ON DUPLICATE KEY UPDATE updated_at_m = ?enables idempotent permission assignments where re-adding an existing permission updates its timestamp rather than failing.Also applies to: 13-25
27-33: Proper struct updates for the new SQL behavior.The addition of db tags and the new
UpdatedAtfield properly support the ON DUPLICATE KEY UPDATE functionality. Usingsql.NullInt64correctly handles nullable timestamp values.
48-55: Correct parameter handling for updated SQL.The function correctly passes all parameters including the new
UpdatedAtfield to match the SQL statement's placeholders.go/apps/api/openapi/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionRequestBody.yaml (2)
3-3: LGTM! Field rename accurately reflects dual ID/slug support.The change from
permissionIdtopermissioncorrectly communicates that the field accepts either a permission ID or slug.Also applies to: 5-5
13-13: Clear documentation of dual ID/slug support.The description effectively communicates that both permission IDs and slugs are accepted.
go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsResponseData.yaml (2)
12-12: Excellent schema unification.Replacing the inline permission object definition with a reference to the shared
Permission.yamlschema improves consistency and maintainability across the API.
5-5: Good consolidation of documentation.The rename from "Important notes" to "Notes" is more concise while maintaining the essential information.
go/apps/api/routes/v2_keys_add_permissions/400_test.go (2)
36-36: Good addition of required RBAC permission.Adding
"rbac.*.add_permission_to_key"to the root key permissions correctly reflects the enhanced permission checks for this operation.
187-189: Correct simplification of request structure.The change from complex permission objects to a simple string slice aligns with the API schema simplification. The empty array test case is properly updated.
go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml (2)
22-22: Clear documentation of dual ID/slug support.The updated description effectively communicates that both permission IDs and slugs are accepted.
26-30: Good schema simplification with proper validation.The change from complex object structure to simple string type with validation constraints simplifies the API while maintaining proper input validation. The pattern and length constraints are appropriate for both permission IDs and slugs.
go/apps/api/routes/v2_keys_add_permissions/200_test.go (4)
32-32: Correct addition of required RBAC permission.Adding
"rbac.*.add_permission_to_key"ensures the root key has the necessary permissions for the enhanced permission checks.
74-76: Excellent simplification of request structure.The change from complex permission objects to simple string arrays makes the API much cleaner while maintaining the same functionality.
229-240: Good improvement in response validation logic.Using a helper function to check for permission presence without assuming order is more robust than direct array index comparisons. This correctly handles the fact that the response order may not be deterministic.
213-214: Comprehensive test coverage maintained.The test correctly demonstrates mixed usage of permission IDs and slugs in a single request, which validates the core functionality of this PR.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (4)
35-35: LGTM! Appropriate RBAC permissions added.The addition of
"rbac.*.remove_permission_from_key"and"rbac.*.add_permission_to_key"permissions to the root key creation is appropriate for permission management operations and aligns with the broader RBAC enhancements in this PR.
109-111: LGTM! Simplified request structure aligns with API changes.The simplification from complex permission objects to a straightforward string array for
Permissionsmakes the API more intuitive and flexible, allowing either permission IDs or slugs as intended by the PR objectives.
125-136: Excellent defensive programming for response validation.The
containshelper function properly handles flexible ordering in the response data, making the test more robust against implementation changes while still validating the correct permissions are returned.
372-428: Great test coverage for automatic permission creation.This test case effectively validates the on-the-fly permission creation feature mentioned in the PR objectives, ensuring that non-existent permission slugs are automatically created and properly assigned to keys.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (2)
36-61: LGTM! Improved test setup with helper functions.The refactoring to use
CreateApiandCreateKeyhelper functions from theseedpackage makes the test setup cleaner and more maintainable compared to manual database operations.
74-75: LGTM! Consistent with simplified API structure.The simplified
Permissionsfield using a string array aligns with the API changes and maintains consistency across the test suite.go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (2)
15-16: LGTM! Proper workspace scoping and flexible ID/slug lookup.The SQL query correctly scopes permissions to the workspace (preventing cross-workspace access) and efficiently handles lookup by either ID or slug using OR logic, which aligns perfectly with the PR objectives.
28-41: LGTM! Clean generated query implementation.The generated function properly handles parameter binding, query execution, and result scanning. The reuse of the
Searchparameter for both ID and slug matching is efficient and correct.go/pkg/db/permission_find_many_by_id_or_slug.sql_generated.go (1)
33-48: Fix duplicate parameter processing causing query parameter mismatch.The code duplicates the parameter processing logic, adding each ID from
arg.IdstoqueryParamsfour times total (twice in lines 33-40, twice again in lines 41-48). However, the SQL query expects each ID only twice (once for theid INclause, once for theslug INclause).queryParams = append(queryParams, arg.WorkspaceID) if len(arg.Ids) > 0 { for _, v := range arg.Ids { queryParams = append(queryParams, v) } query = strings.Replace(query, "/*SLICE:ids*/?", strings.Repeat(",?", len(arg.Ids))[1:], 1) } else { query = strings.Replace(query, "/*SLICE:ids*/?", "NULL", 1) } - if len(arg.Ids) > 0 { - for _, v := range arg.Ids { - queryParams = append(queryParams, v) - } - query = strings.Replace(query, "/*SLICE:ids*/?", strings.Repeat(",?", len(arg.Ids))[1:], 1) - } else { - query = strings.Replace(query, "/*SLICE:ids*/?", "NULL", 1) - } + // Second replacement for slug IN clause + if len(arg.Ids) > 0 { + for _, v := range arg.Ids { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:ids*/?", strings.Repeat(",?", len(arg.Ids))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:ids*/?", "NULL", 1) + }Likely an incorrect or invalid review comment.
go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (2)
14-16: LGTM! Efficient batch deletion query design.The SQL DELETE statement correctly targets the
keys_permissionsjunction table with proper filtering bykey_idand a list ofpermission_idvalues, enabling efficient batch removal of multiple permissions from a key in a single database operation.
31-38: LGTM! Proper dynamic query construction.The slice replacement logic correctly handles both non-empty slices (building appropriate placeholder list) and empty slices (using NULL), ensuring the query remains valid in all cases while avoiding SQL injection vulnerabilities.
go/apps/api/routes/v2_permissions_get_permission/200_test.go (4)
42-56: LGTM: Good test setup refactoring.Moving the permission creation outside individual test cases reduces duplication and makes the test more maintainable. The setup correctly creates all necessary fields including the slug.
59-84: LGTM: Correct field rename and test logic.The field rename from
PermissionIdtoPermissionaligns with the PR objective of accepting either ID or slug. The test assertions properly verify all expected fields.
86-106: LGTM: Good test coverage for slug-based retrieval.The new test case properly verifies that permissions can be retrieved by slug, which is a key feature of this PR. The assertions correctly verify that the same permission data is returned regardless of whether accessed by ID or slug.
126-126: LGTM: Consistent field usage.The field name change is consistently applied across all test cases.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (5)
36-36: LGTM: Correct permission scope addition.Adding
rbac.*.add_permission_to_keyto the root key permissions is appropriate for the enhanced functionality being tested.
60-62: LGTM: Simplified request structure.The simplification from complex permission objects to a string slice makes the API more intuitive and aligns with the PR objectives of accepting either ID or slug as strings.
95-95: LGTM: Correct permission prefix usage.Using
uid.PermissionPrefixinstead ofuid.TestPrefixis more semantically correct for permission ID generation in tests.
98-100: LGTM: Consistent simplified request structure.The simplified request structure is consistently applied across test cases.
154-156: LGTM: Consistent field usage across test cases.The simplified request structure is properly maintained across all test scenarios.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml (3)
18-18: LGTM: Reasonable array size limit.The increase to maxItems: 1000 provides good flexibility while maintaining reasonable bounds for bulk operations.
23-26: LGTM: Clear documentation of new behavior.The documentation clearly explains that both permission slugs and IDs are accepted, and describes the auto-creation behavior when using slugs. This aligns perfectly with the PR objectives.
28-32: Pattern is intentional and consistent across key permission endpointsThe regex
^[a-zA-Z][a-zA-Z0-9._-]*$is used uniformly by all V2 key-related request bodies (createKey, updateKey, addPermissions, etc.) to support hierarchical permission patterns (e.g.resource.resource_id.action) and wildcards. This differs from the slug pattern for permission entities (^[a-zA-Z0-9_]+$) and is documented inopenapi-split.yaml(“Key permissions follow a hierarchical structure with patterns likeapis.*.create_key”). You can safely ignore this suggestion.Likely an incorrect or invalid review comment.
go/apps/api/routes/v2_keys_add_permissions/403_test.go (7)
15-15: LGTM: Appropriate import addition.Adding the seed package import enables the use of helper functions for cleaner test setup.
36-44: LGTM: Improved test setup using helpers.Replacing manual database inserts with helper functions makes the test more maintainable and consistent with other tests in the codebase.
46-61: LGTM: Consistent helper usage.Using the CreateKey helper function provides better consistency across tests and reduces boilerplate code.
74-76: LGTM: Simplified request structure.The simplified Permissions field as a string slice makes the API more intuitive and aligns with the PR objectives.
121-131: LGTM: Consistent test setup pattern.The use of helper functions for creating workspace, API, and key entities follows a consistent pattern and improves test maintainability.
Also applies to: 133-148
151-151: LGTM: Correct permission scope.Adding
rbac.*.add_permission_to_keyto the root key permissions is appropriate for testing the enhanced functionality.
154-156: LGTM: Consistent request structure.The simplified request structure is consistently applied across all test scenarios.
go/pkg/db/plugins/bulk-insert/generator.go (3)
57-61: LGTM: More idiomatic prefix handling.Using
strings.CutPrefixis cleaner and more idiomatic thanstrings.TrimPrefix+strings.HasPrefixpattern. The boolean return value also provides better validation.
113-127: LGTM: Well-designed field separation logic.The logic to separate fields based on
ValuesPlaceholderCountis well-reasoned and correctly handles SQL queries withON DUPLICATE KEY UPDATEclauses. The comment clearly explains the approach and the guarantee about parameter ordering from sqlc.
140-142: LGTM: Consistent template data structure.Passing the separated
ValuesFieldsandUpdateFieldsto the template renderer enables proper handling of complex SQL queries in the generated code.go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml (2)
6-14: Good security improvements for keyId validation.The addition of maxLength and pattern constraints helps prevent injection attacks and ensures data integrity. The clarified description also helps distinguish between the database identifier and the actual API key string.
15-30: Breaking change: Simplified permissions format and regex updateThe change replaces the previous object‐based permission definitions with a string array and updates the regex from
^[a-zA-Z0-9_]+$to^[a-zA-Z][a-zA-Z0-9._-]*$. This may break existing clients expecting objects or the old pattern.Please verify manually:
- That this breaking change is intentional and has been communicated to API consumers.
- The new string‐only permissions format and regex are applied consistently across all OpenAPI specs under
go/apps/api/openapi/spec/paths.- No remaining endpoints or test fixtures still reference the old object‐based structure or regex.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (3)
35-35: LGTM! Root key permissions correctly updated.The addition of
rbac.*.remove_permission_from_keyandrbac.*.add_permission_to_keypermissions aligns with the new RBAC requirements in the handler.
95-95: Good fix: Corrected UID prefix for permission IDs.Using
uid.PermissionPrefixinstead ofuid.TestPrefixgenerates proper permission IDs with the "perm_" prefix, making the tests more realistic and accurate.Also applies to: 195-195
58-61: Test requests correctly updated for new API format.All test cases properly use string slices for permissions instead of the previous struct format, maintaining test coverage for the simplified API.
Also applies to: 97-100, 147-150, 197-200
go/pkg/db/querier_generated.go (1)
42-46: Generated database interfaces properly support new batch operations.The new methods enable efficient batch deletions and lookups by ID or slug, while the ON DUPLICATE KEY UPDATE clause in InsertKeyPermission ensures idempotent permission assignments.
Also applies to: 312-317, 326-331, 746-746
go/apps/api/routes/v2_keys_add_permissions/handler.go (5)
58-65: Correct use of FindKeyByIdOrHash with explicit null handling.The change properly uses the unified lookup method with clear null value handling for the hash parameter.
85-111: Excellent security enhancement with combined RBAC checks.The requirement for both API update permissions and explicit
rbac.*.add_permission_to_keypermission provides proper separation of concerns and prevents unauthorized permission management.
187-289: Excellent transaction management and bulk operations.The code properly uses transactions for consistency, performs efficient bulk inserts, and ensures audit logs are created atomically with the permission changes. Cache invalidation after the transaction is also correctly placed.
292-322: Clean response construction with proper nil handling.The code correctly merges existing and new permissions, and properly handles the optional description field.
194-214: Good use of audit log constants.Replacing hardcoded strings with
auditlogpackage constants improves maintainability and prevents typos.Also applies to: 252-264
go/apps/api/routes/v2_keys_remove_permissions/handler.go (4)
88-114: Correct RBAC implementation for remove operation.The combined checks properly require both API update permissions and the specific
rbac.*.remove_permission_from_keypermission, maintaining security consistency with the add operation.
140-167: Robust permission validation and filtering.The code properly validates all permissions exist before removal and filters to only remove permissions actually assigned to the key, making the operation idempotent and safe.
204-215: Efficient batch deletion implementation.Using
DeleteManyKeyPermissionByKeyAndPermissionIDsfor batch deletion is much more efficient than individual delete operations.
230-244: Efficient response construction using in-memory state.Excellent optimization - using the already-updated
currentPermissionIDsmap avoids an unnecessary database query while providing the correct remaining permissions.go/apps/api/routes/v2_keys_set_permissions/handler.go (6)
61-67: Good improvement for key lookup flexibility.The change from
FindKeyByIDtoFindKeyByIdOrHashwith explicit null handling allows for more flexible key lookups in the future while maintaining backward compatibility.
88-118: Enhanced security with combined RBAC checks.The new permission structure properly enforces that setting permissions requires both update rights on the key AND explicit add/remove permission rights. This is a good security improvement that follows the principle of least privilege.
128-137: Efficient bulk permission lookup implementation.The change to
FindManyPermissionsByIdOrSlugimproves performance by querying all permissions in a single database call and supports the PR objective of accepting either permission IDs or slugs.
139-183: Well-implemented permission resolution with auto-creation.The logic correctly handles the PR requirement of accepting either permission ID or slug, and the auto-creation of non-system permissions (those not starting with "perm_") is implemented as specified. The dual deletion approach (lines 148-149) elegantly handles both ID and slug lookups.
215-296: Excellent use of batch operations for performance.The implementation efficiently uses
DeleteManyKeyPermissionByKeyAndPermissionIDsfor batch deletion andInsertPermissionsfor batch creation, significantly improving performance compared to individual operations. The transaction handling ensures atomicity.
231-337: Comprehensive audit logging implementation.The audit logging covers all operations (remove, create, add) with proper event types and detailed metadata. Good use of constants from the auditlog package for consistency.
go/apps/api/openapi/gen.go (1)
1-4: Auto-generated code correctly regenerated from updated OpenAPI specsThe PR includes updates to the OpenAPI spec files under
go/apps/api/openapi/spec/…to introduceEmptyResponseand support permission ID/slug fields, and thegen.gofile reflects those changes via a freshoapi-codegenrun. No manual edits should be made to this generated file.– Spec files updated (e.g.
paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml,paths/v2/apis/deleteApi/V2ApisDeleteApiResponseBody.yaml, etc.)
–go/apps/api/openapi/gen.goregenerated byoapi-codegen v2.4.1No further action required here; changes belong in the
.yamlsources, not ingen.go.go/apps/api/openapi/openapi-generated.yaml (6)
1-4: No concerns with generated header – safe to ignore.
204-214: 👍 Consistent empty-payload envelope
Requiringdataand pointing it to#/components/schemas/EmptyResponsekeeps responses uniform and aids SDK generation.
857-866: Uniform empty response envelope confirmed – LGTM
1312-1321: No issues – envelope consistent
1513-1527: Good – deletion accepts slug or ID and length 255 fits IDs
2115-2118:EmptyResponseaddition approved – keeps SDK models DRY.
go/apps/api/openapi/spec/paths/v2/apis/deleteApi/V2ApisDeleteApiResponseBody.yaml
Show resolved
Hide resolved
...api/spec/paths/v2/permissions/deletePermission/V2PermissionsDeletePermissionRequestBody.yaml
Show resolved
Hide resolved
This stack of pull requests is managed by Graphite. Learn more about stacking. |
chronark
left a comment
There was a problem hiding this comment.
let's think about how we can avoid relying on the prefix, the rest looks good
|
Thank you for following the naming conventions for pull request titles! 🙏 |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (5)
go/apps/api/routes/v2_keys_set_permissions/403_test.go (1)
144-164: Note: Duplicate test case mentioned in past reviewBased on previous review comments, there appears to be a duplicate of this test case later in the file. Please verify and remove any duplicate "permission for different resource" test cases to keep the test suite clean.
go/apps/api/openapi/openapi-generated.yaml (4)
568-574: Repeated regex/length block – factor out aPermissionIdentifiercomponent.This exact
{minLength,maxLength,pattern}tuple now appears in add, remove, set and several other request bodies. Duplicating it invites drift. Define a reusable schema:components: schemas: PermissionIdentifier: type: string minLength: 1 maxLength: 100 pattern: "^[a-zA-Z][a-zA-Z0-9._-]*$"… and replace every inline
items:block withitems: $ref: "#/components/schemas/PermissionIdentifier"
928-947: Same slug-only wording here – needs “slug or ID”.See earlier comment for
addPermissions. Keep the wording consistent across all permission arrays.
1030-1039:keyIdpattern still too lax – does not enforce the requiredkey_prefix.Docs (and
uid.New(uid.KeyPrefix)) guarantee every DB key starts withkey_. Leaving the pattern as^[a-zA-Z0-9_]+$accepts invalid IDs (fooBar). Tighten it:- pattern: "^[a-zA-Z0-9_]+$" + pattern: "^key_[a-zA-Z0-9]+$"
1602-1605: Description claimsperm_prefix is mandatory, but regex does not enforce it.Exactly the same divergence as in the delete-permission body. Pick one approach – either require IDs here or accept both identifiers and adjust the description/pattern accordingly.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (22)
go/apps/api/openapi/gen.go(13 hunks)go/apps/api/openapi/openapi-generated.yaml(15 hunks)go/apps/api/openapi/spec/common/permission.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/verifyKey/V2KeysVerifyKeyRequestBody.yaml(1 hunks)go/apps/api/routes/v2_keys_add_permissions/200_test.go(7 hunks)go/apps/api/routes/v2_keys_add_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_add_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_create_key/handler.go(5 hunks)go/apps/api/routes/v2_keys_remove_permissions/200_test.go(9 hunks)go/apps/api/routes/v2_keys_remove_permissions/handler.go(5 hunks)go/apps/api/routes/v2_keys_set_permissions/200_test.go(9 hunks)go/apps/api/routes/v2_keys_set_permissions/403_test.go(3 hunks)go/apps/api/routes/v2_keys_set_permissions/404_test.go(3 hunks)go/apps/api/routes/v2_keys_set_permissions/handler.go(5 hunks)go/apps/api/routes/v2_keys_update_key/handler.go(7 hunks)go/pkg/db/permission_find_by_slugs.sql_generated.go(2 hunks)go/pkg/db/querier_generated.go(4 hunks)go/pkg/db/queries/permission_find_by_slugs.sql(1 hunks)
🧰 Additional context used
🧠 Learnings (22)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/openapi/spec/paths/v2/keys/verifyKey/V2KeysVerifyKeyRequestBody.yaml (3)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/routes/v2_keys_create_key/handler.go (4)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (7)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/routes/v2_keys_add_permissions/200_test.go (4)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/pkg/db/permission_find_by_slugs.sql_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (4)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyRequestBody.yaml (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml (5)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
go/apps/api/openapi/spec/common/permission.yaml (3)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (8)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
go/apps/api/routes/v2_keys_update_key/handler.go (6)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_remove_permissions/handler.go (8)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_add_permissions/handler.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_set_permissions/handler.go (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/pkg/db/querier_generated.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/gen.go (11)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3647
File: go/apps/api/openapi/openapi-generated.yaml:3569-3575
Timestamp: 2025-07-22T18:09:41.800Z
Learning: In the Unkey codebase, using non-standard HTTP status code 529 for internal-only endpoints is acceptable and should not be flagged as an issue in future reviews.
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{env,sh,yaml,yml,json,conf,ini} : All environment variables MUST follow the format UNKEY_<SERVICE_NAME>_VARNAME.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
go/apps/api/openapi/openapi-generated.yaml (14)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
🧬 Code Graph Analysis (7)
go/apps/api/routes/v2_keys_set_permissions/403_test.go (2)
go/pkg/testutil/seed/seed.go (1)
CreateApiRequest(78-86)go/pkg/uid/uid.go (1)
PermissionPrefix(27-27)
go/apps/api/routes/v2_keys_add_permissions/200_test.go (4)
go/pkg/codes/unkey_data.go (1)
Data(87-128)go/pkg/rbac/permissions.go (1)
CreatePermission(105-105)go/pkg/testutil/seed/seed.go (1)
CreatePermissionRequest(396-401)go/apps/api/routes/v2_keys_add_permissions/handler.go (1)
Request(24-24)
go/pkg/db/permission_find_by_slugs.sql_generated.go (2)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/apps/api/openapi/gen.go (1)
Permission(366-386)
go/apps/api/routes/v2_keys_add_permissions/404_test.go (1)
go/pkg/uid/uid.go (1)
PermissionPrefix(27-27)
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (2)
go/pkg/testutil/seed/seed.go (1)
CreatePermissionRequest(396-401)go/apps/api/routes/v2_keys_remove_permissions/handler.go (1)
Request(22-22)
go/pkg/db/querier_generated.go (5)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (1)
DeleteManyKeyPermissionByKeyAndPermissionIDsParams(18-21)go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (1)
FindPermissionByIdOrSlugParams(18-21)go/pkg/db/models_generated.go (1)
Permission(744-752)go/pkg/db/permission_find_by_slugs.sql_generated.go (1)
FindPermissionsBySlugsParams(17-20)
go/apps/api/openapi/gen.go (2)
go/pkg/codes/unkey_data.go (1)
Data(87-128)go/pkg/db/models_generated.go (1)
Permission(744-752)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Build / Build
- GitHub Check: Test Go API Local / Test
- GitHub Check: Test API / API Test Local
- GitHub Check: Test Packages / Test
🔇 Additional comments (42)
go/apps/api/openapi/spec/paths/v2/keys/verifyKey/V2KeysVerifyKeyRequestBody.yaml (1)
11-11: LGTM: Whitespace cleanupGood housekeeping - removing trailing whitespace from the summary field.
go/pkg/db/queries/permission_find_by_slugs.sql (1)
2-2: LGTM: Enhanced query to return full permission dataChanging from
SELECT id, slugtoSELECT *provides complete permission objects, which aligns with the broader API refactoring to use full permission structs instead of partial data.go/apps/api/routes/v2_keys_set_permissions/403_test.go (4)
15-15: LGTM: Improved test setup with helper functionsGood refactoring to use the
seedpackage helpers instead of manual database insertions. This makes the test more maintainable and consistent with other tests.
36-61: LGTM: Clean test data creationUsing
CreateApiandCreateKeyhelpers significantly simplifies the test setup and removes the need for manual timestamp and hash management.
63-63: LGTM: Correct permission ID prefixGood fix - using
uid.PermissionPrefixinstead of the incorrectuid.TestPrefixensures proper permission ID generation.
74-76: LGTM: Simplified request structureThe change from complex permission objects to a simple string slice aligns with the API simplification effort and makes the test more readable.
go/apps/api/openapi/spec/paths/v2/keys/updateKey/V2KeysUpdateKeyRequestBody.yaml (1)
121-123: LGTM: Enhanced permission validationThe validation updates are well-designed:
- Increased
minLengthto 3 enforces more meaningful permission names- Updated regex pattern
^[a-zA-Z0-9_:\-\.\*]+$appropriately supports:
- Colons for namespaced permissions (e.g.,
api:read)- Asterisks for wildcard permissions (e.g.,
documents.*)- Removes the restrictive requirement for first character to be a letter
These changes align with the broader API simplification and provide more flexibility for permission naming conventions.
go/apps/api/routes/v2_keys_create_key/handler.go (4)
366-369: LGTM: Enhanced permission data handlingGood change from partial
FindPermissionsBySlugsRowto fulldb.Permissionstructs. This provides complete permission information and aligns with the API's move toward using full permission objects.
372-372: LGTM: Consistent use of full Permission structsUsing complete
db.Permissionstructs throughout the permission handling logic ensures consistency and provides all necessary permission data for downstream operations.Also applies to: 391-399
387-387: LGTM: Reasonable default for auto-created permissionsSetting an empty description for auto-created permissions is appropriate - it can be updated later through the management API, and the slug/name fields provide sufficient identification.
434-434: LGTM: Audit log constants improve maintainabilityExcellent refactoring to use
auditlogpackage constants instead of string literals. This prevents typos, ensures consistency across the codebase, and makes audit log resource types centrally managed.Also applies to: 441-441, 521-521, 528-528, 563-563, 570-570
go/apps/api/routes/v2_keys_update_key/handler.go (3)
383-412: LGTM! Improved permission handling with full objects.The refactoring to use a map of full
Permissionobjects and track requested permissions enables efficient lookups and proper metadata handling for auto-created permissions.
415-439: Excellent audit logging for permission creation.The comprehensive audit logs capture all relevant details about auto-created permissions, improving traceability and compliance.
460-467: LGTM! Consistent timestamp handling.Using the same timestamp for both
CreatedAtandUpdatedAtwhen inserting new records is the correct approach.go/apps/api/routes/v2_keys_remove_permissions/200_test.go (2)
35-35: LGTM! Proper RBAC permission for removing permissions.The root key correctly includes the
rbac.*.remove_permission_from_keypermission required for this operation.
155-167: Good practice: Order-independent permission verification.The
containshelper function properly verifies permission presence without assuming a specific order in the response.go/pkg/db/permission_find_by_slugs.sql_generated.go (1)
14-65: LGTM! Enhanced query returns complete permission data.The updated query returns full
Permissionobjects instead of partial data, enabling handlers to access all permission metadata for authorization checks and audit logging. This aligns with the API's simplified permission management approach.go/apps/api/openapi/spec/common/permission.yaml (1)
24-24: Review permission slug regex for expanded character setPlease verify that the updated slug pattern in
go/apps/api/openapi/spec/common/permission.yamlaligns with our validation requirements:
- Location: Line 24
- Current pattern:
pattern: ^[a-zA-Z0-9_:\-\.\*]+$- Concern: This now permits
:,-,., and*in addition to alphanumeric and underscore, whereas existing slugs (per OpenAPI schema and handler validation) use only[a-zA-Z0-9_]+.- Action:
- Confirm whether colons, hyphens, periods, and asterisks are intentionally allowed for permission slugs.
- Ensure consistency with other slug validations across your OpenAPI specs and handlers, or revert the regex to enforce only alphanumeric and underscore if not intended.
go/apps/api/routes/v2_keys_add_permissions/200_test.go (1)
32-32: LGTM! Complete RBAC permissions for permission management.The root key correctly includes both
rbac.*.add_permission_to_keyandrbac.*.create_permissionpermissions, enabling full permission management functionality including auto-creation.go/apps/api/openapi/spec/paths/v2/keys/removePermissions/V2KeysRemovePermissionsRequestBody.yaml (1)
21-30: LGTM! Schema simplification improves API usability.The change from complex permission objects to simple strings significantly simplifies the API while maintaining functionality. The expanded regex pattern
^[a-zA-Z0-9_:\-\.\*]+$appropriately supports hierarchical permission naming conventions with separators like colons and dots.go/apps/api/routes/v2_keys_set_permissions/200_test.go (3)
112-114: LGTM! Simplified request structure improves usability.The change from complex permission objects to a simple string array significantly simplifies the API while maintaining all necessary functionality.
128-140: Well-implemented response validation helper.The
containshelper function provides a clean way to verify response data without relying on specific ordering, which is more robust than fixed index assertions.
35-35: Please confirm the necessity of the expanded RBAC scopesI couldn’t find any references in
go/apps/api/routes/v2_keys_set_permissions/handler.gothat check for or invoke acreate_permissionscope (or other new RBAC permissions). Before approving these additions, please:
- Manually verify that the handler enforces or needs each of the newly added RBAC scopes (especially
"rbac.*.create_permission").- If any of the expanded permissions aren’t actually used by the endpoint, consider removing them from the test setup to avoid confusion.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (3)
36-36: LGTM! Appropriate RBAC permissions for add operation.The root key correctly includes the
"rbac.*.add_permission_to_key"permission scope needed for the add permissions functionality.
46-46: Correct permission ID prefix usage.Good use of
uid.PermissionPrefixinstead of generic test prefix, aligning with the established UID conventions in the codebase.
117-119: Confirm Permission Resolution for IDs and SlugsI wasn’t able to locate any explicit lookup or resolution logic in
go/apps/api/routes/v2_keys_add_permissions/handler.gothat handles both raw UUIDs and human-friendly slugs for permissions. Please manually verify that:
- The handler (or underlying service) accepts a mixed array of permission identifiers (both IDs and slugs).
- Any repository or service call invoked by this handler normalizes or resolves slugs to their corresponding IDs before granting permissions.
go/apps/api/openapi/spec/paths/v2/keys/addPermissions/V2KeysAddPermissionsRequestBody.yaml (2)
25-30: LGTM! Well-designed schema with clear auto-creation behavior.The simplified string-based permission format significantly improves API usability. The expanded regex pattern
^[a-zA-Z0-9_:\-\.\*]+$appropriately supports hierarchical permission naming with separators, and the auto-creation behavior is clearly documented.
18-18: Appropriate limit for permission sets.The
maxItems: 1000limit provides reasonable protection against abuse while allowing for complex applications with extensive permission sets.go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml (2)
9-14: LGTM! Consistent keyId validation.The keyId validation constraints (maxLength: 255, pattern for alphanumeric + underscore) are appropriate and consistent with other permission endpoints.
18-27: Clear documentation of replacement behavior.The description clearly explains that this is a "complete replacement operation" that overwrites existing direct permissions, which is important for API consumers to understand.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (1)
35-35: LGTM! Test updates align with API simplifications.The changes correctly reflect the simplified permission request format where permissions are now represented as strings (IDs or slugs) rather than complex objects. The additional RBAC permissions for the root key (
rbac.*.add_permission_to_keyandrbac.*.remove_permission_from_key) are appropriate for the permission management operations.Also applies to: 59-60, 109-110
go/pkg/db/querier_generated.go (1)
42-46: Well-aligned database interface enhancements.The generated database methods properly support the refactored permission management:
DeleteManyKeyPermissionByKeyAndPermissionIDsenables efficient batch deletionFindPermissionByIdOrSlugsupports unified permission lookupsFindPermissionsBySlugsnow returns fullPermissionstructs for richer responsesInsertKeyPermissionincludesON DUPLICATE KEY UPDATEto handle idempotent operationsThese changes align perfectly with the handler refactoring for improved efficiency and consistency.
Also applies to: 320-325, 342-345, 740-741
go/apps/api/routes/v2_keys_add_permissions/handler.go (2)
57-65: Excellent refactoring with improved efficiency and security.The handler improvements are well-implemented:
- RBAC checks properly combine update key and add permission requirements
- Batch permission resolution via
FindPermissionsBySlugsreduces database queries- Auto-creation of missing permissions is controlled by explicit RBAC checks
- The removal of string prefix inference (no more checking for "perm_" prefix) addresses the previous concern about inferring behavior from strings
The batch processing approach significantly improves performance.
Also applies to: 84-110, 119-188
190-288: Well-structured transaction with comprehensive audit logging.The transaction properly handles:
- Batch insertion of new permissions with appropriate audit events
- Batch assignment of permissions to keys using
ON DUPLICATE KEY UPDATE- Standardized audit log constants from the
auditlogpackage- Clear separation of permission creation vs assignment events
The audit trail will be invaluable for compliance and debugging.
go/apps/api/routes/v2_keys_set_permissions/handler.go (2)
87-118: Appropriate RBAC requirements for set operation.The combined RBAC check correctly requires both
AddPermissionToKeyandRemovePermissionFromKeypermissions, which is appropriate since the set operation can both add and remove permissions. This ensures proper authorization for the full scope of the operation.
188-214: Efficient permission diffing and batch operations.The implementation efficiently determines which permissions to add and remove:
- Clean mapping structures for O(1) lookups
- Single batch delete operation for all removals
- Proper audit logging for each removed permission
- No unnecessary database queries
The approach minimizes database operations while maintaining data consistency.
Also applies to: 218-263
go/apps/api/routes/v2_keys_remove_permissions/handler.go (2)
88-114: Consistent implementation with proper validation.The handler follows the established pattern:
- Appropriate RBAC check for update key + remove permission
- Batch permission lookup for efficiency
- Proper validation that all requested permissions exist before removal
- Clear error messages for missing permissions
The consistency across all permission handlers improves maintainability.
Also applies to: 129-156
169-228: Clean batch deletion with comprehensive audit trail.The removal logic is well-implemented:
- Efficient batch deletion via
DeleteManyKeyPermissionByKeyAndPermissionIDs- Proper audit logging for each removed permission
- Cache invalidation only when changes are made
- Response built from the updated in-memory state
The implementation minimizes database operations while maintaining a complete audit trail.
go/apps/api/openapi/gen.go (1)
1-2386: This is auto-generated code - do not modify directlyThis file is generated from OpenAPI specifications as indicated by the header comment. Any changes should be made to the source OpenAPI specification files (in
go/apps/api/openapi/spec/) and then regenerated using the code generation process.The generated changes correctly reflect the PR objectives:
- New
EmptyResponsetype for standardized empty responses- Simplified permission fields accepting
[]stringfor IDs or slugs- Updated documentation mentioning auto-creation behavior
go/apps/api/openapi/openapi-generated.yaml (3)
204-213: 👍 Good move replacing per-endpoint empty objects with a sharedEmptyResponse.The
meta + data(EmptyResponse)envelope is consistent with the rest of the spec and avoids dozens of bespoke “{}” schemas.
2119-2123: LGTM – conciseEmptyResponsecomponent is clean and future-proof.
1523-1531: Pattern allows dots/- but IDs begin withperm_– mismatch with “ID or slug” promise.If a client passes an ID (
perm_abcd), it matches; fine.
If the doc says “slug or ID”, the pattern should remain broad but the description (line 1527) must reflect that and drop the “Must begin with perm_” phrase. Either:
- Keep broad pattern and change description to “permission ID or slug”, or
- Split into two oneOf schemas to validate strictly.
Current mixed message will confuse integrators.
⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3617 File: go/apps/api/openapi/openapi.yaml:3309-3312 Timestamp: 2025-07-16T17:51:57.297Z Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466 Timestamp: 2025-07-15T14:25:05.608Z Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.Learnt from: MichaelUnkey PR: unkeyed/unkey#3173 File: apps/docs/security/delete-protection.mdx:32-36 Timestamp: 2025-04-22T17:33:28.162Z Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.Learnt from: MichaelUnkey PR: unkeyed/unkey#3173 File: apps/docs/security/delete-protection.mdx:21-24 Timestamp: 2025-04-22T17:34:04.438Z Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581 Timestamp: 2025-07-15T14:47:20.490Z Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.Learnt from: Flo4604 PR: unkeyed/unkey#3421 File: go/apps/api/openapi/openapi.yaml:196-200 Timestamp: 2025-07-03T05:58:10.699Z Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as `description`) alongside `$ref` in schema objects. Do not flag this as an error in future reviews.
go/apps/api/openapi/spec/paths/v2/keys/setPermissions/V2KeysSetPermissionsRequestBody.yaml
Show resolved
Hide resolved
feat: replace roleId with singular role field
Merge activity
|
There was a problem hiding this comment.
Actionable comments posted: 16
🔭 Outside diff range comments (1)
go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml (1)
5-24: LGTM: Field renamed to support ID or name with appropriate validation.The change from
roleIdtorolewith the relaxed pattern correctly implements the PR objective to accept either role ID or name. The validation pattern matches the established role name format from the codebase learnings.Consider updating the example to show a role name instead of a role ID, or provide two examples to clarify both accepted formats:
- example: role_dns_manager + examples: + role_id: role_dns_manager + role_name: dns_manager
♻️ Duplicate comments (10)
go/apps/api/routes/v2_keys_add_permissions/400_test.go (1)
202-202: Ensure Specific Validation Error Tests Are RetainedThe test now only asserts a generic "failed to validate schema" error message, which reduces clarity on user-facing error feedback. This risks losing specificity about what exactly failed validation (e.g., missing permission ID or slug).
go/apps/api/routes/v2_keys_update_key/handler.go (1)
92-92: TODO already tracked for separate PR.This TODO comment about role permission checks has already been discussed and will be addressed in a separate PR as confirmed by the author.
go/apps/api/routes/v2_keys_add_permissions/handler.go (2)
58-64: Use FindKeyByID instead of FindKeyByIdOrHashSame as in the set permissions handler - since the hash parameter is always invalid, use the simpler
FindKeyByIDfunction.-key, err := db.Query.FindKeyByIdOrHash(ctx, - h.DB.RO(), - db.FindKeyByIdOrHashParams{ - ID: sql.NullString{String: req.KeyId, Valid: true}, - Hash: sql.NullString{String: "", Valid: false}, - }, -) +key, err := db.Query.FindKeyByID(ctx, h.DB.RO(), req.KeyId)
140-147: Same issue with permission ID vs slug handlingThis handler has the same limitation as the set permissions handler - it only handles permission slugs, not IDs, despite the PR objective to support both.
go/apps/api/openapi/openapi-generated.yaml (6)
540-545: Description still says “slug” only – update to “slug or ID”.The surrounding paragraph (lines 533-540) clearly states that either identifier works, but the
items.descriptionfield still mentions “slug” only.
Keeping the docs consistent avoids confusing API consumers.
887-894: Same slug-only wording as earlier – please harmonise.
items.descriptionshould mention “slug or ID” to match the behaviour described a few lines above.
955-964:keyIdpattern still too permissive + outdated wording.
- Pattern
^[a-zA-Z0-9_]+$acceptsfooBar– it should enforce the mandatorykey_prefix (see prior comment).- The permission array description later in this block says “slug” only.
2108-2110: Doc string should mention “slugs or IDs”.The list now accepts both, but the description still says “permission slugs”.
1204-1208: Clarify that either slug or ID is accepted here too.The
itemsblock forpermissionsno longer restricts the character set to slugs, but the surrounding description omits IDs. Align wording for accuracy.
2352-2361:Permission.idpattern contradicts its own description.Description says “Always begins with
perm_”, yet pattern^[a-zA-Z0-9_]+$does not require it.- pattern: "^[a-zA-Z0-9_]+$" + pattern: "^perm_[a-zA-Z0-9_]+$"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (87)
go/apps/api/openapi/gen.go(19 hunks)go/apps/api/openapi/openapi-generated.yaml(22 hunks)go/apps/api/openapi/spec/common/role.yaml(0 hunks)go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml(1 hunks)go/apps/api/routes/v2_apis_list_keys/handler.go(1 hunks)go/apps/api/routes/v2_keys_add_permissions/400_test.go(6 hunks)go/apps/api/routes/v2_keys_add_permissions/401_test.go(2 hunks)go/apps/api/routes/v2_keys_add_permissions/403_test.go(3 hunks)go/apps/api/routes/v2_keys_add_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_add_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_add_roles/200_test.go(4 hunks)go/apps/api/routes/v2_keys_add_roles/400_test.go(3 hunks)go/apps/api/routes/v2_keys_add_roles/401_test.go(1 hunks)go/apps/api/routes/v2_keys_add_roles/403_test.go(4 hunks)go/apps/api/routes/v2_keys_add_roles/404_test.go(11 hunks)go/apps/api/routes/v2_keys_add_roles/handler.go(8 hunks)go/apps/api/routes/v2_keys_create_key/handler.go(6 hunks)go/apps/api/routes/v2_keys_remove_permissions/200_test.go(10 hunks)go/apps/api/routes/v2_keys_remove_permissions/400_test.go(2 hunks)go/apps/api/routes/v2_keys_remove_permissions/404_test.go(7 hunks)go/apps/api/routes/v2_keys_remove_roles/200_test.go(4 hunks)go/apps/api/routes/v2_keys_remove_roles/400_test.go(9 hunks)go/apps/api/routes/v2_keys_remove_roles/401_test.go(6 hunks)go/apps/api/routes/v2_keys_remove_roles/403_test.go(7 hunks)go/apps/api/routes/v2_keys_remove_roles/404_test.go(8 hunks)go/apps/api/routes/v2_keys_remove_roles/handler.go(8 hunks)go/apps/api/routes/v2_keys_set_permissions/200_test.go(14 hunks)go/apps/api/routes/v2_keys_set_permissions/401_test.go(2 hunks)go/apps/api/routes/v2_keys_set_permissions/403_test.go(2 hunks)go/apps/api/routes/v2_keys_set_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_set_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_set_roles/200_test.go(7 hunks)go/apps/api/routes/v2_keys_set_roles/400_test.go(0 hunks)go/apps/api/routes/v2_keys_set_roles/401_test.go(1 hunks)go/apps/api/routes/v2_keys_set_roles/403_test.go(2 hunks)go/apps/api/routes/v2_keys_set_roles/404_test.go(14 hunks)go/apps/api/routes/v2_keys_set_roles/handler.go(5 hunks)go/apps/api/routes/v2_keys_update_key/handler.go(8 hunks)go/apps/api/routes/v2_permissions_create_permission/handler.go(4 hunks)go/apps/api/routes/v2_permissions_create_role/handler.go(4 hunks)go/apps/api/routes/v2_permissions_delete_permission/200_test.go(5 hunks)go/apps/api/routes/v2_permissions_delete_permission/403_test.go(4 hunks)go/apps/api/routes/v2_permissions_delete_permission/404_test.go(5 hunks)go/apps/api/routes/v2_permissions_delete_role/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_delete_role/400_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_delete_role/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/404_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/handler.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_get_permission/403_test.go(4 hunks)go/apps/api/routes/v2_permissions_get_role/200_test.go(6 hunks)go/apps/api/routes/v2_permissions_get_role/400_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_get_role/404_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/handler.go(3 hunks)go/apps/api/routes/v2_permissions_list_permissions/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_list_permissions/403_test.go(3 hunks)go/apps/api/routes/v2_permissions_list_roles/200_test.go(2 hunks)go/apps/api/routes/v2_permissions_list_roles/handler.go(2 hunks)go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go(1 hunks)go/pkg/db/models_generated.go(2 hunks)go/pkg/db/permission_insert.sql_generated.go(2 hunks)go/pkg/db/plugins/bulk-insert/template_test.go(4 hunks)go/pkg/db/querier_generated.go(7 hunks)go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql(1 hunks)go/pkg/db/queries/role_find_by_id_or_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_find_many_by_id_or_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_find_many_by_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_list.sql(1 hunks)go/pkg/db/queries/role_list_by_key_id.sql(1 hunks)go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_list.sql_generated.go(2 hunks)go/pkg/db/role_list_by_key_id.sql_generated.go(1 hunks)go/pkg/db/sqlc.json(1 hunks)go/pkg/db/types/null_string.go(1 hunks)go/pkg/testutil/seed/seed.go(3 hunks)
💤 Files with no reviewable changes (2)
- go/apps/api/routes/v2_keys_set_roles/400_test.go
- go/apps/api/openapi/spec/common/role.yaml
🧰 Additional context used
🧠 Learnings (80)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: unkeyed/unkey#2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In `apps/api/src/routes/v1_keys_updateKey.ts`, the code intentionally handles `externalId` and `ownerId` separately for clarity. The `ownerId` field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: unkeyed/unkey#3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as `description`) alongside `$ref` in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (9)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_add_permissions/403_test.go (8)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_set_permissions/401_test.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_keys_add_roles/handler.go (6)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_add_roles/400_test.go (5)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_permissions_list_roles/200_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_apis_list_keys/handler.go (4)
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For identity deletion operations in the Unkey API, identityId takes precedence over externalId when both are provided in the request body.
go/apps/api/routes/v2_permissions_get_role/403_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/pkg/db/permission_insert.sql_generated.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_permissions_delete_role/403_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_permissions_get_role/401_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_get_role/404_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_keys_set_roles/401_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_roles/403_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_list_roles/handler.go (2)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_permissions_create_role/handler.go (4)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_add_roles/401_test.go (1)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_permissions_list_permissions/200_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_list_permissions/403_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_permissions_delete_role/401_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_delete_role/200_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/plugins/bulk-insert/template_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_delete_role/400_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_get_role/400_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/sqlc.json (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_permissions_delete_role/handler.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_get_permission/403_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_remove_roles/200_test.go (3)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_add_roles/403_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/pkg/db/queries/role_list.sql (1)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_update_key/handler.go (12)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2825
File: apps/dashboard/app/(app)/logs-v2/hooks/use-bookmarked-filters.ts:0-0
Timestamp: 2025-01-30T20:51:44.359Z
Learning: The user (ogzhanolguncu) prefers to handle refactoring suggestions in separate PRs to maintain focus in the current PR.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_remove_roles/400_test.go (7)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_keys_remove_roles/401_test.go (6)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/queries/role_list_by_key_id.sql (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_add_permissions/401_test.go (7)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (10)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_add_permissions/400_test.go (10)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_get_permission/200_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_get_role/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_create_permission/handler.go (4)
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_set_roles/handler.go (7)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (8)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/pkg/testutil/seed/seed.go (3)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_remove_roles/404_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_permissions_get_role/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_roles/404_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/types/null_string.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_permissions_delete_role/404_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (8)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml (3)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_create_key/handler.go (6)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_add_roles/404_test.go (4)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/models_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_add_roles/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (7)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (1)
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
go/apps/api/routes/v2_keys_set_roles/403_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_keys_set_roles/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/role_list_by_key_id.sql_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_keys_remove_roles/handler.go (8)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_add_permissions/handler.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: Flo4604
PR: #3606
File: go/pkg/prometheus/metrics/database.go:29-30
Timestamp: 2025-07-16T10:06:35.397Z
Learning: In Go packages, variables defined in one file within a package (like latencyBuckets and constLabels in go/pkg/prometheus/metrics/http.go) are accessible from other files in the same package without requiring imports. This is a common pattern for sharing configuration across multiple files within a package.
go/apps/api/routes/v2_keys_set_permissions/handler.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/gen.go (11)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3647
File: go/apps/api/openapi/openapi-generated.yaml:3569-3575
Timestamp: 2025-07-22T18:09:41.800Z
Learning: In the Unkey codebase, using non-standard HTTP status code 529 for internal-only endpoints is acceptable and should not be flagged as an issue in future reviews.
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{env,sh,yaml,yml,json,conf,ini} : All environment variables MUST follow the format UNKEY_<SERVICE_NAME>_VARNAME.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
go/pkg/db/querier_generated.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/openapi/openapi-generated.yaml (16)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
🧬 Code Graph Analysis (30)
go/apps/api/routes/v2_permissions_list_roles/200_test.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_get_role/403_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/pkg/db/permission_insert.sql_generated.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_role/403_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_get_role/404_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_list_permissions/200_test.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/cli/flag.go (1)
String(331-363)
go/apps/api/routes/v2_permissions_list_permissions/403_test.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_role/401_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_delete_role/200_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Role(425-449)go/pkg/db/models_generated.go (1)
Role(813-820)
go/apps/api/routes/v2_permissions_delete_role/400_test.go (2)
go/apps/api/routes/v2_permissions_delete_role/handler.go (1)
Request(19-19)go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_delete_role/handler.go (5)
go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (1)
FindRoleByIdOrNameWithPermsParams(36-39)go/apps/api/openapi/gen.go (1)
Role(425-449)go/pkg/db/models_generated.go (2)
Role(813-820)AuditLog(554-570)go/pkg/fault/wrap.go (3)
Wrap(25-67)Internal(75-89)Public(97-111)go/pkg/codes/unkey_application.go (1)
App(53-71)
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)
go/apps/api/routes/v2_keys_add_permissions/401_test.go (4)
go/pkg/testutil/seed/seed.go (3)
CreateApiRequest(79-87)CreateKeyRequest(183-200)New(36-42)go/pkg/uid/uid.go (1)
TestPrefix(24-24)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (2)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)
go/apps/api/routes/v2_keys_add_permissions/400_test.go (4)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/routes/v2_keys_add_permissions/handler.go (1)
Request(25-25)go/pkg/testutil/seed/seed.go (1)
New(36-42)go/pkg/uid/uid.go (2)
TestPrefix(24-24)KeyPrefix(16-16)
go/apps/api/routes/v2_permissions_get_permission/200_test.go (6)
go/pkg/uid/uid.go (1)
PermissionPrefix(27-27)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/testutil/http.go (1)
CallRoute(257-291)
go/apps/api/routes/v2_permissions_get_role/200_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Role(425-449)go/pkg/db/models_generated.go (1)
Role(813-820)
go/apps/api/routes/v2_permissions_create_permission/handler.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_keys_set_permissions/404_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/testutil/seed/seed.go (1)
New(36-42)go/pkg/uid/uid.go (1)
KeyPrefix(16-16)
go/apps/api/routes/v2_keys_remove_roles/404_test.go (3)
go/pkg/db/role_insert.sql_generated.go (1)
InsertRoleParams(30-36)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/routes/v2_keys_remove_roles/handler.go (1)
Request(23-23)
go/apps/api/routes/v2_permissions_delete_role/404_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_keys_create_key/handler.go (4)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/pkg/db/role_list.sql_generated.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_keys_add_roles/200_test.go (2)
go/pkg/testutil/seed/seed.go (1)
CreateRoleRequest(360-366)go/pkg/ptr/pointer.go (1)
P(49-51)
go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_keys_set_roles/200_test.go (3)
go/pkg/rbac/query.go (1)
T(84-90)internal/db/src/types.ts (1)
InsertRole(26-26)go/pkg/db/role_insert.sql_generated.go (1)
InsertRoleParams(30-36)
go/pkg/db/role_list_by_key_id.sql_generated.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/openapi/gen.go (2)
go/pkg/codes/unkey_data.go (1)
Data(87-128)go/pkg/db/models_generated.go (2)
Permission(746-754)Role(813-820)
go/pkg/db/querier_generated.go (11)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (1)
DeleteManyKeyPermissionByKeyAndPermissionIDsParams(18-21)go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (1)
DeleteManyKeyRolesByKeyAndRoleIDsParams(18-21)go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (2)
FindManyRolesByIdOrNameWithPermsParams(37-40)FindManyRolesByIdOrNameWithPermsRow(42-50)go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go (2)
FindManyRolesByNamesWithPermsParams(34-37)FindManyRolesByNamesWithPermsRow(39-47)go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (1)
FindPermissionByIdOrSlugParams(18-21)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/permission_find_by_slugs.sql_generated.go (1)
FindPermissionsBySlugsParams(17-20)go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (2)
FindRoleByIdOrNameWithPermsParams(36-39)FindRoleByIdOrNameWithPermsRow(41-49)go/pkg/db/role_list.sql_generated.go (2)
ListRolesParams(36-39)ListRolesRow(41-49)go/pkg/db/role_list_by_key_id.sql_generated.go (1)
ListRolesByKeyIDRow(35-43)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Test Go API Local / Test
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Test API / API Test Local
🔇 Additional comments (198)
go/pkg/db/plugins/bulk-insert/template_test.go (4)
28-28: LGTM! Good addition of ValuesFields for template rendering.The new
ValuesFieldsfield properly separates the fields used in the SQL VALUES clause from other template fields, enabling more flexible bulk insert operations with upsert capabilities.
51-51: LGTM! Consistent ValuesFields usage in upsert test case.The
ValuesFieldsaddition aligns with the upsert functionality where fields for VALUES clause and ON DUPLICATE KEY UPDATE clause may need to be handled separately.
71-71: LGTM! ValuesFields properly added to no-db-argument test case.Consistent with other test cases, ensuring the template handles both database connection patterns correctly.
113-113: LGTM! ValuesFields included in error handling test.Ensures the invalid template test covers the complete
TemplateDatastructure including the newValuesFieldsfield.go/apps/api/routes/v2_permissions_get_role/403_test.go (2)
56-56: LGTM! Field name change aligns with unified API model.The change from
RoleIdtoRolereflects the API model update that allows endpoints to accept either role IDs or names, providing more flexibility in role management.
83-83: LGTM! Consistent field naming with API model changes.The
Rolefield name matches the updated API specification and maintains the same functionality while supporting the unified role identifier approach.go/apps/api/routes/v2_permissions_delete_role/403_test.go (2)
62-62: LGTM! Consistent field naming with API model updates.The change from
RoleIdtoRolealigns with the unified API approach that accepts either role IDs or names, maintaining consistency across permission and role management endpoints.
86-86: LGTM! Field name change supports flexible role identification.The
Rolefield name matches the updated API specification and supports the enhanced flexibility in role management operations.go/apps/api/routes/v2_permissions_list_roles/200_test.go (2)
14-14: LGTM! Import added for custom nullable string type.The addition of the
dbtypepackage import supports the migration to custom nullable string handling for better JSON and database operations.
61-61: LGTM! Migration to custom nullable string type for permissions.The change from
sql.NullStringtodbtype.NullStringfor permission descriptions aligns with the codebase migration to unified nullable string handling. This provides better JSON serialization and database handling for permission metadata.go/apps/api/routes/v2_apis_list_keys/handler.go (1)
189-189: LGTM! Minor formatting improvement enhances readability.The added blank line properly separates the error handling block from the subsequent logic, improving code organization and readability.
go/apps/api/routes/v2_permissions_delete_role/404_test.go (1)
48-48: LGTM: Field rename aligns with API flexibility enhancement.The change from
RoleIdtoRolecorrectly reflects the API's enhanced capability to accept either role IDs or slugs, as mentioned in the PR objectives.Also applies to: 83-83
go/apps/api/routes/v2_permissions_get_role/401_test.go (1)
26-26: LGTM: Consistent field rename for API unification.The field rename from
RoleIdtoRoleis consistent with the broader API refactoring to support both IDs and slugs.go/apps/api/routes/v2_permissions_list_permissions/403_test.go (2)
14-14: LGTM: Standardizing nullable string type usage.The addition of the
dbtypeimport alias supports the project's move to custom nullable string types instead of the standard library'ssql.NullString.
40-40: LGTM: Consistent nullable string type update.The change from
sql.NullStringtodbtype.NullStringaligns with the project-wide type standardization effort, maintaining the same functionality while using the custom type system.Also applies to: 81-81
go/apps/api/routes/v2_permissions_delete_role/400_test.go (1)
38-42: LGTM: Comprehensive and consistent terminology updates.Excellent work updating not just the field names but also the comments and test case names to consistently use "role" instead of "roleId". This level of consistency should be the standard across all related files.
Also applies to: 57-61
go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql (1)
1-3: LGTM! Well-structured batch deletion query.The SQL query correctly implements batch deletion of key-role associations using sqlc conventions. The use of
sqlc.slice('role_ids')with theINoperator will efficiently handle multiple role deletions in a single database operation, which aligns with the PR's objective to improve batch operations.go/apps/api/routes/v2_permissions_delete_role/401_test.go (1)
27-27: LGTM! Field name updated to match API changes.The field name change from
RoleIdtoRolealigns with the PR's objective to allow either role ID or slug in permission-related requests. The test value follows the expected role ID format.go/apps/api/routes/v2_keys_set_roles/401_test.go (1)
29-29: LGTM! Simplified roles field structure.The change from complex role objects to a simple string slice (
[]string{"role_123"}) aligns with the API simplification goals. This supports the PR's objective to accept either role ID or slug as string values, making the API more flexible and easier to use.go/apps/api/routes/v2_keys_remove_roles/403_test.go (1)
69-69: LGTM! Consistent roles field simplification across all test cases.The simplification of the
Rolesfield from complex objects to string slices is applied consistently across all authorization test cases. This change supports the PR's goal of accepting either role ID or slug as simple string values, improving API usability while maintaining comprehensive test coverage.Also applies to: 122-122, 175-175, 228-228, 281-281, 334-334, 388-388
go/apps/api/routes/v2_keys_add_roles/401_test.go (1)
51-51: LGTM! Roles field simplified for better API usability.The change from complex role objects to a simple string slice (
[]string{"role_123"}) is consistent with the API refactoring across the codebase. This simplification supports the PR's objective to accept either role ID or slug as string values, making the API more intuitive while maintaining full test coverage for authentication scenarios.go/apps/api/routes/v2_permissions_get_permission/403_test.go (3)
14-14: LGTM!The import of the custom
dbtypepackage aligns with the codebase migration from standard librarysql.NullStringto the project-specific nullable string type.
43-43: LGTM!The migration from
sql.NullStringtodbtype.NullStringfor the permission description field is consistent with the broader codebase standardization effort.
59-59: LGTM!The field name change from
PermissionIdtoPermissionsimplifies the request structure and aligns with the PR objective to allow either permission ID or slug in permission-related requests.Also applies to: 86-86
go/pkg/db/models_generated.go (2)
13-13: LGTM!The import addition enables the use of the custom
dbtype.NullStringtype in the generated database models, supporting the migration from standard library types.
751-751: LGTM!The migration of the
Descriptionfield fromsql.NullStringtodbtype.NullStringin the generated Permission struct aligns with the codebase-wide standardization of nullable string handling.go/pkg/db/permission_insert.sql_generated.go (2)
11-11: LGTM!The import addition enables the use of the custom
dbtype.NullStringtype in the generated permission insertion parameters.
38-38: LGTM!The migration of the
Descriptionfield todbtype.NullStringin theInsertPermissionParamsstruct maintains consistency with the Permission model and supports unified nullable string handling across database operations.go/apps/api/routes/v2_permissions_delete_role/200_test.go (3)
14-14: LGTM!The import of the custom
dbtypepackage enables the test to use the project-specific nullable string type for permission descriptions.
68-68: LGTM!The migration to
dbtype.NullStringfor the permission description in test data creation maintains consistency with the updated database models.
112-112: LGTM!The field name change from
RoleIdtoRolesimplifies the request structure and supports the API's flexibility to accept either role ID or name.Also applies to: 171-171
go/apps/api/routes/v2_permissions_get_role/404_test.go (1)
40-40: LGTM!The field name change from
RoleIdtoRolealigns with the API simplification effort to use unified identifier fields that can accept either role ID or name.go/apps/api/routes/v2_permissions_create_role/handler.go (4)
6-6: LGTM!The addition of the
fmtimport is necessary for thefmt.Sprintfusage in the error message formatting below.
92-92: Improved error message formatting with quoted role names.The use of
fmt.Sprintfwith quoted role names (%q) provides better readability and clarity in error messages, making it easier to identify the specific role name that caused the duplicate error.
110-110: Excellent use of audit log constants.Replacing the hardcoded string with
auditlog.RoleCreateEventimproves maintainability and consistency across the codebase. This aligns with the broader refactoring to standardize audit log event types.
120-120: Consistent use of audit log resource type constants.Using
auditlog.RoleResourceTypeinstead of hardcoded strings ensures consistency with other audit log implementations and makes the code more maintainable.go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml (1)
16-16: Excellent schema consolidation.Replacing the inline role object definition with a reference to the common role schema (
../../../../common/role.yaml) eliminates duplication and creates a single source of truth for role definitions. This improves maintainability and consistency across the API specification.go/apps/api/routes/v2_permissions_list_permissions/200_test.go (2)
13-13: Good refactoring to use custom nullable string type.The import change to use
dbtypealias for the custom nullable string type is part of a broader codebase standardization that centralizes nullable string handling and enables custom JSON marshaling behavior.
63-63: Consistent migration to dbtype.NullString.The replacement of
sql.NullStringwithdbtype.NullStringfor permission descriptions is consistent throughout the test and aligns with the broader refactoring to standardize nullable string types across the codebase. This enables better JSON handling and maintains type safety.Also applies to: 76-76, 150-150
go/apps/api/routes/v2_keys_set_roles/403_test.go (1)
69-69: Excellent API simplification.The change from a slice of structs with optional
IdandNamepointers to a simple slice of role ID strings significantly simplifies the request payload structure. This makes the API more intuitive and easier to use while maintaining the same functionality.This aligns with the broader refactoring to standardize role and permission representations across the codebase.
Also applies to: 97-97
go/pkg/db/sqlc.json (1)
44-52: Proper sqlc configuration for custom nullable string type.The override configuration correctly maps the
permissions.descriptiondatabase column to the customdbtype.NullStringtype with the appropriate package import. This ensures that generated database code uses the consistent nullable string type across the codebase, enabling custom JSON marshaling behavior while maintaining proper nullable handling.go/apps/api/routes/v2_keys_set_permissions/401_test.go (3)
15-15: LGTM: Adopting custom nullable string type.The migration from
database/sqltodbtypealigns with the project-wide standardization of nullable string handling.
75-75: LGTM: Consistent nullable string type usage.The change from
sql.NullStringtodbtype.NullStringmaintains consistency with the database model updates and improves type safety.
80-81: LGTM: Simplified API model for permissions.The change from complex permission objects to a simple string slice (
[]string{permissionID}) aligns with the API simplification goals mentioned in the PR objectives. This makes the API more intuitive for users who can now specify permissions by either ID or slug directly.go/apps/api/routes/v2_keys_add_roles/403_test.go (4)
60-60: LGTM: Simplified role specification in API.The change from complex role objects to a simple string slice (
[]string{"role_123"}) aligns with the API model simplification. Users can now specify roles by either ID or name directly, making the API more intuitive.
124-124: LGTM: Consistent role specification pattern.The simplified string slice format for roles maintains consistency across all test cases and aligns with the unified API model.
170-170: LGTM: Maintains test coverage with simplified API.The role specification change preserves the authorization test logic while using the cleaner API model.
216-216: LGTM: Final role specification follows pattern.Consistent with other test cases, the simplified role format improves API usability.
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (4)
14-14: LGTM: Consistent nullable string type adoption.The import of
dbtypepackage aligns with the project-wide migration fromsql.NullStringtodbtype.NullString.
44-44: LGTM: Database model consistency.The change to
dbtype.NullStringmaintains consistency with the updated database models and improves nullable string handling.
60-60: LGTM: Unified permission field naming.The change from
PermissionIdtoPermissionaligns with the API model unification where the field now accepts either permission ID or slug, as mentioned in the PR objectives.
95-95: LGTM: Consistent permission field usage.The
Permissionfield usage is consistent across test cases and supports the unified API model.go/pkg/db/queries/role_list.sql (1)
2-21: LGTM: Enhanced role query with permission aggregation.The SQL query enhancement effectively aggregates permissions for each role using JSON functions:
JSON_ARRAYAGGcreates a properly structured array of permission objectsCOALESCEensures an empty array when no permissions exist, preventing null values- Pagination support with
id_cursorand limit of 101 (standard pattern for has_more logic)- The JOIN and subquery structure is efficient and maintains data integrity
This optimization reduces the need for N+1 queries when fetching roles with their associated permissions.
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (5)
13-13: LGTM: Consistent type import.The
dbtypeimport maintains consistency with the project-wide migration to custom nullable string types.
55-55: LGTM: Database type consistency.The migration to
dbtype.NullStringaligns with the updated database models and maintains consistency across the codebase.
67-67: LGTM: Unified permission field naming.The change from
PermissionIdtoPermissionsupports the API's ability to accept either permission ID or slug, as outlined in the PR objectives.
113-113: LGTM: Consistent nullable string usage.The
dbtype.NullStringusage maintains consistency with the database model updates.
126-126: LGTM: Consistent permission field usage.The
Permissionfield usage aligns with the unified API model across all test scenarios.go/pkg/testutil/seed/seed.go (3)
14-14: LGTM!The import addition for the custom nullable string type aligns with the codebase standardization effort.
152-152: LGTM!The replacement of
sql.NullStringwithdbtype.NullStringfor the permission description field is consistent with the broader codebase refactoring to standardize nullable string handling.
415-415: LGTM!Consistent usage of
dbtype.NullStringfor the permission description field, matching the pattern established throughout the codebase.go/pkg/db/queries/role_find_many_by_name_with_perms.sql (1)
1-18: Efficient batch query design.This SQL query correctly implements batch role retrieval with permissions aggregation. The design is well-structured:
- Proper workspace scoping ensures data isolation
- JSON aggregation provides a consistent response format with COALESCE handling empty cases
- The batch approach is more efficient than individual role lookups
- All relevant permission fields are included in the JSON object
The use of
sqlc.slice('names')for dynamic IN clause generation is appropriate for the sqlc workflow.go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml (1)
17-17: LGTM!The reference to the common role schema (
../../../../common/role.yaml) is a good approach for API schema unification, reducing duplication and improving maintainability. The comprehensive description clearly explains the response behavior and expectations.go/pkg/db/queries/role_find_by_id_or_name_with_perms.sql (1)
1-21: Flexible role lookup implementation.This query provides efficient role retrieval by either ID or name with permissions aggregation. The implementation is well-designed:
- Consistent JSON aggregation pattern with the batch query
- Flexible OR condition allows lookup by either ID or name using a single parameter
- Proper workspace scoping maintains data isolation
- COALESCE ensures consistent response format
The single
searchparameter approach is clean and efficient for the use case.go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
14-14: LGTM!The import change to use the custom nullable string type aligns with the codebase standardization effort for consistent type handling.
47-47: Consistent API model updates.The field name change from
PermissionIdtoPermissionacross all test cases correctly reflects the updated API model that now accepts either permission IDs or slugs as strings. This simplifies the request structure and aligns with the broader API unification effort.Also applies to: 68-68, 104-104
93-93: LGTM!The type change from
sql.NullStringtodbtype.NullStringfor the permission description field is consistent with the database model updates and codebase standardization.go/pkg/db/queries/role_find_many_by_id_or_name_with_perms.sql (1)
1-21: Well-structured query that supports flexible role lookup.The SQL query effectively implements the PR objective of allowing either permission ID or slug (in this case, role ID or name) by:
- Using
sqlc.slice('search')to match against bothr.idandr.namefields- Properly aggregating permissions as JSON using
JSON_ARRAYAGGandjson_object- Handling empty permission sets with
COALESCEandJSON_ARRAY()- Maintaining workspace isolation for security
The JSON aggregation approach eliminates the need for separate permission queries in handlers, improving performance.
go/apps/api/routes/v2_permissions_list_roles/handler.go (3)
5-5: LGTM: Added encoding/json import for permission unmarshaling.The import is correctly added to support the new JSON unmarshaling approach for role permissions.
91-96: Improved role response initialization with explicit defaults.The early initialization with explicit
nilvalues forDescriptionandPermissionsmakes the code more readable and prevents potential nil pointer issues.
116-116: LGTM: Simplified permission assignment using unified response structure.The direct assignment to
roleResponse.Permissionsis cleaner than the previous approach and aligns with the unified role schema changes.go/apps/api/routes/v2_permissions_delete_role/handler.go (3)
66-69: Excellent: Supports flexible role identification as per PR objectives.The updated query
FindRoleByIdOrNameWithPermsenables the handler to accept either role ID or name (slug), directly implementing the PR's core objective. The workspace scoping is now handled at the query level, which is more secure than explicit checks.
84-84: LGTM: Consistent use of resolved role ID.Using
role.ID(the resolved role ID) instead ofreq.Rolefor all deletion operations ensures consistency regardless of whether the request used a role ID or name. This prevents potential issues where the request contained a name but deletions expected an ID.Also applies to: 92-92, 100-100
111-111: Improved maintainability with audit log constants.Replacing string literals with constants from the
auditlogpackage (auditlog.RoleDeleteEvent,auditlog.RoleResourceType) improves maintainability and prevents typos in audit log entries.Also applies to: 116-116, 121-122
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml (1)
17-17: Excellent: Centralized schema reference improves maintainability.Replacing the inline role definition with a reference to
"../../../../common/role.yaml"is a best practice that:
- Eliminates schema duplication across endpoints
- Ensures consistent role representation throughout the API
- Simplifies future schema updates by maintaining a single source of truth
- Aligns with the PR's objective of standardizing role and permission handling
go/apps/api/routes/v2_keys_create_key/handler.go (5)
20-20: LGTM: Added dbtype import for unified null string handling.The import of
dbtypepackage supports the transition fromsql.NullStringtodbtype.NullString, which is part of the codebase-wide null string type unification mentioned in the PR.
367-370: Improved: Using full Permission struct for consistency.The change from
db.FindPermissionsBySlugsRowtodb.Permissionprovides consistency across the codebase and ensures all permission fields are available for processing.
373-373: Comprehensive permission struct initialization prevents field omission issues.The updated code properly initializes all fields of the
db.Permissionstruct when creating new permissions, including:
- All required fields (
ID,Name,Slug,WorkspaceID,CreatedAtM)- Proper null handling with
dbtype.NullStringforDescription- Default values for
UpdatedAtMThis prevents potential issues from missing fields and aligns with the codebase-wide type improvements.
Also applies to: 392-400
388-388: Consistent null string type usage.Using
dbtype.NullStringinstead ofsql.NullStringfor theDescriptionfield aligns with the PR's objective of unifying null string handling across the codebase.
435-435: Improved maintainability with audit log resource type constants.Replacing string literals with constants from the
auditlogpackage (auditlog.KeyResourceType,auditlog.PermissionResourceType,auditlog.RoleResourceType,auditlog.APIResourceType) improves code maintainability and prevents typos in audit log entries.Also applies to: 442-442, 522-522, 529-529, 564-564, 571-571
go/pkg/db/queries/role_list_by_key_id.sql (1)
2-16: Review JSON aggregation pattern and performance optimizationWe’ve verified that the correlated JSON_ARRAYAGG subquery isn’t unique to
role_list_by_key_id.sql—it appears in six other queries undergo/pkg/db/queries/(e.g.,role_list.sql,role_find_by_id_or_name_with_perms.sql, etc.). While functionally correct, executing a subquery per role can incur an N+1–style cost on large datasets.Before keeping this pattern, please:
- Profile this query (e.g., EXPLAIN ANALYZE) against expected data volumes.
- Ensure there are indexes on
roles_permissions.role_idandpermissions.id.- Consider a single JOIN + GROUP BY approach, for example:
SELECT r.*, COALESCE( JSON_ARRAYAGG( JSON_OBJECT( 'id', p.id, 'name', p.name, 'slug', p.slug, 'description', p.description ) ) FILTER (WHERE p.id IS NOT NULL), JSON_ARRAY() ) AS permissions FROM roles r LEFT JOIN roles_permissions rp ON rp.role_id = r.id LEFT JOIN permissions p ON p.id = rp.permission_id WHERE r.key_id = :key_id GROUP BY r.id;This rewrite aggregates all permissions in one pass rather than per role. If benchmarks show no significant difference, the existing pattern is acceptable; otherwise, migrate to the JOIN+GROUP BY style for better scalability.
go/apps/api/routes/v2_permissions_get_role/200_test.go (3)
14-14: LGTM: Custom nullable string type migration.The migration from
sql.NullStringtodbtype.NullStringis consistent with the broader codebase standardization on custom nullable types.
84-84: LGTM: Request field updated to support ID or name.The change from
RoleIdtoRolealigns with the PR objective to allow either permission ID or slug in permission-related requests. The tests now properly validate both ID-based (line 84) and name-based (line 140) role lookup.Also applies to: 140-140
163-164: LGTM: Updated permissions assertion for new JSON array structure.The assertion changes from checking non-nil to verifying empty slice correctly reflect the new permissions representation as a JSON array unmarshaled from the database query.
go/apps/api/routes/v2_keys_add_permissions/401_test.go (4)
13-15: LGTM: Updated imports for test refactoring.The import changes correctly reflect the migration to helper-based test setup (
testutil/seed) and custom nullable types (dbtype), while removing dependencies on manual database operations.
36-53: LGTM: Simplified test setup with helper functions.The refactoring from manual database insertions to
CreateApiandCreateKeyhelper functions reduces boilerplate code and improves test maintainability while maintaining the same test coverage.
61-67: LGTM: Consistent migration to custom nullable string type.The change from
sql.NullStringtodbtype.NullStringaligns with the broader codebase standardization on custom nullable types.
65-67: LGTM: Simplified request structure.The change from a slice of permission structs to a slice of permission ID strings reflects the API model simplification and makes the request construction more straightforward.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (4)
13-15: LGTM: Updated imports for test refactoring.The import changes correctly support the migration to helper-based test setup and custom nullable types, consistent with other test files in this refactor.
36-61: LGTM: Simplified test setup with helper functions.The refactoring to use
CreateApiandCreateKeyhelper functions improves test maintainability and consistency across the test suite.
63-63: LGTM: Corrected permission ID prefix.Good fix changing from
uid.TestPrefixtouid.PermissionPrefix- this ensures the permission ID follows the correct naming convention for actual permissions rather than test entities.
69-75: LGTM: Consistent type migration and request simplification.The changes to use
dbtype.NullStringand simplify the request structure to use a slice of strings align with the broader API model refactoring and improve consistency.go/apps/api/routes/v2_keys_remove_roles/401_test.go (1)
66-66: LGTM: Simplified role representation improves API usability.The change from complex role objects with optional
IdandNamefields to simple string arrays is a good simplification. This makes the API more intuitive and easier to use while maintaining the same functionality.Also applies to: 116-116, 167-167, 218-218, 269-269, 324-324
go/apps/api/routes/v2_keys_set_roles/404_test.go (2)
81-81: LGTM: Consistent role simplification across test cases.The uniform change from role structs to string arrays maintains consistency across all test scenarios and simplifies the API interface.
Also applies to: 105-105, 129-129, 237-237, 259-259, 284-284, 309-309, 334-334
119-119: Good: Standardized error message format.The consistent use of
fmt.Sprintf("Role %q was not found", ...)provides uniform error messaging across different test scenarios, improving the user experience.Also applies to: 143-143, 251-251, 273-273, 298-298, 348-348
go/apps/api/routes/v2_permissions_create_permission/handler.go (3)
14-14: LGTM: Standardized internal type usage.The switch from
sql.NullStringtodbtype.NullStringaligns with the codebase-wide standardization of using internal nullable types for better consistency and type safety.Also applies to: 78-78
99-99: Good: Constants improve maintainability.Replacing string literals with predefined constants (
auditlog.PermissionCreateEventandauditlog.PermissionResourceType) reduces the risk of typos and improves maintainability across the audit logging system.Also applies to: 109-109
111-111: Audit log resource name is correct for permissions
The change inv2_permissions_create_permission/handler.goto set the audit log resource’sNamefield toreq.Slug(withDisplayName: req.Name) is intentional and appropriate: slugs serve as stable identifiers, while display names remain human-readable. Other permission handlers don’t emit audit logs for names, and roles have no slug field, so they continue to usereq.Name. No further changes are needed here.go/apps/api/routes/v2_keys_add_permissions/400_test.go (3)
15-15: LGTM: Consistent internal type usage.The standardization to
dbtype.NullStringmaintains consistency with the broader codebase changes for nullable string handling.Also applies to: 183-183, 253-253
37-37: Good: Updated permission scope for root key.Adding
"rbac.*.add_permission_to_key"permission ensures the root key has the necessary authorization for the updated permission management functionality.
188-189: LGTM: Simplified permission request structure.The change from complex permission objects to simple string arrays aligns with the API simplification goals and makes the interface more intuitive.
Also applies to: 209-210, 227-228, 259-260
go/apps/api/routes/v2_keys_add_roles/404_test.go (3)
36-36: Good: Updated RBAC permission scope.Adding
"rbac.*.add_role_to_key"ensures the root key has proper authorization for the enhanced role management functionality.
48-48: LGTM: Consistent role simplification.The uniform change from role objects to string arrays maintains consistency across all test scenarios and simplifies the API interface.
Also applies to: 88-88, 126-126, 164-164, 212-212, 261-261, 311-311, 365-365, 415-415
298-302: Improved test clarity with specific error checking.The variable name changes (
validName,invalidName) and the updated error assertion that checks for the specific invalid role name improve test clarity and make failures easier to debug.Also applies to: 324-324
go/apps/api/routes/v2_permissions_get_permission/200_test.go (4)
13-13: LGTM! Consistent type migration.The migration from
sql.NullStringtodbtype.NullStringis consistent with the codebase-wide effort to use a custom nullable string type.
42-84: Well-structured permission retrieval tests.The test properly validates permission retrieval by ID with all fields populated, including the nullable description field using the new
dbtype.NullStringtype.
86-106: Good addition of slug-based retrieval test.Adding a separate test case for retrieving permissions by slug ensures both identifier types are properly tested, which aligns with the API's flexibility to accept either ID or slug.
119-119: Consistent nullable type usage.Both the permission insertion and request use the updated field names and types consistently -
dbtype.NullStringfor the description andPermission(instead ofPermissionId) for the request field.Also applies to: 126-126
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (4)
15-15: LGTM! Consistent type migration.The migration to
dbtype.NullStringis consistent with the codebase-wide nullable string type standardization.
38-38: Appropriate permission scope addition.Adding
"rbac.*.remove_permission_from_key"to the root key ensures proper authorization for the remove permissions operation.
60-62: Clean API simplification.The request structure has been simplified from complex objects with
IdandSlugpointers to a straightforward string slice, making the API more intuitive and easier to use.Also applies to: 98-99, 169-170, 240-241
132-132: Consistent nullable type usage.All permission insertions now use
dbtype.NullStringfor the description field, maintaining consistency across the test suite.Also applies to: 235-235
go/apps/api/routes/v2_keys_update_key/handler.go (5)
18-18: LGTM! Consistent type migration.The import of
dbtypepackage aligns with the codebase-wide migration to use custom nullable types.
110-111: Excellent audit logging implementation.The audit logging has been enhanced with:
- Initialization inside the transaction for consistency
- Detailed entries for each auto-created permission
- Use of predefined constants for resource types (
auditlog.KeyResourceType,auditlog.APIResourceType,auditlog.PermissionResourceType)- Comprehensive resource metadata
This provides excellent traceability for permission creation and key updates.
Also applies to: 416-441, 549-575
384-413: Clean permission handling logic.The permission resolution logic efficiently:
- Uses a map to track existing permissions
- Identifies which permissions need to be created
- Maintains the requested permission list for later assignment
The implementation is clear and performant.
461-469: Proper timestamp handling for bulk operations.Using a single timestamp for both
CreatedAtandUpdatedAtfields ensures consistency in bulk insert operations and aligns with the updated SQL queries that includeON DUPLICATE KEY UPDATElogic.
593-593: Standardized response format.Using
openapi.EmptyResponse{}instead of a pointer to an empty struct follows the standardized empty response pattern across the API.go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml (1)
28-32: Clean API schema simplification.The role specification has been simplified from a complex object structure to a simple string representing the role name. The pattern
^[a-zA-Z][a-zA-Z0-9_-]*$ensures valid role names that start with a letter, and the length constraints (3-255) provide reasonable bounds. This makes the API more intuitive and aligns with the broader simplification effort across role and permission endpoints.go/apps/api/routes/v2_keys_remove_roles/400_test.go (2)
35-35: Appropriate permission scope for role operations.Adding
"rbac.*.remove_role_from_key"permission ensures proper authorization for role removal operations.
86-86: Consistent API request simplification.All test cases have been updated to use the simplified
Roles: []string{...}format instead of complex objects withIdandNamefields. This aligns perfectly with the API schema changes and makes the tests cleaner and more maintainable.Also applies to: 114-114, 185-185, 222-222, 259-259, 289-289, 335-335, 383-383
go/apps/api/routes/v2_keys_remove_roles/200_test.go (4)
35-35: LGTM! Appropriate permission added for role removal operations.The addition of
"rbac.*.remove_role_from_key"permission is correct and aligns with the enhanced RBAC controls introduced in this PR.
43-43: Test case name accurately reflects the operation.The rename from a generic test name to "remove single role" provides better clarity about what this specific test case validates.
88-88: Clean API simplification with string-based role references.The change from complex objects with optional ID/Name fields to a simple string slice improves API usability and aligns with the overall simplification effort across the codebase.
Also applies to: 145-145
129-134: Consistent test data naming.Using descriptive role names like "unassigned_role" improves test readability and makes the test's purpose clearer.
go/apps/api/routes/v2_permissions_get_role/handler.go (1)
64-80: Efficient single-query approach for role retrieval.The refactoring to use
FindRoleByIdOrNameWithPermseliminates the N+1 query problem by fetching the role and its permissions in a single database call. This is a good performance optimization.go/apps/api/routes/v2_keys_set_roles/handler.go (3)
88-102: Enhanced permission verification with API-specific checks.Good improvement to check permissions at both the wildcard level and the specific API level. This provides more granular access control.
117-136: Efficient batch role resolution and validation.The refactoring to use
FindManyRolesByNamesWithPermswith a combined validation map eliminates multiple database queries and simplifies the validation logic.
198-201: Optimized batch database operations.Excellent use of batch operations (
DeleteManyKeyRolesByKeyAndRoleIDsandBulkQuery.InsertKeyRoles) to reduce database round trips and improve performance.Also applies to: 251-251
go/apps/api/routes/v2_keys_remove_roles/404_test.go (2)
35-35: Consistent permission addition across test files.The addition of
"rbac.*.remove_role_from_key"permission matches the changes in the success test file, maintaining consistency.
59-59: Simplified test requests align with API changes.All test cases have been properly updated to use the new string slice format for roles, maintaining comprehensive 404 error coverage while simplifying the test code.
Also applies to: 98-98, 138-138, 188-188, 238-238, 288-288, 338-338
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (2)
13-13: Consistent migration to custom NullString type.The change from
sql.NullStringtodbtype.NullStringaligns with the codebase-wide type migration for better type safety and consistency.Also applies to: 167-167
174-175: Simplified permission references in test requests.The change to use a string slice for permissions matches the API simplification, making the test requests cleaner and more intuitive.
go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml (2)
3-3: Property rename aligns with API unification.The rename from
roleIdtoroleeffectively supports the PR objective of accepting either role ID or role name in a single field.
9-12: Pattern doesn't match role ID format described in documentation.The regex pattern
^[a-zA-Z][a-zA-Z0-9_-]*$requires the first character to be a letter, but the description states that role IDs begin with "role_" (which starts with a letter). However, this pattern would reject role IDs like "role_1234567890abcdef" because the underscore appears immediately after the first letter.Consider updating the pattern to accommodate both formats:
- pattern: "^[a-zA-Z][a-zA-Z0-9_-]*$" + pattern: "^[a-zA-Z][a-zA-Z0-9_-]*$|^role_[a-zA-Z0-9]+$"Or simplify to allow role IDs by relaxing the first character requirement:
- pattern: "^[a-zA-Z][a-zA-Z0-9_-]*$" + pattern: "^[a-zA-Z0-9][a-zA-Z0-9_-]*$"⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581 Timestamp: 2025-07-15T14:47:20.490Z Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.Learnt from: chronark PR: unkeyed/unkey#3617 File: go/apps/api/openapi/openapi.yaml:3309-3312 Timestamp: 2025-07-16T17:51:57.297Z Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.Learnt from: ogzhanolguncu PR: unkeyed/unkey#3324 File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18 Timestamp: 2025-06-19T11:48:05.070Z Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.go/apps/api/routes/v2_keys_add_roles/400_test.go (2)
30-30: Correct RBAC permission added for role management.The addition of
"rbac.*.add_role_to_key"permission scope is appropriate for the enhanced role management functionality introduced in this PR.
119-122: Simplified role representation aligns with API changes.The change from complex role objects to a simple string slice (
[]string{}) is consistent with the API simplification described in the PR summary.go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml (1)
28-32: Role specification simplified to string type.The simplification from complex role objects to string identifiers aligns well with the PR's goal to unify role references across the API.
go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (2)
31-38: Proper handling of variable-length role ID slices.The dynamic query construction correctly handles both populated and empty role ID slices. The NULL replacement for empty slices ensures the SQL query remains syntactically valid while avoiding unintended deletions.
27-41: Well-structured batch deletion method.The generated method properly implements batch deletion with appropriate parameter binding and error handling. This supports the performance optimization goals mentioned in the PR summary.
go/pkg/db/types/null_string.go (2)
9-10: Clean custom type definition.Using a type alias based on
sql.NullStringprovides a solid foundation while allowing custom JSON behavior.
35-43: Proper SQL interface delegation.The
ScanandValuemethods correctly delegate to the underlyingsql.NullStringimplementation, ensuring database compatibility.go/apps/api/routes/v2_keys_remove_permissions/200_test.go (5)
13-13: LGTM!The addition of the
dbtypeimport supports the project's type unification effort, replacing standardsql.NullStringwith a custom type for consistency.
35-35: Enhanced RBAC permission scope is appropriate.The addition of
"rbac.*.remove_permission_from_key"permission to the root key aligns with the enhanced RBAC permission checking introduced in this PR.
74-74: Excellent API simplification!The change from complex permission structs with optional
IdandSlugpointers to a simple[]stringsignificantly improves API usability while maintaining the same functionality. Users can now directly specify permissions as strings without worrying about struct construction.Also applies to: 152-152, 203-203, 293-293, 393-397
259-259: Consistent type usage.The migration from
sql.NullStringtodbtype.NullStringaligns with the project-wide type unification effort and provides better type consistency across the codebase.Also applies to: 270-270
43-417: Comprehensive test coverage.The test suite effectively covers all key scenarios: single/multiple permission removal, idempotent operations, partial removal, and complete removal. The tests properly verify both API responses and database state changes.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (4)
35-35: Comprehensive RBAC permissions for set operation.The expanded permission scopes
"rbac.*.remove_permission_from_key","rbac.*.add_permission_to_key", and"rbac.*.create_permission"are appropriate for the set_permissions endpoint, which may need to perform all these operations when setting the complete permission set.
113-113: Consistent API design across endpoints.The simplified
Permissions: []stringformat maintains consistency with the remove_permissions endpoint, providing a unified developer experience across permission management operations.Also applies to: 205-205, 291-291, 353-353, 398-398
128-136: Well-designed helper function.The
containshelper function elegantly handles potential ordering differences in response data, making the tests more robust and maintainable.
376-432: Excellent validation of auto-creation feature.This test case effectively validates the key PR feature of automatically creating permissions when they don't exist, properly verifying both the API response and the resulting database state.
go/apps/api/routes/v2_keys_add_roles/200_test.go (3)
34-34: Consistent RBAC enhancement for role operations.The addition of
"rbac.*.add_role_to_key"permission follows the same enhanced RBAC pattern as the permission endpoints, maintaining consistency across the API.
63-63: Consistent API simplification for roles.The
Roles: []stringformat maintains the same simplification pattern as permissions, providing a unified API experience across both role and permission management operations.Also applies to: 124-124
87-162: Comprehensive idempotent behavior validation.This test effectively validates the nuanced behavior of adding both existing and new roles in a single request, properly verifying that only new role assignments generate audit logs while existing ones remain idempotent.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (3)
60-60: Consistent error test structure.The simplified
Permissions: []stringformat in error tests maintains consistency with the success tests, ensuring comprehensive validation of the API contract.Also applies to: 110-110
76-124: Critical workspace isolation validation.This test properly validates multi-tenant security by ensuring that keys from different workspaces are isolated and return appropriate 404 errors, which is essential for preventing unauthorized cross-workspace access.
51-51: Consistent database type usage.The use of
dbtype.NullStringmaintains type consistency across all test files and supports the project's type unification effort.Also applies to: 104-104
go/pkg/db/role_list_by_key_id.sql_generated.go (4)
14-33: Efficient SQL query enhancement.The JSON aggregation of permissions within roles is well-designed, using appropriate MySQL JSON functions and COALESCE to handle edge cases. This approach efficiently avoids N+1 query problems and provides rich data in a single query.
35-43: Well-designed struct for enriched data.The new
ListRolesByKeyIDRowstruct appropriately handles the enriched role data with permissions. Usinginterface{}for the JSON permissions field is a pragmatic choice that provides flexibility for JSON unmarshaling.
66-66: Appropriate method signature update.The change from
[]Roleto[]ListRolesByKeyIDRowproperly reflects the enhanced data structure and maintains type safety for the enriched query results.
72-87: Correct scanning logic implementation.The updated scanning logic properly handles the new
Permissionsfield while maintaining consistent error handling patterns throughout the function.go/apps/api/routes/v2_keys_add_permissions/404_test.go (4)
14-14: LGTM: Custom nullable string type import.The addition of the
dbtypeimport supports the migration fromsql.NullStringto the customdbtype.NullStringtype, which is consistent with the broader codebase standardization efforts.
36-36: LGTM: Expanded root key permissions for enhanced RBAC.The addition of
"rbac.*.remove_permission_from_key"permission scope aligns with the enhanced permission management capabilities introduced in this PR, ensuring proper authorization for permission-related operations.
46-63: LGTM: Simplified permission request structure and improved clarity.The changes effectively implement the PR objective of supporting both permission ID and slug by:
- Clearer variable naming: Using
permissionSlugvariable for better readability- Simplified request format: Converting from complex struct with optional
Create,Id, andSlugfields to a straightforward[]stringslice- Consistent database types: Migration to
dbtype.NullStringaligns with codebase standardizationThe simplified API request format makes the endpoint more intuitive while maintaining the flexibility to accept either IDs or slugs.
112-119: LGTM: Consistent application of refactoring patterns.The changes maintain consistency with the previous test case by:
- Database type consistency: Using
dbtype.NullStringfor the description field- Simplified request structure: Using permission ID directly in the string slice format
This uniform application of the refactoring ensures consistency across all test scenarios.
go/apps/api/routes/v2_keys_add_permissions/403_test.go (4)
13-15: LGTM: Enhanced imports for improved test infrastructure.The added imports support key improvements:
dbtype: Enables migration to custom nullable string types for better type safetyseed: Provides structured helper methods for test data creation, improving test maintainability
36-76: LGTM: Improved test data creation and simplified request structure.The refactoring enhances test quality through:
- Helper method adoption: Replacing manual SQL inserts with
h.CreateApi()andh.CreateKey()improves maintainability and reduces boilerplate- Structured seed requests: Explicit field specification makes test setup clearer and more maintainable
- Simplified permission requests: Converting from complex objects to string slices aligns with the PR's goal of supporting ID or slug references
- Database type consistency: Migration to
dbtype.NullStringmaintains consistency with codebase standards
121-156: LGTM: Consistent refactoring applied to cross-workspace test.The changes maintain consistency with the overall refactoring approach:
- Helper method usage:
h.CreateWorkspace(),h.CreateApi(), andh.CreateKey()provide better abstraction- Structured test data: Explicit field specification improves test clarity
- Simplified requests: String slice format for permissions maintains consistency with other test cases
The cross-workspace authorization logic remains intact while benefiting from improved test infrastructure.
151-151: LGTM: Proper RBAC permission configuration.The addition of
"rbac.*.add_permission_to_key"ensures the root key has the necessary permissions for the enhanced permission management operations being tested, maintaining proper authorization scope.go/apps/api/routes/v2_keys_set_roles/200_test.go (4)
43-75: LGTM: Simplified role request structure improves API usability.The refactoring from complex role objects to a simple string slice (
[]string{roleName}) aligns with the PR objective of simplifying permission and role management. The test logic and assertions remain intact, ensuring continued verification of role assignment functionality.
127-155: LGTM: Improved readability with consistent simplification.The changes enhance test quality through:
- Clearer variable naming: Using
roleNamevariable improves code readability- Consistent request format: String slice format maintains consistency with other test cases
- Preserved test logic: Role replacement functionality verification remains intact
242-242: LGTM: Intuitive empty roles representation.Using an empty string slice (
[]string{}) to represent clearing all roles is intuitive and aligns well with the simplified API design. This clearly communicates the intent to remove all role associations.
298-324: LGTM: Consistent pattern applied to idempotent operation test.The changes maintain the established refactoring pattern:
- Clear variable naming:
roleNamevariable improves readability- Simplified request format: String slice maintains consistency
- Important edge case: Continues to verify that no audit logs are created when no changes occur
This ensures the API correctly handles idempotent operations with the new simplified format.
go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (2)
13-34: LGTM: Well-designed query supporting flexible role lookup.The SQL query effectively implements the PR's objective of supporting both ID and name-based role lookup:
- Efficient data fetching: JSON aggregation of permissions reduces database round-trips
- Flexible lookup: OR condition supports both
r.id = ?andr.name = ?searches- Proper scoping: Workspace-scoped queries prevent cross-workspace access
- Null handling:
COALESCEensures roles without permissions return empty JSON arrays
36-86: LGTM: Well-structured generated code with efficient parameter design.The generated code demonstrates good design principles:
- Efficient parameters: Single
Searchfield supports both ID and name lookup without duplication- Appropriate types:
interface{}forPermissionsfield correctly handles JSON data- Standard patterns: Generated method follows established sqlc conventions
- Proper error handling: Standard error propagation from database operations
go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (2)
14-40: LGTM: Proper extension of single role query for batch operations.The query effectively scales the single role lookup pattern for multiple roles:
- Consistent structure: Maintains the JSON aggregation and COALESCE patterns from the single role query
- Batch-friendly: Uses
INclauses for efficient multiple role lookup- Flexible matching: Same search terms can match either role IDs or names via OR condition
- Proper scoping: Workspace restriction prevents cross-workspace access
78-93: No action needed: duplicate search parameter processing is required.The two identical blocks correspond to two separate
/*SLICE:search*/?placeholders—each must expand thearg.Searchslice and append its values in order. This duplication is expected for correctly binding parameters to both IN clauses.go/apps/api/routes/v2_keys_remove_roles/handler.go (7)
59-65: Good: Explicit null handling for hash parameterThe change to use
FindKeyByIdOrHashwith explicitsql.NullStringhandling is cleaner and more explicit than the previous approach. This aligns well with Go's preference for explicit null handling.
79-85: Security improvement: Early workspace validationMoving the workspace validation before permission checks is a good security practice. This prevents potential information leakage about key existence across workspaces.
115-130: Efficient batch role lookupThe refactoring to use
FindManyRolesByNamesWithPermsfor batch role lookup is more efficient than individual lookups. The dual-key map approach (by ID and name) is clever for validation.
142-151: Elegant role filtering logicThe logic to filter roles that are currently assigned is clean and efficient. The in-place deletion from
currentRoleIDswhile buildingrolesToRemoveis a nice optimization.
189-200: Performance improvement: Batch deletionThe change to use
DeleteManyKeyRolesByKeyAndRoleIDsfor batch deletion is a significant performance improvement over multiple individual deletes.
215-243: Efficient response constructionThe optimization to avoid an extra database query by using the remaining roles in
currentRoleIDsis excellent. This reduces database load while maintaining correctness.
94-94: Permission scope change is consistent across key handlersThe switch from
key.KeyAuthIDto using the API’s ID (key.Api.ID) forResourceIDmatches all other key-related endpoints (get, update, delete, set/remove roles/permissions). No further action needed here.go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml (1)
20-32: API simplification: String-based role referencesThe simplification from complex objects to string arrays for role names is a good API design improvement. The pattern validation
^[a-zA-Z][a-zA-Z0-9_-]*$aligns with the learnings about role name validation at the OpenAPI schema layer.go/apps/api/routes/v2_keys_add_roles/handler.go (3)
87-110: Comprehensive permission checksThe compound permission check using
rbac.Andto require both update key permission AND add role permission is excellent security practice. This ensures proper authorization for role management operations.
204-212: Efficient batch insertionThe use of
BulkQuery.InsertKeyRolesfor batch insertion is more efficient than individual inserts. Good performance optimization.
227-241: Smart response constructionThe approach of wrapping newly added roles and appending them to current roles for the response is efficient and avoids an extra database query.
go/pkg/db/role_list.sql_generated.go (1)
14-34: Efficient permission aggregationThe JSON aggregation approach to include permissions with roles in a single query is excellent for performance. The use of
COALESCEwithJSON_ARRAY()ensures consistent return types even when no permissions exist.go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go (2)
72-79: Proper handling of dynamic IN clauseThe dynamic SQL construction for the IN clause is well-implemented with proper handling of the empty slice case. The approach of replacing with NULL when no names are provided is appropriate.
68-108: Well-structured batch query implementationThis new query method provides efficient batch role lookup with permissions included. The implementation follows sqlc patterns correctly and includes proper error handling and resource cleanup.
go/apps/api/routes/v2_keys_set_permissions/handler.go (1)
219-263: Well-implemented batch deletion with comprehensive audit loggingThe batch deletion using
DeleteManyKeyPermissionByKeyAndPermissionIDsis efficient, and the audit logging properly captures all permission removal events with appropriate metadata.go/pkg/db/querier_generated.go (1)
42-46: Well-structured database interface improvementsThe new batch delete methods, enriched role queries with permissions, and the upsert behavior for key permissions all support more efficient database operations. The changes to return full Permission structs instead of partial data improve type safety and reduce the need for additional queries.
Also applies to: 52-56, 317-339, 340-359, 368-373, 390-393, 809-810, 1186-1206, 1209-1228
go/apps/api/openapi/gen.go (4)
127-128: Good standardization of empty responsesThe introduction of
EmptyResponseas a unified type for empty success responses improves API consistency and makes the intent clear in the generated code.
741-743: Permission handling improvements align with PR objectivesThe updated permission fields now correctly support both IDs and slugs as strings, with clear documentation about auto-creation behavior when the root key has appropriate permissions. This simplification makes the API more flexible and user-friendly.
Also applies to: 995-999, 1082-1096
1485-1500: Consistent field naming for ID/slug flexibilityThe renaming from
PermissionId/RoleIdtoPermission/Roleaccurately reflects that these fields now accept either IDs or slugs/names. The comprehensive deletion warnings in the documentation are appropriate for these irreversible operations.Also applies to: 1513-1527, 1540-1542, 1560-1566
776-776: Clean response type definitionsThe response data types are now consistently defined as arrays of
PermissionorRoleobjects, providing a cleaner and more predictable API surface for clients.Also applies to: 826-826, 1026-1026, 1078-1078, 1129-1129, 1182-1182
go/apps/api/openapi/openapi-generated.yaml (2)
1451-1455: Role-delete regex inconsistent with role-add (dot missing).
roledeletion pattern omits the dot (.) allowed during add/set operations (^[a-zA-Z][a-zA-Z0-9._-]*$). Users could addfinance.readbut never delete it.- pattern: "^[a-zA-Z][a-zA-Z0-9_-]*$" + pattern: "^[a-zA-Z][a-zA-Z0-9._-]*$"⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581 Timestamp: 2025-07-15T14:47:20.490Z Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.Learnt from: ogzhanolguncu PR: unkeyed/unkey#3324 File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18 Timestamp: 2025-06-19T11:48:05.070Z Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.Learnt from: chronark PR: unkeyed/unkey#3617 File: go/apps/api/openapi/openapi.yaml:3309-3312 Timestamp: 2025-07-16T17:51:57.297Z Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
1513-1518: Same dot-exclusion issue for role-get endpoint.Apply the same regex fix as the delete-role block to maintain consistency.
⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581 Timestamp: 2025-07-15T14:47:20.490Z Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.Learnt from: AkshayBandi027 PR: unkeyed/unkey#2215 File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29 Timestamp: 2024-10-08T15:33:04.290Z Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.Learnt from: ogzhanolguncu PR: unkeyed/unkey#3324 File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18 Timestamp: 2025-06-19T11:48:05.070Z Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 24
🔭 Outside diff range comments (1)
go/apps/api/routes/v2_keys_set_roles/200_test.go (1)
35-35: Add missing RBAC permissions for set‐roles testsThe 200 test in
go/apps/api/routes/v2_keys_set_roles/200_test.goonly gives the root key the"api.*.update_key"permission, but setting roles internally performs both add and remove operations. As in theadd_rolesandremove_rolestests, you need to grant both RBAC permissions:• File: go/apps/api/routes/v2_keys_set_roles/200_test.go
Line 35- rootKey := h.CreateRootKey(workspace.ID, "api.*.update_key") + rootKey := h.CreateRootKey( + workspace.ID, + "api.*.update_key", + "rbac.*.add_role_to_key", + "rbac.*.remove_role_from_key", + )Apply the same update to the other
v2_keys_set_roles/*_test.gofiles (400, 404, etc.) to keep them consistent.
♻️ Duplicate comments (12)
go/apps/api/routes/v2_keys_update_key/handler.go (1)
92-92: Address the TODO comment about role permission checks.This TODO was already flagged in a previous review. The missing RBAC checks for role operations should be implemented.
go/apps/api/routes/v2_keys_add_permissions/400_test.go (1)
202-202: Ensure specific validation error messages are retained.The test now only asserts a generic "failed to validate schema" error message, which reduces clarity on specific validation issues. This aligns with the concern raised in previous reviews about maintaining comprehensive error feedback for users.
go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (1)
49-49: Use[]byteinstead ofinterface{}for the Permissions field.Same issue as in other generated files. The
Permissionsfield should be[]bytefor proper JSON handling.go/apps/api/openapi/openapi-generated.yaml (9)
968-983: Same slug-only wording + pattern duplication – see earlier comments.
1201-1207: Inconsistent wording again (“slug” only)
Please apply the same wording fix here to stay consistent.
2106-2110: List description should match mixed identifier capability
Same wording fix as earlier: slugs or IDs.
2508-2511: Consistent wording needed – same slug vs slug/ID issue.
533-545: Still says “slug” even though the endpoint now accepts slug or ID
This is the exact wording flagged in a previous round and is unchanged.- description: Specify the permission by its slug. + description: Specify the permission by its slug **or** its `perm_*` ID.
876-895: Same “slug only” wording issue – please keep the docs consistent with the new mixed identifier capability.
927-938: Role removal description ignores IDs
Replace “role by name” with “role by name or role_* ID”.
955-963:keyIdpattern still too permissive – allowsfooBar
Previous review asked to enforce the requiredkey_prefix; pattern is unchanged.- pattern: "^[a-zA-Z0-9_]+$" + pattern: "^key_[a-zA-Z0-9]+$"
2352-2361:Permission.idregex should enforceperm_prefix- pattern: "^[a-zA-Z0-9_]+$" + pattern: "^perm_[a-zA-Z0-9]+$"Without this, a plain string like
foopasses validation despite docs stating it “Always begins with 'perm_'”.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (87)
go/apps/api/openapi/gen.go(19 hunks)go/apps/api/openapi/openapi-generated.yaml(22 hunks)go/apps/api/openapi/spec/common/role.yaml(0 hunks)go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml(1 hunks)go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml(1 hunks)go/apps/api/routes/v2_apis_list_keys/handler.go(1 hunks)go/apps/api/routes/v2_keys_add_permissions/400_test.go(6 hunks)go/apps/api/routes/v2_keys_add_permissions/401_test.go(2 hunks)go/apps/api/routes/v2_keys_add_permissions/403_test.go(3 hunks)go/apps/api/routes/v2_keys_add_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_add_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_add_roles/200_test.go(4 hunks)go/apps/api/routes/v2_keys_add_roles/400_test.go(3 hunks)go/apps/api/routes/v2_keys_add_roles/401_test.go(1 hunks)go/apps/api/routes/v2_keys_add_roles/403_test.go(4 hunks)go/apps/api/routes/v2_keys_add_roles/404_test.go(11 hunks)go/apps/api/routes/v2_keys_add_roles/handler.go(8 hunks)go/apps/api/routes/v2_keys_create_key/handler.go(6 hunks)go/apps/api/routes/v2_keys_remove_permissions/200_test.go(10 hunks)go/apps/api/routes/v2_keys_remove_permissions/400_test.go(2 hunks)go/apps/api/routes/v2_keys_remove_permissions/404_test.go(7 hunks)go/apps/api/routes/v2_keys_remove_roles/200_test.go(4 hunks)go/apps/api/routes/v2_keys_remove_roles/400_test.go(9 hunks)go/apps/api/routes/v2_keys_remove_roles/401_test.go(6 hunks)go/apps/api/routes/v2_keys_remove_roles/403_test.go(7 hunks)go/apps/api/routes/v2_keys_remove_roles/404_test.go(8 hunks)go/apps/api/routes/v2_keys_remove_roles/handler.go(8 hunks)go/apps/api/routes/v2_keys_set_permissions/200_test.go(14 hunks)go/apps/api/routes/v2_keys_set_permissions/401_test.go(2 hunks)go/apps/api/routes/v2_keys_set_permissions/403_test.go(2 hunks)go/apps/api/routes/v2_keys_set_permissions/404_test.go(4 hunks)go/apps/api/routes/v2_keys_set_permissions/handler.go(6 hunks)go/apps/api/routes/v2_keys_set_roles/200_test.go(7 hunks)go/apps/api/routes/v2_keys_set_roles/400_test.go(0 hunks)go/apps/api/routes/v2_keys_set_roles/401_test.go(1 hunks)go/apps/api/routes/v2_keys_set_roles/403_test.go(2 hunks)go/apps/api/routes/v2_keys_set_roles/404_test.go(14 hunks)go/apps/api/routes/v2_keys_set_roles/handler.go(5 hunks)go/apps/api/routes/v2_keys_update_key/handler.go(8 hunks)go/apps/api/routes/v2_permissions_create_permission/handler.go(4 hunks)go/apps/api/routes/v2_permissions_create_role/handler.go(4 hunks)go/apps/api/routes/v2_permissions_delete_permission/200_test.go(5 hunks)go/apps/api/routes/v2_permissions_delete_permission/403_test.go(4 hunks)go/apps/api/routes/v2_permissions_delete_permission/404_test.go(5 hunks)go/apps/api/routes/v2_permissions_delete_role/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_delete_role/400_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_delete_role/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/404_test.go(2 hunks)go/apps/api/routes/v2_permissions_delete_role/handler.go(2 hunks)go/apps/api/routes/v2_permissions_get_permission/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_get_permission/403_test.go(4 hunks)go/apps/api/routes/v2_permissions_get_role/200_test.go(6 hunks)go/apps/api/routes/v2_permissions_get_role/400_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/401_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/403_test.go(2 hunks)go/apps/api/routes/v2_permissions_get_role/404_test.go(1 hunks)go/apps/api/routes/v2_permissions_get_role/handler.go(3 hunks)go/apps/api/routes/v2_permissions_list_permissions/200_test.go(4 hunks)go/apps/api/routes/v2_permissions_list_permissions/403_test.go(3 hunks)go/apps/api/routes/v2_permissions_list_roles/200_test.go(2 hunks)go/apps/api/routes/v2_permissions_list_roles/handler.go(2 hunks)go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go(1 hunks)go/pkg/db/models_generated.go(2 hunks)go/pkg/db/permission_insert.sql_generated.go(2 hunks)go/pkg/db/plugins/bulk-insert/template_test.go(4 hunks)go/pkg/db/querier_generated.go(7 hunks)go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql(1 hunks)go/pkg/db/queries/role_find_by_id_or_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_find_many_by_id_or_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_find_many_by_name_with_perms.sql(1 hunks)go/pkg/db/queries/role_list.sql(1 hunks)go/pkg/db/queries/role_list_by_key_id.sql(1 hunks)go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go(1 hunks)go/pkg/db/role_list.sql_generated.go(2 hunks)go/pkg/db/role_list_by_key_id.sql_generated.go(1 hunks)go/pkg/db/sqlc.json(1 hunks)go/pkg/db/types/null_string.go(1 hunks)go/pkg/testutil/seed/seed.go(3 hunks)
💤 Files with no reviewable changes (2)
- go/apps/api/routes/v2_keys_set_roles/400_test.go
- go/apps/api/openapi/spec/common/role.yaml
🧰 Additional context used
🧠 Learnings (81)
📓 Common learnings
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_get_permission/403_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_add_permissions/403_test.go (7)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (4)
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/models_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml (5)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_set_permissions/404_test.go (10)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_delete_role/401_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_roles/400_test.go (7)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_keys_add_permissions/401_test.go (7)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_permissions_delete_role/403_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_add_roles/404_test.go (6)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (1)
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_set_roles/403_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go (1)
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_set_permissions/401_test.go (3)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_delete_role/404_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_keys_remove_roles/403_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_keys_add_roles/200_test.go (3)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_permissions_delete_role/handler.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/permission_insert.sql_generated.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_add_roles/403_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (7)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (6)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/plugins/bulk-insert/template_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_delete_role/400_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_permissions/handler.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_set_permissions/403_test.go (10)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_permissions_get_role/404_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_remove_roles/401_test.go (6)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_permissions_create_permission/handler.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_get_role/401_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_create_role/handler.go (5)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_apis_list_keys/handler.go (4)
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For identity deletion operations in the Unkey API, identityId takes precedence over externalId when both are provided in the request body.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_permissions_get_role/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/queries/role_list.sql (1)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_keys_add_roles/401_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/queries/role_list_by_key_id.sql (3)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_permissions_get_role/400_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_add_permissions/400_test.go (10)
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_add_roles/400_test.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_permissions_list_roles/200_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_list_permissions/403_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_keys_update_key/handler.go (12)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #2825
File: apps/dashboard/app/(app)/logs-v2/hooks/use-bookmarked-filters.ts:0-0
Timestamp: 2025-01-30T20:51:44.359Z
Learning: The user (ogzhanolguncu) prefers to handle refactoring suggestions in separate PRs to maintain focus in the current PR.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml (5)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/routes/v2_keys_create_key/handler.go (6)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/sqlc.json (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_remove_roles/handler.go (8)
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_permissions_list_roles/handler.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_remove_roles/404_test.go (5)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_add_permissions/404_test.go (9)
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
go/apps/api/routes/v2_keys_set_permissions/200_test.go (10)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_keys_add_roles/handler.go (5)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_permissions_get_role/403_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_roles/401_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/testutil/seed/seed.go (3)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_permissions_list_permissions/200_test.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/pkg/db/role_list_by_key_id.sql_generated.go (2)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
go/apps/api/routes/v2_permissions_get_role/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_keys_remove_roles/200_test.go (4)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/apps/api/routes/v2_permissions_delete_role/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/routes/v2_permissions_get_permission/200_test.go (3)
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_roles/404_test.go (2)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/apps/api/routes/v2_keys_set_roles/200_test.go (3)
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
go/pkg/db/types/null_string.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/routes/v2_keys_add_permissions/handler.go (7)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.
Learnt from: Flo4604
PR: #3606
File: go/pkg/prometheus/metrics/database.go:29-30
Timestamp: 2025-07-16T10:06:35.397Z
Learning: In Go packages, variables defined in one file within a package (like latencyBuckets and constLabels in go/pkg/prometheus/metrics/http.go) are accessible from other files in the same package without requiring imports. This is a common pattern for sharing configuration across multiple files within a package.
go/pkg/db/querier_generated.go (4)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.
Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.
go/apps/api/routes/v2_keys_set_roles/handler.go (7)
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/openapi/openapi-generated.yaml (16)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
go/apps/api/openapi/gen.go (11)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3647
File: go/apps/api/openapi/openapi-generated.yaml:3569-3575
Timestamp: 2025-07-22T18:09:41.800Z
Learning: In the Unkey codebase, using non-standard HTTP status code 529 for internal-only endpoints is acceptable and should not be flagged as an issue in future reviews.
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{env,sh,yaml,yml,json,conf,ini} : All environment variables MUST follow the format UNKEY_<SERVICE_NAME>_VARNAME.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
🧬 Code Graph Analysis (28)
go/apps/api/routes/v2_permissions_get_permission/403_test.go (1)
go/pkg/db/models_generated.go (1)
Permission(746-754)
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (4)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/testutil/seed/seed.go (1)
New(36-42)go/pkg/uid/uid.go (1)
KeyPrefix(16-16)go/apps/api/routes/v2_keys_remove_permissions/handler.go (1)
Request(22-22)
go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (2)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/pkg/db/key_role_delete_all_by_key_id.sql_generated.go (1)
DeleteAllKeyRolesByKeyID(21-24)
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_keys_set_permissions/404_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/testutil/seed/seed.go (1)
New(36-42)go/pkg/uid/uid.go (1)
KeyPrefix(16-16)
go/apps/api/routes/v2_permissions_delete_role/401_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_keys_add_permissions/401_test.go (4)
go/pkg/testutil/seed/seed.go (2)
CreateApiRequest(79-87)CreateKeyRequest(183-200)go/pkg/uid/uid.go (1)
TestPrefix(24-24)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_role/403_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_permissions_delete_role/404_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_keys_add_roles/200_test.go (2)
go/pkg/testutil/seed/seed.go (1)
CreateRoleRequest(360-366)go/pkg/ptr/pointer.go (1)
P(49-51)
go/pkg/db/permission_insert.sql_generated.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_permission/403_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)
go/apps/api/routes/v2_keys_remove_permissions/200_test.go (5)
go/pkg/testutil/seed/seed.go (2)
CreatePermissionRequest(397-402)New(36-42)go/apps/api/routes/v2_keys_remove_permissions/handler.go (1)
Request(22-22)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/uid/uid.go (1)
TestPrefix(24-24)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)
go/apps/api/routes/v2_permissions_get_role/404_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_get_role/401_test.go (1)
go/apps/api/openapi/gen.go (1)
Role(425-449)
go/apps/api/routes/v2_permissions_create_role/handler.go (2)
go/pkg/fault/wrap.go (2)
Internal(75-89)Public(97-111)go/pkg/sim/events.go (1)
Event(11-19)
go/pkg/db/role_list.sql_generated.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/hydra/store/db.go (1)
DBTX(8-13)
go/apps/api/routes/v2_permissions_list_roles/200_test.go (1)
go/pkg/db/types/null_string.go (1)
NullString(10-10)
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (2)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)
go/apps/api/routes/v2_keys_create_key/handler.go (5)
go/apps/api/openapi/gen.go (1)
Permission(296-316)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/cli/flag.go (1)
String(331-363)
go/apps/api/routes/v2_keys_add_permissions/404_test.go (4)
go/pkg/uid/uid.go (2)
PermissionPrefix(27-27)KeyPrefix(16-16)go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/routes/v2_keys_add_permissions/handler.go (1)
Request(25-25)
go/apps/api/routes/v2_keys_set_permissions/200_test.go (4)
go/pkg/db/permission_insert.sql_generated.go (1)
InsertPermissionParams(33-40)go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/testutil/seed/seed.go (1)
New(36-42)go/pkg/uid/uid.go (2)
TestPrefix(24-24)PermissionPrefix(27-27)
go/apps/api/routes/v2_permissions_list_permissions/200_test.go (2)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/pkg/cli/flag.go (1)
String(331-363)
go/apps/api/routes/v2_permissions_get_role/200_test.go (3)
go/pkg/db/types/null_string.go (1)
NullString(10-10)go/apps/api/openapi/gen.go (1)
Role(425-449)go/pkg/db/models_generated.go (1)
Role(813-820)
go/apps/api/routes/v2_keys_set_roles/200_test.go (3)
go/pkg/rbac/query.go (1)
T(84-90)internal/db/src/types.ts (1)
InsertRole(26-26)go/pkg/db/role_insert.sql_generated.go (1)
InsertRoleParams(30-36)
go/pkg/db/querier_generated.go (11)
go/pkg/hydra/store/db.go (1)
DBTX(8-13)go/pkg/db/key_permission_delete_many_by_key_and_permission_ids.sql_generated.go (1)
DeleteManyKeyPermissionByKeyAndPermissionIDsParams(18-21)go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (1)
DeleteManyKeyRolesByKeyAndRoleIDsParams(18-21)go/pkg/db/role_find_many_by_id_or_name_with_perms.sql_generated.go (2)
FindManyRolesByIdOrNameWithPermsParams(37-40)FindManyRolesByIdOrNameWithPermsRow(42-50)go/pkg/db/role_find_many_by_name_with_perms.sql_generated.go (2)
FindManyRolesByNamesWithPermsParams(34-37)FindManyRolesByNamesWithPermsRow(39-47)go/pkg/db/permission_find_by_id_or_slug.sql_generated.go (1)
FindPermissionByIdOrSlugParams(18-21)go/pkg/db/models_generated.go (1)
Permission(746-754)go/pkg/db/permission_find_by_slugs.sql_generated.go (1)
FindPermissionsBySlugsParams(17-20)go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (2)
FindRoleByIdOrNameWithPermsParams(36-39)FindRoleByIdOrNameWithPermsRow(41-49)go/pkg/db/role_list.sql_generated.go (2)
ListRolesParams(36-39)ListRolesRow(41-49)go/pkg/db/role_list_by_key_id.sql_generated.go (1)
ListRolesByKeyIDRow(35-43)
go/apps/api/openapi/gen.go (2)
go/pkg/codes/unkey_data.go (1)
Data(87-128)go/pkg/db/models_generated.go (2)
Permission(746-754)Role(813-820)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Test API / API Test Local
🔇 Additional comments (165)
go/pkg/db/plugins/bulk-insert/template_test.go (1)
28-28: LGTM: Test coverage updated for ValuesFields functionalityThe addition of
ValuesFieldsto all test cases properly covers the new field in theTemplateDatastruct. Setting it to the same values asFieldsis appropriate for these test scenarios where insertion fields and overall fields are identical.Also applies to: 51-51, 71-71, 113-113
go/apps/api/routes/v2_permissions_get_role/403_test.go (1)
56-56: LGTM! Field renaming aligns with PR objectives.The change from
RoleIdtoRoleproperly supports the PR objective of allowing either role ID or role name in permission-related requests. This change is consistent across both test cases.Also applies to: 83-83
go/apps/api/routes/v2_apis_list_keys/handler.go (1)
189-189: LGTM! Minor formatting improvement.The added blank line improves code readability by separating the error handling block from the subsequent logic.
go/apps/api/routes/v2_permissions_list_roles/200_test.go (1)
14-14: LGTM! Type migration improves consistency.The change from
sql.NullStringtodbtype.NullStringaligns with the broader codebase standardization effort. Thedbtype.NullStringtype provides consistent JSON and SQL handling across the application.Also applies to: 61-61
go/apps/api/routes/v2_permissions_delete_role/403_test.go (1)
62-62: LGTM! Consistent field renaming supports flexible role identification.The change from
RoleIdtoRoleis consistent with the PR objective and matches similar changes across other test files. This allows the endpoint to accept either role ID or role name.Also applies to: 86-86
go/apps/api/routes/v2_permissions_delete_role/401_test.go (1)
27-27: LGTM! Final consistent field renaming.The change from
RoleIdtoRolemaintains consistency with all other test files and supports the unified approach to role identification using either ID or name.go/apps/api/routes/v2_permissions_get_role/401_test.go (1)
26-26: LGTM: Field name update aligns with API model changes.The field name change from
RoleIdtoRoleis consistent with the broader API refactoring that now accepts either role ID or name in the unifiedRolefield.go/apps/api/routes/v2_permissions_get_role/404_test.go (1)
40-40: LGTM: Field name update maintains test coverage.The field name change from
RoleIdtoRoleis consistent with the API model updates. The test continues to appropriately verify 404 responses for non-existent role identifiers.go/apps/api/routes/v2_permissions_delete_role/200_test.go (3)
14-14: LGTM: Import added for standardized nullable string type.The addition of the
dbtypeimport aligns with the codebase standardization of nullable string handling.
68-68: LGTM: Type change standardizes nullable string handling.The change from
sql.NullStringtodbtype.NullStringis part of the broader codebase standardization for nullable string fields.
112-112: LGTM: Field name updates align with API model changes.The field name changes from
RoleIdtoRoleare consistent with the API refactoring that now accepts either role ID or name in the unifiedRolefield. The test logic appropriately covers both role deletion scenarios.Also applies to: 171-171
go/apps/api/routes/v2_permissions_list_permissions/403_test.go (2)
14-14: LGTM: Import standardization for nullable string type.The import change to use the
dbtypepackage aligns with the codebase-wide standardization of nullable string handling.
40-40: LGTM: Type changes standardize nullable string handling.The changes from
sql.NullStringtodbtype.NullStringare consistent with the project-wide type standardization for nullable string fields in database operations.Also applies to: 81-81
go/pkg/db/queries/key_role_delete_many_by_key_and_role_ids.sql (1)
1-3: LGTM! Efficient batch deletion query.The SQL query is well-structured for bulk deletion operations. Using
sqlc.slicefor therole_idsparameter enables efficient batch processing while maintaining proper parameterization to prevent SQL injection.go/pkg/db/models_generated.go (2)
13-13: Proper import for custom nullable string type.The addition of the
dbtypeimport supports the migration from standardsql.NullStringto the customdbtype.NullStringtype.
747-754: Consistent migration to custom nullable string type.The change from
sql.NullStringtodbtype.NullStringfor theDescriptionfield aligns with the broader codebase migration to custom nullable types that provide enhanced JSON and SQL marshaling capabilities.go/apps/api/routes/v2_permissions_delete_role/404_test.go (2)
48-48: Field name updated to support unified role identification.The change from
RoleIdtoRolealigns with the API simplification allowing either role ID or slug to be used for role identification.
83-83: Consistent field naming across test cases.The field name change maintains consistency with the API model updates and supports the unified role identification approach.
go/apps/api/routes/v2_permissions_create_role/handler.go (3)
6-6: Import added for improved error message formatting.The
fmtpackage import supports better error message formatting with quoted role names.
92-92: Enhanced error message with proper role name quoting.The use of
fmt.Sprintfwith%qprovides clearer error messages by properly quoting role names, improving user experience when duplicate role errors occur.
110-110: Consistent use of audit log constants.Replacing hardcoded strings with
auditlog.RoleCreateEventandauditlog.RoleResourceTypeconstants improves maintainability and ensures consistent audit logging across the codebase.Also applies to: 120-120
go/apps/api/routes/v2_keys_add_roles/401_test.go (1)
51-51: Simplified role specification in request payload.The change from a slice of structs to a simple slice of strings aligns with the API model simplification, allowing roles to be specified directly as strings (either IDs or names) rather than requiring structured objects.
go/apps/api/routes/v2_permissions_get_permission/403_test.go (3)
14-14: LGTM: Consistent nullable string type migration.The import change from
sqltodbtypealigns with the codebase-wide migration to use custom nullable string types for better consistency across database operations.
43-43: LGTM: Database operation updated with consistent type.The change from
sql.NullStringtodbtype.NullStringmaintains the same functionality while aligning with the new type system being adopted across the codebase.
59-59: LGTM: Request field renamed for API consistency.The field rename from
PermissionIdtoPermissionaligns with the PR objective to allow either permission ID or slug in permission-related requests, providing a unified field name for both use cases.Also applies to: 86-86
go/apps/api/routes/v2_keys_set_roles/401_test.go (1)
29-29: LGTM: Simplified roles field structure.The change from a complex struct slice with optional
IdandNamefields to a simple string slice aligns with the API model simplification described in the PR. This makes the API more intuitive while maintaining the same functionality for role management.go/apps/api/routes/v2_permissions_list_permissions/200_test.go (2)
13-13: LGTM: Consistent import for nullable string type.The import change to use
dbtypefrom the custom types package aligns with the codebase-wide standardization of nullable string handling.
63-63: LGTM: Database operations updated with consistent type.All permission insertions have been consistently updated to use
dbtype.NullStringinstead ofsql.NullStringfor the Description field, maintaining the same functionality while adopting the standardized type system.Also applies to: 76-76, 150-150
go/apps/api/routes/v2_keys_remove_roles/403_test.go (1)
69-69: LGTM: Consistent roles field simplification across all test cases.All test cases in
TestAuthorizationErrorshave been consistently updated to use simple string slices for theRolesfield instead of complex struct slices. This aligns with the API model simplification that standardizes role operations to use string arrays for role IDs/names, making the API more intuitive and consistent.Also applies to: 122-122, 175-175, 228-228, 281-281, 334-334, 388-388
go/pkg/testutil/seed/seed.go (2)
14-14: LGTM: Import updated for consistent type system.The import change to use
dbtypefrom the custom types package ensures that seed utilities use the same standardized nullable string types as the rest of the codebase.
152-152: LGTM: Seed methods updated with consistent nullable string type.Both
CreateRootKeyandCreatePermissionmethods have been updated to usedbtype.NullStringfor permission descriptions, ensuring that test data creation utilities align with the standardized type system used throughout the codebase.Also applies to: 415-415
go/pkg/db/permission_insert.sql_generated.go (1)
11-11: LGTM: Type standardization aligns with codebase migration.The migration from
sql.NullStringtodbtype.NullStringfor theDescriptionfield is consistent with the broader codebase standardization. The customdbtype.NullStringtype provides enhanced JSON marshaling capabilities while maintaining SQL compatibility.Also applies to: 38-38
go/pkg/db/sqlc.json (1)
44-52: LGTM: Proper SQLC configuration for type standardization.The type override configuration correctly maps
permissions.descriptionto the customdbtype.NullStringtype. This ensures consistent nullable string handling across all generated database operations while maintaining JSON marshaling compatibility.go/apps/api/routes/v2_keys_set_roles/403_test.go (1)
69-69: LGTM: API simplification improves usability.The change from complex role objects to simple string slices aligns with the PR objective of accepting either permission ID or slug. This simplification makes the API more intuitive while maintaining the same authorization testing coverage.
Also applies to: 97-97
go/apps/api/routes/v2_permissions_delete_permission/200_test.go (2)
13-13: LGTM: Type standardization using custom nullable string type.The migration from
sql.NullStringtodbtype.NullStringensures consistent nullable string handling across the codebase with enhanced JSON marshaling capabilities.Also applies to: 55-55, 113-113
67-67: LGTM: Field rename supports unified ID/slug handling.The field name change from
PermissionIdtoPermissionaligns with the PR objective of accepting either permission ID or slug in permission-related requests, providing a more flexible API contract.Also applies to: 126-126
go/apps/api/routes/v2_keys_add_roles/403_test.go (2)
60-60: LGTM: Consistent API simplification across authorization tests.The change from complex role objects to simple string slices maintains comprehensive authorization error testing while simplifying the API contract. This supports the PR objective of accepting either role ID or slug in a unified format.
Also applies to: 124-124, 170-170, 216-216
42-56: LGTM: Improved test setup using helper methods.The migration from manual database inserts to
testutil/seedhelpers improves test maintainability and readability while ensuring proper test data setup.go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesResponseData.yaml (1)
17-17: LGTM! Good schema centralization.The change from inline role object definition to a reference to the common role schema improves maintainability and reduces duplication across the API specification.
go/apps/api/routes/v2_keys_set_permissions/401_test.go (3)
15-15: LGTM! Consistent type migration.The change from
database/sqlimport todbtypepackage aligns with the codebase-wide migration to use internal nullable string types.
75-75: LGTM! Consistent nullable string type usage.The change from
sql.NullStringtodbtype.NullStringis consistent with the broader type migration across the codebase for better JSON marshaling/unmarshaling support.
80-81: LGTM! Simplified permissions structure.The change from complex permission objects to a simple string slice (
[]string{permissionID}) aligns perfectly with the PR objective to accept either permission ID or slug, making the API more user-friendly.go/apps/api/routes/v2_permissions_delete_permission/403_test.go (3)
14-14: LGTM! Consistent import migration.The change to use
dbtypepackage import is consistent with the codebase-wide migration to internal nullable types.
44-44: LGTM! Consistent type usage.The migration from
sql.NullStringtodbtype.NullStringmaintains consistency across the codebase.
60-60: LGTM! Field name aligns with PR objectives.The change from
PermissionIdtoPermissionis semantically better and aligns with the PR objective to accept either permission ID or slug in permission-related requests.Also applies to: 95-95
go/apps/api/routes/v2_permissions_delete_role/400_test.go (2)
41-41: LGTM! Clear comment update.The comment clearly indicates the missing field in the context of the updated field name.
57-58: LGTM! Consistent field name standardization.The change from
RoleIdtoRoleis consistent with the API standardization and aligns with the PR objective to support both role ID and role name references. The test description updates maintain clarity.Also applies to: 60-60
go/apps/api/routes/v2_permissions_delete_permission/404_test.go (3)
14-14: LGTM! Consistent import standardization.The migration to
dbtypepackage maintains consistency across all test files.
47-47: LGTM! Consistent field name updates across all test cases.The uniform change from
PermissionIdtoPermissionacross all test scenarios maintains consistency and aligns with the API's new ability to accept either permission ID or slug.Also applies to: 68-68, 104-104
93-93: LGTM! Consistent nullable type usage.The change to
dbtype.NullStringmaintains type consistency across the codebase.go/pkg/db/queries/role_list.sql (2)
2-16: LGTM! Well-structured JSON aggregation for role permissions.The SQL correctly uses
COALESCEwithJSON_ARRAYAGGto handle roles without permissions, returning an empty JSON array when no permissions exist. The correlated subquery properly joins the role-permission association table with the permissions table.
19-21: Standard cursor-based pagination implementation.The
id_cursorfiltering andLIMIT 101indicate proper cursor-based pagination where the extra item helps determine if there's a next page.go/apps/api/routes/v2_permissions_get_role/200_test.go (5)
14-14: Appropriate use of custom dbtype package.The import of
dbtypealigns with the codebase's custom database type wrappers.
67-67: Consistent use of dbtype.NullString for nullable fields.The change from
sql.NullStringtodbtype.NullStringmaintains consistency with the codebase's custom database types.
84-84: Request field properly updated to support flexible role identification.The change from
RoleIdtoRolealigns with the PR objective to accept either role ID or name, improving API flexibility.Also applies to: 140-140
127-127: Role name simplified and follows naming conventions.The change from
"test.get.role.no.perms"to"rolewithoutpermissions"follows cleaner naming conventions and aligns with the test's purpose.
163-164: Test assertions correctly updated for new response structure.The assertions properly check for an empty permissions slice, which matches the updated API response structure where permissions are returned as slices rather than nullable fields.
go/pkg/db/queries/role_find_many_by_id_or_name_with_perms.sql (1)
1-21: Well-implemented batch role lookup with flexible identification.The query correctly implements the PR objective of accepting either role IDs or names. The JSON aggregation pattern is consistent with other role queries, and the use of
sqlc.slicefor variable-length IN clauses is appropriate for batch operations.go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesResponseData.yaml (1)
17-17: Good use of shared schema reference for consistency.Using
$refto the common role schema promotes consistency across the API specification and reduces duplication. This aligns with the broader refactoring to unify role representations.go/pkg/db/queries/role_find_many_by_name_with_perms.sql (1)
1-18: Clean implementation for name-based role lookup.The query follows the established JSON aggregation pattern and correctly filters roles by name only. The use of
sqlc.slicefor the names parameter properly handles variable-length IN clauses for batch operations.go/apps/api/routes/v2_permissions_delete_role/handler.go (3)
66-69: LGTM! Enhanced role lookup supports ID or name.The change from a simple role ID lookup to
FindRoleByIdOrNameWithPermsaligns perfectly with the PR objective to support both role IDs and names/slugs. The query properly scopes to the authorized workspace and includes permissions data in a single query, improving efficiency.
84-84: Correct usage of resolved role ID throughout database operations.All database operations now consistently use
role.IDfrom the resolved role instead ofreq.Role, ensuring they operate on the actual role record found by the flexible lookup. This prevents potential issues if the request contained a role name that needed to be resolved to an ID.Also applies to: 92-92, 100-100
111-111: Good standardization of audit log constants.Replacing hardcoded string literals with predefined constants (
auditlog.RoleDeleteEvent,auditlog.RoleResourceType) improves maintainability and reduces the risk of typos in audit logging. The display message correctly uses the resolvedrole.ID.Also applies to: 116-116, 121-122
go/apps/api/routes/v2_permissions_create_permission/handler.go (3)
14-14: Good migration to internal nullable string types.The change from
sql.NullStringtodbtype.NullStringstandardizes the codebase to use internal types consistently. This provides better control over database type handling and aligns with the broader refactoring across permission-related handlers.Also applies to: 78-78
99-99: Excellent standardization of audit log constants.Using
auditlog.PermissionCreateEventandauditlog.PermissionResourceTypeinstead of hardcoded strings improves maintainability and prevents typos in audit logging.Also applies to: 109-109
111-111: Audit log resource Name is intentionally using the slug for permissionsThe change in v2_permissions_create_permission (
Name: req.Slug,DisplayName: req.Name) aligns with our pattern of logging a machine-friendly identifier separately from the human-readable label. In contrast, roles have no slug, so bothNameandDisplayNameremainreq.Name. No further edits are required here.go/pkg/db/queries/role_find_by_id_or_name_with_perms.sql (1)
1-21: Well-designed SQL query supporting flexible role lookup.This query effectively implements the core requirement of finding roles by either ID or name while efficiently aggregating permissions as JSON. Key strengths:
- Flexible search: Uses
sqlc.arg('search')for both ID and name comparison- Efficient aggregation: Single query retrieves role and permissions together
- Proper null handling:
COALESCEwithJSON_ARRAY()handles roles without permissions- Complete permission data: Includes all relevant permission fields (id, name, slug, description)
- Workspace scoping: Properly restricts results to the authorized workspace
The JSON aggregation approach is efficient and avoids N+1 query problems.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesResponseData.yaml (1)
16-16: Good schema centralization with shared role reference.Replacing the inline role object definition with a reference to the common role schema improves maintainability and ensures consistent role representation across all API endpoints. This aligns well with the PR's goal to standardize permission and role schemas.
go/apps/api/routes/v2_keys_remove_roles/401_test.go (1)
66-66: Excellent test simplification aligning with API changes.The conversion from complex role structs with optional
IdandNamefields to simple string slices makes the test code cleaner and aligns perfectly with the simplified API request format. This reduces test complexity while maintaining the same test coverage for authentication error scenarios.Also applies to: 116-116, 167-167, 218-218, 269-269, 324-324
go/apps/api/routes/v2_keys_create_key/handler.go (4)
20-20: LGTM! Import addition for custom nullable string type.The addition of the
dbtypeimport aligns with the codebase migration fromsql.NullStringto the customdbtype.NullStringtype for nullable database fields.
367-370: LGTM! Improved consistency with full Permission struct.The change from using
db.FindPermissionsBySlugsRowtodb.Permissionimproves consistency throughout the permission handling logic.
435-435: LGTM! Standardized audit log resource types.Replacing hardcoded strings with constants from the
auditlogpackage (auditlog.KeyResourceType,auditlog.PermissionResourceType,auditlog.RoleResourceType,auditlog.APIResourceType) improves maintainability and consistency across the codebase.Also applies to: 442-442, 522-522, 529-529, 564-564, 571-571
392-400: Please manually verify UpdatedAtM handling in InsertPermissions SQLI wasn’t able to locate the generated
InsertPermissionsimplementation to confirm whether theupdated_at_mcolumn is part of the INSERT. Before merging, please check the SQL in the generated bulk-insert file for permissions and ensure that:
- If
updated_at_mis listed in the INSERT columns, your struct provides a valid timestamp.- If it’s omitted, the zero-value (
Valid: false) is correct.go/apps/api/routes/v2_permissions_list_roles/handler.go (2)
5-5: LGTM! Import addition for JSON unmarshaling.The
encoding/jsonimport is correctly added to support the new inline permission unmarshaling logic.
91-96: LGTM! Simplified role response structure.The removal of the
CreatedAtfield aligns with the API model simplifications mentioned in the PR objectives.go/apps/api/routes/v2_permissions_get_permission/200_test.go (4)
13-13: LGTM! Import change aligns with codebase migration.The addition of
dbtypeimport aligns with the codebase-wide migration fromsql.NullStringto the customdbtype.NullStringtype.
42-56: LGTM! Improved test setup efficiency.Creating the permission once before running multiple subtests is more efficient and follows good testing practices.
59-59: LGTM! Comprehensive test coverage for unified Permission field.The subtests effectively verify that both permission ID and slug retrieval work correctly with the unified
Permissionfield, aligning with the PR objective to accept either permission ID or slug.Also applies to: 86-106
53-53: LGTM! Consistent use of dbtype.NullString.The migration from
sql.NullStringtodbtype.NullStringis consistent with the broader codebase changes.Also applies to: 119-119
go/apps/api/routes/v2_keys_set_permissions/403_test.go (4)
13-13: LGTM! Import changes align with test modernization.The addition of
dbtypeandseedimports, along with removal of unused imports, aligns with the test modernization using seed helpers and the codebase migration to custom nullable types.Also applies to: 15-15
36-61: LGTM! Simplified test setup using seed helpers.The refactoring from manual database insertions to using
h.CreateApiandh.CreateKeyseed helpers significantly simplifies the test setup and improves maintainability.
63-63: LGTM! Corrected permission ID prefix.The change from
uid.TestPrefixtouid.PermissionPrefixis the correct prefix for permission entities and aligns with proper UID conventions.
69-69: LGTM! Simplified request structure and consistent nullable type usage.The simplification of the
Permissionsfield from complex objects to a string slice aligns with the API model changes, and the use ofdbtype.NullStringis consistent with the codebase migration.Also applies to: 75-75
go/apps/api/routes/v2_keys_add_permissions/401_test.go (3)
13-13: LGTM! Import changes support test modernization.The addition of
dbtypeandseedimports, with removal of unused imports, supports the migration to seed helpers and custom nullable types.Also applies to: 15-15
36-53: LGTM! Simplified test setup with seed helpers.The use of
h.CreateApiandh.CreateKeyseed helpers significantly improves test maintainability compared to manual database insertions.
61-61: LGTM! Consistent type usage and simplified request structure.The use of
dbtype.NullStringand simplifiedPermissionsfield as a string slice aligns with the broader codebase changes and API model simplifications.Also applies to: 67-67
go/apps/api/routes/v2_permissions_get_role/handler.go (1)
64-67: Good optimization using a single query.The refactor to use
FindRoleByIdOrNameWithPermsimproves performance by fetching the role and its permissions in a single database query.go/pkg/db/queries/role_list_by_key_id.sql (1)
1-21: Well-structured SQL query with efficient JSON aggregation.The query efficiently retrieves roles with their permissions using JSON aggregation, properly handles empty permission sets, and maintains good performance characteristics.
go/apps/api/routes/v2_keys_add_roles/400_test.go (1)
30-30: Test updates correctly reflect the simplified API structure.The changes appropriately update the test cases to use the new string-based roles format and include the required RBAC permission.
Also applies to: 121-121, 161-161
go/apps/api/routes/v2_keys_update_key/handler.go (2)
416-440: Excellent audit logging for permission creation.The implementation provides comprehensive audit trails for each created permission with all relevant metadata.
461-468: Good practice using consistent timestamps for batch inserts.Using a single timestamp ensures all permissions in the batch have identical creation times, which is appropriate for atomic operations.
go/apps/api/routes/v2_keys_remove_permissions/404_test.go (1)
15-15: Test updates align with API simplification and type improvements.The changes correctly update tests to use the new string-based permissions format and custom nullable types, maintaining good test coverage.
Also applies to: 38-38, 60-61, 98-99, 132-132, 235-235
go/apps/api/routes/v2_keys_add_permissions/400_test.go (4)
15-15: LGTM - Import aligns with type standardization.The addition of the
dbtypeimport supports the migration fromsql.NullStringtodbtype.NullStringthroughout the codebase, which provides better type consistency.
37-37: LGTM - Enhanced RBAC permission scope.The addition of
"rbac.*.add_permission_to_key"permission to the root key creation aligns with the PR's objective to enable permission creation when the root key has the necessary permissions.
188-189: LGTM - API simplification improves usability.The change from complex permission objects with optional
IdandSlugfields to a simple string array makes the API more intuitive and easier to use. OpenAPI schema validation ensures input integrity.
183-183: LGTM - Type standardization for nullable strings.The migration from
sql.NullStringtodbtype.NullStringimproves consistency across the codebase while maintaining the same underlying functionality.go/apps/api/openapi/spec/paths/v2/permissions/deleteRole/V2PermissionsDeleteRoleRequestBody.yaml (3)
3-5: LGTM - Field name simplification improves API consistency.Renaming
roleIdtorolemakes the API more intuitive since the field now accepts either role IDs or names, aligning with the broader API unification effort.
7-8: LGTM - Validation pattern matches role naming requirements.The regex pattern
"^[a-zA-Z][a-zA-Z0-9_-]*$"andminLength: 3correctly implement the role naming validation requirements, allowing names that start with a letter followed by letters, numbers, underscores, or hyphens.
10-12: LGTM - Clear documentation for dual-purpose field.The updated description clearly explains that the field accepts either a role ID (starting with 'role_') or a role name, providing better guidance for API users while maintaining important deletion warnings.
go/apps/api/openapi/spec/paths/v2/keys/removeRoles/V2KeysRemoveRolesRequestBody.yaml (2)
20-20: LGTM - Schema simplification with appropriate constraints.The addition of
maxItems: 100provides reasonable abuse protection, and the simplification from complex role objects to strings with proper validation patterns improves API usability while maintaining data integrity.Also applies to: 28-32
32-32: LGTM - Concise description matches simplified schema.The simplified description "Specify the role by name." clearly communicates the expected input format for the string-based role specification.
go/apps/api/routes/v2_keys_set_roles/404_test.go (2)
81-81: LGTM - Consistent API simplification across test cases.The conversion from complex role objects with
IdandNamepointers to simple string arrays consistently applies the API simplification pattern across all test scenarios, improving test readability and maintainability.Also applies to: 105-105, 129-129, 192-192, 237-237, 259-259, 284-284, 309-309, 334-334
119-119: LGTM - Improved error message assertions.Using
fmt.Sprintfto format expected error messages with specific role identifiers provides more precise validation of error responses, ensuring exact matching rather than generic substring checks.Also applies to: 143-143, 251-251, 273-273, 298-298, 348-348
go/apps/api/routes/v2_keys_remove_permissions/400_test.go (2)
13-13: LGTM - Consistent type standardization.The addition of
dbtypeimport supports the migration to standardized nullable string types, maintaining consistency with other test files in this PR.
167-167: LGTM - Aligned with API simplification pattern.The change from
sql.NullStringtodbtype.NullStringand the simplification of the permissions field from complex objects to a string array maintains consistency with the broader API refactoring effort.Also applies to: 174-175
go/apps/api/routes/v2_keys_remove_roles/400_test.go (2)
35-35: LGTM! Proper permission scope added.The addition of
"rbac.*.remove_role_from_key"permission to the root key creation is necessary for the test to have proper authorization for role removal operations.
86-86: LGTM! Consistent role representation simplification.The conversion from complex role structures to simple string slices (
[]string) aligns with the API simplification goals. All test cases maintain their coverage while using the cleaner format that accepts either role IDs or names directly.Also applies to: 114-114, 185-185, 222-222, 259-259, 289-289, 335-335, 383-383
go/apps/api/openapi/spec/paths/v2/keys/setRoles/V2KeysSetRolesRequestBody.yaml (1)
28-32: LGTM! Proper validation pattern and API simplification.The schema correctly implements the role name validation pattern
^[a-zA-Z][a-zA-Z0-9_-]*$which matches the established validation standards in the codebase. The simplification to string-based role references with appropriate length constraints (3-255 characters) aligns with the API streamlining objectives.go/apps/api/routes/v2_keys_add_roles/404_test.go (3)
36-36: LGTM! Correct permission scope for add roles operation.The addition of
"rbac.*.add_role_to_key"permission ensures proper authorization for the add roles test scenarios.
48-48: LGTM! Consistent API simplification across test cases.The conversion to string slices for role representation maintains comprehensive test coverage while aligning with the simplified API design. All scenarios including error cases, cross-workspace isolation, and multi-role operations are properly tested.
Also applies to: 88-88, 126-126, 164-164, 212-212, 261-261, 311-311, 365-365, 415-415
298-302: LGTM! Improved variable naming for clarity.The variable naming changes from ID-based to name-based variables (
validName,invalidName) improve code readability and align with the string-based role representation.Also applies to: 307-307, 324-324
go/pkg/db/key_role_delete_many_by_key_and_role_ids.sql_generated.go (1)
27-41: LGTM! Well-implemented batch deletion method.The generated method properly handles:
- Dynamic IN clause construction for variable-length role ID slices
- Empty slice edge case by replacing with NULL
- Consistent parameter binding and error handling
- Follows established patterns from similar batch operations
This enables efficient bulk deletion of key-role associations, improving performance over individual delete operations.
go/apps/api/routes/v2_keys_remove_roles/404_test.go (3)
35-35: LGTM! Consistent permission scoping.The addition of
"rbac.*.remove_role_from_key"permission maintains consistency with the RBAC permission model across test files.
59-59: LGTM! Comprehensive error scenario coverage with simplified API.The string-based role representation maintains all critical error test scenarios including cross-workspace isolation, non-existent roles by ID/name, and multi-role operations with partial failures.
Also applies to: 98-98, 138-138, 188-188, 238-238, 288-288, 338-338
324-328: LGTM! Clear and consistent variable naming.The variable naming improvements (
validName,nonExistentRoleName) enhance test readability and clearly indicate the test scenarios being exercised.Also applies to: 334-334
go/apps/api/routes/v2_keys_add_roles/200_test.go (1)
34-34: LGTM! Permission scope correctly updated.The addition of
"rbac.*.add_role_to_key"permission aligns with the enhanced RBAC checks in the handler.go/apps/api/routes/v2_keys_remove_roles/200_test.go (1)
35-35: LGTM! Permission scope correctly updated.The addition of
"rbac.*.remove_role_from_key"permission is consistent with the enhanced RBAC checks.go/apps/api/routes/v2_keys_remove_permissions/200_test.go (4)
13-13: LGTM! Import change aligns with codebase standardization.The switch from
database/sqltodbtypefor nullable string types is consistent with the codebase-wide migration to use the customdbtype.NullStringwrapper.
35-35: Appropriate RBAC permission added for test authorization.The addition of
"rbac.*.remove_permission_from_key"permission to the root key is correct and necessary for testing the remove permissions endpoint.
72-75: Request structure correctly simplified to match API schema.The change from complex permission objects to a simple string slice aligns with the API model simplifications across the codebase.
259-259: Consistent use of dbtype.NullString for nullable fields.The migration from
sql.NullStringtodbtype.NullStringis properly applied here, maintaining consistency with the database model changes across the codebase.Also applies to: 270-270
go/apps/api/routes/v2_keys_set_permissions/404_test.go (2)
35-35: Correct RBAC permissions for set operations.The root key appropriately includes both
"rbac.*.remove_permission_from_key"and"rbac.*.add_permission_to_key"permissions, which are necessary for the set operation that may both add and remove permissions.
59-61: Request payload correctly simplified.The change to use permission IDs directly as strings in the request aligns with the API schema simplification.
Also applies to: 109-111
go/apps/api/routes/v2_keys_add_permissions/403_test.go (2)
36-44: Good refactoring to use test helpers.The migration from manual database operations to using
seedhelper functions improves test maintainability and reduces boilerplate code.Also applies to: 46-61
74-76: Request structure properly updated.The simplified permission array format is consistently applied across all test cases.
go/apps/api/routes/v2_keys_set_roles/handler.go (3)
60-66: Improved key lookup with explicit null handling.The change to use
FindKeyByIdOrHashwith explicitsql.NullStringparameters is more robust and type-safe than the previous approach.
117-127: Efficient batch role resolution.Good optimization using
FindManyRolesByNamesWithPermsto fetch all roles in a single query instead of individual lookups.
198-201: Efficient bulk role removal.The use of
DeleteManyKeyRolesByKeyAndRoleIDsfor batch deletion is a good performance optimization compared to individual deletions.go/pkg/db/role_list.sql_generated.go (2)
14-28: Efficient permission aggregation in role query.The use of
JSON_ARRAYAGGwithCOALESCEto aggregate permissions into a JSON array is an excellent optimization, reducing the need for N+1 queries when fetching roles with their permissions.
41-49: LGTM! Generated struct properly handles JSON permissions.The new
ListRolesRowstruct correctly includes the aggregated permissions data. Whileinterface{}is less type-safe thanjson.RawMessage, this is acceptable for sqlc-generated code.go/apps/api/routes/v2_keys_set_permissions/200_test.go (6)
13-13: LGTM! Consistent with codebase migration to custom database types.The import of
dbtypealigns with the project-wide shift fromsql.NullStringtodbtype.NullStringfor better JSON and SQL compatibility.
35-35: LGTM! Proper RBAC permissions for comprehensive testing.The additional permissions (
rbac.*.remove_permission_from_key,rbac.*.add_permission_to_key,rbac.*.create_permission) are necessary for testing the full range of permission-setting operations, including removal, addition, and on-the-fly creation.
64-94: LGTM! Consistent migration to dbtype.NullString.The permission creation properly uses
dbtype.NullStringinstead ofsql.NullString, which is consistent with the project-wide database type migration. The permission setup with matching name and slug values follows the correct pattern.
111-114: LGTM! Simplified permissions request structure.The refactoring from complex permission objects to simple string arrays (permission slugs) significantly improves API usability while maintaining all necessary functionality. This aligns with the broader API simplification effort.
128-139: LGTM! More robust assertion logic.The introduction of the
containshelper function makes the tests more resilient to response ordering variations, which is a best practice since database query results don't guarantee order unless explicitly specified.
180-432: LGTM! Consistent application of migration patterns.All remaining changes properly apply the established patterns:
- Consistent use of
dbtype.NullStringfor nullable descriptions- Simplified permission requests using string arrays
- Proper use of
uid.PermissionPrefixfor permission ID generation- Maintained test coverage for all scenarios including on-the-fly permission creation
The changes preserve all test functionality while aligning with the API simplification effort.
go/apps/api/openapi/spec/paths/v2/keys/addRoles/V2KeysAddRolesRequestBody.yaml (1)
28-32: LGTM! Proper schema simplification with robust validation.The refactoring from complex role objects to simple strings significantly improves API usability. The validation is comprehensive:
- Regex pattern ensures role names start with a letter and contain only valid characters
- Appropriate length constraints (3-255 characters)
- Clear documentation about specifying roles by name
This aligns with the OpenAPI schema validation patterns used throughout the Unkey codebase.
go/apps/api/routes/v2_keys_set_roles/200_test.go (1)
74-323: LGTM! Consistent role request simplification.All test cases properly apply the simplified request structure using
Roles: []string{...}instead of complex objects. The changes maintain test functionality while aligning with the API schema simplification, and the variable naming (roleName) is consistent throughout.go/pkg/db/role_find_by_id_or_name_with_perms.sql_generated.go (2)
13-34: LGTM! Well-structured SQL query with proper aggregation.The SQL query correctly:
- Scopes results by workspace_id for security
- Supports flexible role lookup by either ID or name
- Aggregates permissions using JSON_ARRAYAGG with proper field mapping
- Handles the no-permissions case with COALESCE and empty JSON_ARRAY()
- Uses appropriate table joins for role-permission relationships
36-86: LGTM! Proper Go implementation of the SQL query.The Go code correctly implements the database query:
- Parameter struct appropriately uses a single
Searchfield for flexible ID/name lookup- Result struct includes all necessary fields with proper database tags
Permissionsfield asinterface{}is appropriate for JSON data handling- Query execution properly passes the search parameter for both ID and name comparisons
- Complete field scanning ensures all data is captured
go/apps/api/routes/v2_keys_add_permissions/404_test.go (4)
14-14: LGTM! Consistent dbtype import.The import aligns with the project-wide migration to custom database types for better compatibility.
36-36: LGTM! Proper RBAC permissions for add_permissions endpoint.The addition of
"rbac.*.add_permission_to_key"permission is necessary for testing the add permissions functionality.
46-62: LGTM! Consistent migration patterns applied.The changes properly apply established patterns:
- Use of
uid.PermissionPrefixfor permission ID generation- Migration to
dbtype.NullStringfor nullable descriptions- Simplified request structure using string arrays for permissions
106-119: LGTM! Consistent test patterns maintained.The second test case correctly follows the same migration patterns while testing cross-workspace isolation scenarios. The permission creation and request structure align with the established patterns.
go/apps/api/routes/v2_keys_add_permissions/handler.go (7)
58-64: Good change to support flexible key lookup.The switch from
FindKeyByIDtoFindKeyByIdOrHashallows the endpoint to accept either a key ID or hash, improving API flexibility. The explicit null hash handling is correct.
85-110: Well-structured RBAC permission check.The combined permission requirement (update key + add permission to key) provides proper security controls and prevents unauthorized permission escalation.
120-129: Efficient bulk permission lookup implementation.The use of
FindPermissionsBySlugsfor batch retrieval is a good optimization over individual queries.
131-148: Correct handling of permission resolution by ID or slug.The logic properly identifies missing permissions and handles the dual ID/slug reference pattern.
191-282: Excellent transaction handling with bulk operations.The atomic transaction ensures data consistency, bulk inserts improve performance, and the ON DUPLICATE KEY UPDATE clause provides idempotency. The comprehensive audit logging properly tracks both permission creation and assignment events.
296-325: Proper response construction with full permission details.The response correctly merges existing and newly added permissions, including optional descriptions.
158-189: Permission name validation is enforced by the OpenAPI schema
- All permission names (used as both
NameandSlug) are validated at the schema layer viapattern: "^[a-zA-Z0-9_]+$"and length constraints (1–100) during thezen.BindBodycall.- Invalid values cannot reach this handler, so no additional defensive checks are needed here.
go/pkg/db/querier_generated.go (1)
42-56: Generated interface changes align well with API refactoring.The new batch deletion methods, enriched role queries with permissions JSON, and flexible ID/slug lookups support the broader API simplification. The change to return full
Permissionstructs fromFindPermissionsBySlugs(line 393) provides richer data for API responses.Also applies to: 317-373, 479-501, 809-809, 1186-1228
go/apps/api/openapi/openapi-generated.yaml (9)
176-185:EmptyResponsewiring looks good
The wrapper correctly re-uses the newEmptyResponsecomponent – nothing to add here.
805-814: OK – consistent use ofEmptyResponse
No issues spotted.
1473-1482: Response wrapper OK
Nothing to flag.
1987-1991: 👍 NewEmptyResponsecomponent is fine
2462-2478: LGTM – response definition wiring is correct
2492-2496: LGTM
2526-2529: LGTM
1408-1422: Regex here rejects valid slugs containing:or*
Other endpoints allowdocuments:*style identifiers via^[a-zA-Z0-9_:\\-\\.\\*]+$, but the delete-permission endpoint uses the narrower^[a-zA-Z][a-zA-Z0-9._-]*$. Deleting such a permission would be impossible through the API.- pattern: "^[a-zA-Z][a-zA-Z0-9._-]*$" + pattern: "^[a-zA-Z0-9_:\\-\\.\\*]+$"⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3617 File: go/apps/api/openapi/openapi.yaml:3309-3312 Timestamp: 2025-07-16T17:51:57.297Z Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581 Timestamp: 2025-07-15T14:47:20.490Z Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.Learnt from: chronark PR: unkeyed/unkey#3560 File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466 Timestamp: 2025-07-15T14:25:05.608Z Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
577-589: Review comment not applicable—API only accepts role names, not IDs
Therolesarray is validated and looked up viaFindRolesByNamesagainst theNamecolumn, so passing a role ID will fail. The OpenAPI snippet and handler logic correctly document name-based assignment. If ID support is desired, the handler must be updated first; otherwise, no docs change is needed.Likely an incorrect or invalid review comment.
go/apps/api/openapi/gen.go (4)
127-128: LGTM! EmptyResponse standardization improves consistency.The introduction of the
EmptyResponsetype alias provides a unified way to handle empty response objects across the API, which improves consistency and maintainability. Themap[string]interface{}type allows for future extensibility while maintaining clear "empty by design" semantics.
741-743: Excellent API simplification for permission operations.The changes from complex permission objects to simple
[]stringarrays significantly improve API usability while maintaining full functionality:
- Flexibility: Supporting both permission IDs and slugs gives developers choice in how they reference permissions
- Simplicity: String arrays are much easier to work with than complex objects
- Security: Auto-creation behavior is properly documented with 403 error handling when root key lacks permissions
- Consistency: Same pattern applied across add, remove, and set operations
This is a great example of API design that balances power with simplicity.
Also applies to: 995-996, 1087-1088, 1095-1096
776-776: Proper use of shared Permission and Role structs in responses.The response data types now correctly reference the shared
PermissionandRolestructs, which:
- Maintains consistency with the database models (as seen in
go/pkg/db/models_generated.go)- Provides complete information including IDs, names, descriptions, and other metadata
- Ensures type safety throughout the codebase
- Follows DRY principles by reusing common type definitions
This aligns well with the broader goal of standardizing permission and role representations across the API.
Also applies to: 826-826, 1026-1026, 1129-1129, 1182-1182
1486-1500: Smart field naming for flexible delete and get operations.The change from specific field names (e.g.,
PermissionId,RoleId) to generic names (Permission,Role) is well thought out:
- Intuitive naming that reflects the dual support for both IDs and slugs/names
- Consistent pattern across all permission and role operations
- Clear documentation about the flexibility and consequences of operations
- Proper warnings about the irreversible nature of delete operations
This naming convention better reflects the actual functionality and improves the developer experience by being more intuitive about what values are accepted.
Also applies to: 1514-1527, 1541-1542, 1561-1566
go/apps/api/openapi/spec/paths/v2/permissions/getRole/V2PermissionsGetRoleRequestBody.yaml
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (11)
go/apps/api/openapi/openapi-generated.yaml (11)
2365-2374:Permission.idpattern still too laxPrevious review noted lack of
perm_prefix enforcement; remains unchanged.
2425-2432:role.idstill lacks validation prefix – see prior comment.
541-545: Description still claims “slug” only – but IDs are acceptedThe surrounding docs (line 533+) and PR objective state that either a slug or
perm_*ID is valid, yet theitems.descriptionsays “Specify the permission by its slug.”- description: Specify the permission by its slug. + description: Specify the permission by its slug **or** its `perm_*` ID.
584-588: Regex / length block duplicated – extractRoleIdentifierThe exact type/min/max/pattern/description bundle for roles appears in multiple request bodies. Factor it out into a
components/schemas/RoleIdentifierand$refit everywhere to de-duplicate.
875-883: Same “slug only” wording issue as add-permissionsUpdate the description to reflect slug or ID, otherwise clients will think IDs aren’t allowed.
- description: Specify the permission by its slug. + description: Specify the permission by its slug **or** its `perm_*` ID.
965-971: Out-of-date description againSame wording mismatch – needs “slug or ID”.
1010-1014: Consider re-usingRoleIdentifierhere as well
1192-1195: Permission regex duplicated across spec – see earlier comment on introducing a reusablePermissionIdentifierschema.
2119-2122: Docs still say “permission slugs” only – mirror earlier fixes.
1501-1506:getPermissionclaims ID must start withperm_but regex doesn’t enforce itTo prevent malformed identifiers, tighten the pattern:
- pattern: "^[a-zA-Z][a-zA-Z0-9._-]*$" + pattern: "^perm_[a-zA-Z0-9_]+$"
1424-1435: Delete-permission endpoint accepts slug and ID but regex blocks ‘:*’ & ‘.’The pattern
^[a-zA-Z][a-zA-Z0-9._-]*$disallows:and*, so callers cannot delete wildcard permissions (documents:*) they previously created. It also diverges from the add/remove/set endpoints which use^[a-zA-Z0-9_:\\-\\.\\*]+$.- pattern: "^[a-zA-Z][a-zA-Z0-9._-]*$" + pattern: "^[a-zA-Z0-9_:\\-\\.\\*]+$"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
go/apps/api/openapi/gen.go(19 hunks)go/apps/api/openapi/openapi-generated.yaml(22 hunks)go/pkg/db/types/null_string.go(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/db/types/null_string.go (1)
Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.
go/apps/api/openapi/gen.go (11)
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: Flo4604
PR: #3647
File: go/apps/api/openapi/openapi-generated.yaml:3569-3575
Timestamp: 2025-07-22T18:09:41.800Z
Learning: In the Unkey codebase, using non-standard HTTP status code 529 for internal-only endpoints is acceptable and should not be flagged as an issue in future reviews.
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{env,sh,yaml,yml,json,conf,ini} : All environment variables MUST follow the format UNKEY_<SERVICE_NAME>_VARNAME.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
go/apps/api/openapi/openapi-generated.yaml (16)
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove AIDEV-*s without explicit human instruction.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: ogzhanolguncu
PR: #3661
File: go/apps/api/routes/v2_identities_update_identity/handler.go:115-119
Timestamp: 2025-07-28T11:47:43.144Z
Learning: The v2 update identity endpoint (go/apps/api/routes/v2_identities_update_identity/handler.go) intentionally uses ExternalId field instead of the unified Identity field used in other v2 identity endpoints. This is because the update endpoint needs to both find by externalId and potentially update the externalId value, making the specific field name more appropriate than the generic Identity field.
Learnt from: chronark
PR: #2146
File: apps/dashboard/lib/trpc/routers/api/setDefaultPrefix.ts:80-80
Timestamp: 2024-10-04T17:27:08.666Z
Learning: Ensure that audit log descriptions accurately reflect the action being performed, such as updating the defaultPrefix, and avoid incorrect references like 'name' when not applicable.
Learnt from: MichaelUnkey
PR: #3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Test Go API Local / Test
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Build / Build
- GitHub Check: Test API / API Test Local
- GitHub Check: Test Packages / Test
- GitHub Check: autofix
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (10)
go/pkg/db/types/null_string.go (3)
12-19: MarshalJSON implementation looks good!The method correctly handles both null and valid string cases, using proper JSON marshaling for the string value.
21-35: UnmarshalJSON correctly addresses the previous bug!The implementation now properly unmarshals JSON strings using
json.Unmarshal, which correctly handles quoted strings and escape sequences. This fixes the issue identified in previous reviews.
37-45: SQL interface implementations are correct!Both
ScanandValuemethods properly delegate to the embeddedsql.NullStringtype, ensuring compatibility with database operations.go/apps/api/openapi/openapi-generated.yaml (2)
179-184:EmptyResponsewiring looks goodThe new unified empty envelope is correctly referenced here – this promotes consistent 2-tuple
{meta,data}responses across the spec.
2000-2003:EmptyResponsecomponent added – good abstractiongo/apps/api/openapi/gen.go (5)
123-124: LGTM: Clean introduction of standardized empty response typeThe
EmptyResponsetype alias provides a consistent way to represent empty success responses across the API, replacing multiple ad-hoc empty response implementations. This aligns well with the API standardization effort mentioned in the AI summary.
503-504: LGTM: Consistent adoption of EmptyResponse across API endpointsThe migration to use
EmptyResponsefor delete and update operations creates a uniform response pattern. This improves API consistency and makes it easier for clients to handle empty success responses predictably.Also applies to: 939-940, 1248-1249, 1505-1506, 1532-1533
737-739: LGTM: Simplified permission handling with auto-creation capabilityThe documentation correctly reflects the new feature allowing either permission IDs or slugs, with automatic permission creation when the root key has appropriate permissions. The simplified
[]stringformat makes the API more intuitive while maintaining backward compatibility.Also applies to: 978-983, 1070-1080
772-772: LGTM: Unified Permission and Role struct usageThe migration from inline type definitions to proper
PermissionandRolestructs provides better type consistency and makes the response data more structured. This aligns with the standardization effort described in the AI summary.Also applies to: 822-822, 1010-1010, 1113-1113, 1166-1166
1486-1500: LGTM: Enhanced field semantics for ID/slug flexibilityThe field name changes from
PermissionId/RoleIdtoPermission/Rolewith updated documentation clearly communicate the new capability to accept either IDs or slugs. The comprehensive documentation helps developers understand the flexibility and implications of each approach.Also applies to: 1514-1527, 1541-1542, 1561-1566


What does this PR do?
This updates the permission endpoints to take in either a permissionID or a slug.
When setting or adding permissions, permissions that dont exist will be auto created if the root key has permissions for it.
keyRole endpoints only allow for slugs and not both ids and slugs.
The keyendpoints themselves allow for both.
The operations will fail with a 403 error otherwise.
Also add an unified emptyResponse
Type of change
How should this be tested?
Checklist
Required
pnpm buildpnpm fmtconsole.logsgit pull origin mainAppreciated
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Documentation
Tests