-
-
Notifications
You must be signed in to change notification settings - Fork 973
Plain customer cards #2933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Plain customer cards #2933
Conversation
|
Review CompleteYour review story is ready! Comment !reviewfast on this PR to re-generate the story. |
WalkthroughAdds three optional environment variables: PLAIN_CUSTOMER_CARDS_SECRET, PLAIN_CUSTOMER_CARDS_KEY, and PLAIN_CUSTOMER_CARDS_HEADERS. Implements a new POST route at /api.v1/plain/customer-cards that authenticates via secret/token, validates JSON payloads, looks up users by externalId or email, and returns assembled UI card payloads (account-details, organizations, projects) with caching hints and action/impersonation links. Adds the new endpoint to the rate-limit whitelist. Refactors admin dashboard routes to centralize impersonation handling and token validation. Introduces JWT one-time impersonation tokens with Redis-backed replay protection and exports generate/validate helpers. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Repository UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (7)**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
{packages/core,apps/webapp}/**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
apps/webapp/app/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Files:
apps/webapp/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Files:
**/*.ts📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
Files:
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (4)📚 Learning: 2025-11-27T16:26:58.661ZApplied to files:
📚 Learning: 2026-01-15T11:50:06.067ZApplied to files:
📚 Learning: 2026-01-15T11:50:06.067ZApplied to files:
📚 Learning: 2025-11-27T16:26:58.661ZApplied to files:
⏰ 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). (23)
🔇 Additional comments (1)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@apps/webapp/app/routes/admin._index.tsx`:
- Around line 34-54: The GET-based impersonation flow in loader currently honors
the impersonate query param without CSRF protection; update the flow so the
impersonation URL includes a signed one-time token (e.g., impersonationToken)
when constructed, then in loader parse both impersonate and impersonationToken
and validate the token signature, expiry and single-use before calling
handleImpersonationRequest/redirectWithImpersonation; keep the existing
requireUser(request) admin check, reject the request and do not impersonate if
token validation fails, and mark/invalidate the token after successful use
(store a one-time nonce or use a signed token with server-side revocation) to
prevent replay.
In `@apps/webapp/app/routes/api.v1.plain.customer-cards.ts`:
- Around line 49-55: The logger currently records full request.headers
(including Authorization) and may log customer PII on validation failures;
update the logging in the authenticatePlainRequest failure path and the related
validation error path to redact sensitive fields before logging: filter
request.headers to remove or replace the Authorization header (and any
cookie/header tokens) and ensure any user/customer objects (emails,
external_ids) are omitted or masked in messages logged by logger.warn (refer to
authenticatePlainRequest and the surrounding logger.warn calls); keep the log
message and non-sensitive context but never emit raw Authorization, emails,
external_ids, or similar PII.
- Around line 57-60: The route currently calls request.json() then falls through
to an outer catch that returns 500 for any error; change this to treat malformed
JSON as a client error by wrapping the request.json() call in its own try/catch
(or explicitly checking for a SyntaxError) and return a 400 response when JSON
parsing fails instead of letting the outer catch produce a 500. Update the
handler around request.json() and PlainCustomerCardRequestSchema.safeParse so
that parsing errors produce a 400 with a clear message, while other errors still
propagate to the existing outer catch for 500 handling.
- Around line 125-133: The switch handling cardKeys builds URLs using a
hard-coded "https://cloud.trigger.dev" in multiple places (e.g., the
impersonateUrl construction inside the "account-details" case); extract a single
appOrigin constant (e.g., const appOrigin = env.APP_ORIGIN ||
"https://cloud.trigger.dev") at the start of the switch or function and replace
all occurrences of the hard-coded domain with appOrigin so all URL constructions
(including impersonateUrl and other cases) consistently respect APP_ORIGIN for
self-hosted/staging deployments.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/webapp/app/env.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/services/apiRateLimit.server.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
**/*.{ts,tsx}: Always import tasks from@trigger.dev/sdk, never use@trigger.dev/sdk/v3or deprecatedclient.defineJobpattern
Every Trigger.dev task must be exported and have a uniqueidproperty with no timeouts in the run function
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Import from
@trigger.dev/coreusing subpaths only, never import from root
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webappAccess environment variables via
envexport fromapps/webapp/app/env.server.ts, never useprocess.envdirectly
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
apps/webapp/app/env.server.tsapps/webapp/app/services/apiRateLimit.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
apps/webapp/app/services/**/*.server.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Separate testable services from configuration files; follow the pattern of
realtimeClient.server.ts(testable service) andrealtimeClientGlobal.server.ts(configuration) in the webapp
Files:
apps/webapp/app/services/apiRateLimit.server.ts
🧠 Learnings (6)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Access environment variables via `env` export from `apps/webapp/app/env.server.ts`, never use `process.env` directly
Applied to files:
apps/webapp/app/env.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp
Applied to files:
apps/webapp/app/env.server.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to apps/webapp/**/*.test.{ts,tsx} : For testable code in the webapp, never import env.server.ts in test files - pass configuration as options instead
Applied to files:
apps/webapp/app/env.server.ts
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.
Applied to files:
apps/webapp/app/env.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Applied to files:
apps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.
Applied to files:
apps/webapp/app/routes/admin._index.tsx
🧬 Code graph analysis (1)
apps/webapp/app/routes/api.v1.plain.customer-cards.ts (2)
apps/webapp/app/routes/admin._index.tsx (1)
action(68-77)packages/core/src/v3/apps/http.ts (1)
json(65-75)
⏰ 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: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: typecheck / typecheck
🔇 Additional comments (8)
apps/webapp/app/services/apiRateLimit.server.ts (1)
49-55: LGTM — whitelist entry looks intentional.Assuming the Plain endpoint remains secret-authenticated, bypassing rate limiting here seems fine.
apps/webapp/app/env.server.ts (1)
109-111: LGTM — optional Plain secret wired into env schema.apps/webapp/app/routes/admin._index.tsx (3)
23-25: LGTM — session helpers swap is straightforward.
68-77: LGTM — action now reuses the impersonation guard.
122-129: LGTM — explicit typing clarifies map iteration.apps/webapp/app/routes/api.v1.plain.customer-cards.ts (3)
9-22: LGTM — request schema is clear and scoped.
24-41: LGTM — shared-secret auth helper is concise.
72-113: LGTM — user lookup and email fallback are clear.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/webapp/app/routes/api.v1.plain.customer-cards.ts`:
- Around line 285-314: The projectCount shown in the orgComponents rendering is
based on membership.organization.projects which is limited to the 10 most recent
items, so update the label generation (in the orgComponents flatMap where
projectCount is computed and passed into uiComponent.text inside asideContent)
to indicate these are "recent" projects—e.g., change the text interpolation that
currently produces `${projectCount} project${projectCount !== 1 ? "s" : ""}` to
a phrasing like `${projectCount} recent project${projectCount !== 1 ? "s" : ""}`
so the UI reflects the upstream take: 10 restriction.
- Around line 11-24: The PlainCustomerCardRequestSchema currently allows
requests where both customer.email and customer.externalId are missing; update
PlainCustomerCardRequestSchema to enforce a stable identifier by adding a
refinement (e.g., .refine or .superRefine on the schema) that checks
customer.email || customer.externalId is present and returns a clear validation
error message when neither exists; target the PlainCustomerCardRequestSchema
definition so validation fails fast instead of returning empty cards.
🧹 Nitpick comments (2)
apps/webapp/app/services/impersonation.server.ts (1)
50-71: Consider a dedicated secret for impersonation tokens.Using the session cookie secret for JWT signing couples two concerns and makes rotation more fragile. A separate secret (or derived key) reduces blast radius.
♻️ Suggested adjustment
-function getImpersonationTokenSecret(): Uint8Array { - return new TextEncoder().encode(env.SESSION_SECRET); -} +function getImpersonationTokenSecret(): Uint8Array { + const secret = env.IMPERSONATION_TOKEN_SECRET ?? env.SESSION_SECRET; + return new TextEncoder().encode(secret); +}(Also add
IMPERSONATION_TOKEN_SECRETto the env schema.)apps/webapp/app/routes/admin._index.tsx (1)
100-100: Prefer typed loader data overas any.The
as anycast and element casts hide type drift. Consider tightening the loader data type souseTypedLoaderDatacan infer safely. Please verify the recommended typing approach withremix-typedjson/Remix docs.♻️ Possible direction
-import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/server-runtime"; +import type { ActionFunctionArgs, LoaderFunctionArgs, SerializeFrom } from "@remix-run/server-runtime"; @@ export default function AdminDashboardRoute() { const user = useUser(); - const { users, filters, page, pageCount } = useTypedLoaderData<typeof loader>() as any; + type LoaderData = SerializeFrom<typeof loader>; + const { users, filters, page, pageCount } = useTypedLoaderData<LoaderData>(); @@ - users.map((user: (typeof users)[0]) => { + users.map((user) => { @@ - {user.orgMemberships.map((org: (typeof user.orgMemberships)[0]) => ( + {user.orgMemberships.map((org) => (Also applies to: 141-148
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.tsapps/webapp/app/services/impersonation.server.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
**/*.{ts,tsx}: Always import tasks from@trigger.dev/sdk, never use@trigger.dev/sdk/v3or deprecatedclient.defineJobpattern
Every Trigger.dev task must be exported and have a uniqueidproperty with no timeouts in the run function
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Import from
@trigger.dev/coreusing subpaths only, never import from root
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
apps/webapp/app/services/**/*.server.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Separate testable services from configuration files; follow the pattern of
realtimeClient.server.ts(testable service) andrealtimeClientGlobal.server.ts(configuration) in the webapp
Files:
apps/webapp/app/services/impersonation.server.ts
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webappAccess environment variables via
envexport fromapps/webapp/app/env.server.ts, never useprocess.envdirectly
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/api.v1.plain.customer-cards.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
apps/webapp/app/services/impersonation.server.tsapps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
🧠 Learnings (17)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Applied to files:
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Generate example payloads for tasks when possible
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-09-03T14:35:52.384Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2464
File: apps/webapp/app/utils/pathBuilder.ts:144-146
Timestamp: 2025-09-03T14:35:52.384Z
Learning: In the trigger.dev codebase, organization slugs are safe for URL query parameters and don't require URL encoding, as confirmed by the maintainer in apps/webapp/app/utils/pathBuilder.ts.
Applied to files:
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `idempotencyKeys.create()` to create idempotency keys for preventing duplicate task executions
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Scope idempotency keys globally or to current run using the scope parameter
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp
Applied to files:
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: The webapp at apps/webapp is a Remix 2.1 application using Node.js v20
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-26T14:40:07.146Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2710
File: packages/schema-to-json/package.json:0-0
Timestamp: 2025-11-26T14:40:07.146Z
Learning: Node.js 24+ has native TypeScript support and can execute .ts files directly without tsx or ts-node for scripts that use only erasable TypeScript syntax (type annotations, interfaces, etc.). The trigger.dev repository uses Node.js 24.11.1+ and scripts like updateVersion.ts can be run with `node` instead of `tsx`.
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Access environment variables via `env` export from `apps/webapp/app/env.server.ts`, never use `process.env` directly
Applied to files:
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path
Applied to files:
apps/webapp/app/routes/admin._index.tsxapps/webapp/app/routes/api.v1.plain.customer-cards.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/services/**/*.server.{ts,tsx} : Separate testable services from configuration files; follow the pattern of `realtimeClient.server.ts` (testable service) and `realtimeClientGlobal.server.ts` (configuration) in the webapp
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure OpenTelemetry instrumentations and exporters in trigger.config.ts for enhanced logging
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-09-02T11:27:36.336Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2463
File: apps/webapp/app/routes/_app.github.callback/route.tsx:33-44
Timestamp: 2025-09-02T11:27:36.336Z
Learning: In the GitHub App installation callback flow in apps/webapp/app/routes/_app.github.callback/route.tsx, the install session cookie is not cleared after use due to interface limitations with redirectWithSuccessMessage/redirectWithErrorMessage not supporting custom headers. The maintainer accepts this design as the 1-hour cookie expiration provides sufficient protection against replay attacks.
Applied to files:
apps/webapp/app/routes/admin._index.tsx
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.
Applied to files:
apps/webapp/app/routes/admin._index.tsx
🧬 Code graph analysis (3)
apps/webapp/app/services/impersonation.server.ts (1)
internal-packages/redis/src/index.ts (1)
createRedisClient(16-42)
apps/webapp/app/routes/admin._index.tsx (3)
apps/webapp/app/services/session.server.ts (1)
requireUser(39-62)apps/webapp/app/models/admin.server.ts (1)
redirectWithImpersonation(215-242)apps/webapp/app/services/impersonation.server.ts (1)
validateAndConsumeImpersonationToken(94-134)
apps/webapp/app/routes/api.v1.plain.customer-cards.ts (4)
apps/webapp/app/routes/admin._index.tsx (1)
action(87-96)packages/core/src/v3/apps/http.ts (1)
json(65-75)internal-packages/tsql/src/query/errors.ts (1)
SyntaxError(39-41)apps/webapp/app/services/impersonation.server.ts (1)
generateImpersonationToken(76-89)
⏰ 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). (20)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
🔇 Additional comments (7)
apps/webapp/app/services/impersonation.server.ts (3)
2-6: No review notes for import additions.
76-88: Token issuance looks solid.Short TTL plus issuer/audience claims make intent clear and consistent.
94-133: Replay protection via Redis NX/EX is a good fit.Atomic consume + TTL provides clean one-time semantics.
apps/webapp/app/routes/admin._index.tsx (2)
24-29: No review notes for import additions.
38-49: Nice consolidation of impersonation handling.Centralizing the admin check keeps loader/action behavior aligned.
Also applies to: 95-95
apps/webapp/app/routes/api.v1.plain.customer-cards.ts (2)
27-50: Auth guard and JSON parsing handling look good.Clear method gate + constant-time compare and 400 on malformed JSON are solid.
Also applies to: 52-56, 66-80
161-256: Card payload composition for account-details/projects is clear.Structure and component usage are consistent and easy to follow.
Also applies to: 345-426
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Uh oh!
There was an error while loading. Please reload this page.