Skip to content

Conversation

@rudransh-shrivastava
Copy link
Collaborator

Resolves #1600

Proposed change

Configure graphql-codegen using this documentation
The codegen generates types and validates the queries.

Use pnpm run graphql-codegen to run the codegen.

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

Summary by CodeRabbit

  • Chores

    • Added automated GraphQL type generation and integrated it into frontend checks.
    • Updated scripts and Makefile to run codegen.
    • Adjusted lint/format and pre-commit settings to ignore generated files.
  • Refactor

    • Standardized GraphQL operation names across queries.
  • Data/Queries

    • My Programs data now includes userRole.
    • Minor field adjustments in module mentors and logout response (removal of an unused id).

Walkthrough

Adds GraphQL Codegen tooling and CI hooks, ignores generated types from linters/formatters, renames many GraphQL operation names, updates several queries’ selections (including removal of one query and small field edits), and integrates codegen into frontend Makefile and package scripts.

Changes

Cohort / File(s) Summary of changes
Tooling ignores
frontend/.prettierignore, frontend/eslint.config.mjs, .pre-commit-config.yaml
Added ignore pattern src/types/__generated__/**/* to Prettier, ESLint ignores, and pre-commit EOF fixer exclude; ESLint ignores reformatted to multi-line.
GraphQL codegen setup
frontend/graphql-codegen.ts, frontend/package.json, frontend/Makefile
New async GraphQL Codegen config file that fetches a CSRF token and sets schema/docs/outputs; added graphql-codegen script and codegen-related dependencies; added graphql-codegen and generate-graphql-types Makefile targets and added codegen step to check-frontend.
Operation name renames (no export signature changes)
frontend/src/server/queries/chapterQueries.ts, .../committeeQueries.ts, .../organizationQueries.ts, .../projectsHealthDashboardQueries.ts, .../repositoryQueries.ts, .../snapshotQueries.ts, .../userQueries.ts
Renamed GraphQL operation names inside gql documents (e.g., GetX → GetXData / GetXMetadata / GetX...); exported constants unchanged.
Query structural changes
frontend/src/server/queries/moduleQueries.ts, frontend/src/server/queries/programsQueries.ts, frontend/src/server/queries/authQueries.ts
modules: flattened mentor/githubUser fields to surface login and avatarUrl; programs: removed GET_PROGRAM_DATA export and added userRole to GET_MY_PROGRAMS result shape; auth: removed id from logout mutation selection.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Implement codegen schema validation (#1600) Codegen tooling and config were added and integrated, but no explicit "schema validation" step or validation logic is present in the config or Makefile; unclear if this satisfies the issue's validation requirement.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removed GET_PROGRAM_DATA export (frontend/src/server/queries/programsQueries.ts) Deleting a public query changes API surface and is unrelated to adding schema validation tooling.
Added userRole to GET_MY_PROGRAMS selection (frontend/src/server/queries/programsQueries.ts) Expands returned data shape; not necessary for implementing schema validation.
Modified mentor selection shape in GET_MODULES_BY_PROGRAM (frontend/src/server/queries/moduleQueries.ts) Changes returned field structure; unrelated to codegen/schema validation objective.

Possibly related PRs

Suggested reviewers

  • kasya
  • aramattamara
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rudransh-shrivastava
Copy link
Collaborator Author

rudransh-shrivastava commented Aug 29, 2025

Had to violate the DRY principle in graphql-codegen.ts for fetching csrf token.
I tried using fetchCsrfTokenServer at frontend/src/server/fetchCsrfTokenServer.ts. But this function gets the csrf url from environment variables. I will use the same script pnpm run graphql-codegen for both local and CI/CD runs.

This made it tricky to use that function and would make the code more complicated as node does not load environment variables from a .env file directly.


export const GET_PROGRAM_DATA = gql`
query GetPrograms($page: Int!, $search: String, $mentorUsername: String) {
allPrograms(page: $page, search: $search, mentorUsername: $mentorUsername) {
Copy link
Collaborator Author

@rudransh-shrivastava rudransh-shrivastava Aug 29, 2025

Choose a reason for hiding this comment

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

This was a query was not being used anywhere. It had syntax errors that were never caught due to it not being used.
The error:

Error 1: Cannot query field "allPrograms" on type "Query". Did you mean "myPrograms" or "getProgram"?
      at /home/psyduck/repos/Nest/frontend/src/server/queries/programsQueries.ts:3:5

}
login
avatarUrl
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This query was not being used anywhere. Fixed syntax errors to run codegen. I can remove it entirely if required.
Error:

Error 0: Cannot query field "githubUser" on type "MentorNode".
      at /home/psyduck/repos/Nest/frontend/src/server/queries/moduleQueries.ts:15:9

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (6)
frontend/eslint.config.mjs (1)

30-39: Use a recursive ignore to be unambiguous.

Minor: make the ignore explicitly recursive to avoid edge cases with some glob engines.

-      'src/types/__generated__',
+      'src/types/__generated__/**',
frontend/src/server/queries/moduleQueries.ts (1)

15-19: Align mentor field selections or extract a shared fragment.

Inconsistency: GET_MODULES_BY_PROGRAM selects { id, login, avatarUrl } while GET_MODULE_BY_ID selects { login, name, avatarUrl }. Prefer one canonical shape or a fragment to keep types consistent.

Option A — add name to list view for parity:

       mentors {
-        id
-        login
-        avatarUrl
+        id
+        login
+        name
+        avatarUrl
       }

Option B — define a fragment for reuse (example):

fragment MentorSummary on Mentor {
  login
  name
  avatarUrl
}

# then use:
mentors { ...MentorSummary }

I can open a follow-up PR to introduce shared fragments if helpful.

Also applies to: 36-40

frontend/src/server/queries/repositoryQueries.ts (1)

3-85: Reduce duplication with fragments (optional).

Author fields repeat across issues, releases, milestones, and PRs. Consider a shared fragment for consistency and smaller diffs when fields evolve.

Example (apply in this file and reuse elsewhere):

import { gql } from '@apollo/client'

const USER_BASIC_FIELDS = gql`
  fragment UserBasicFields on User {
    avatarUrl
    login
    name
  }
`

Then replace repeated author selections with ...UserBasicFields.

frontend/graphql-codegen.ts (3)

3-5: Type the CSRF cache.

Avoid implicit any.

-let csrfToken = null
+let csrfToken: string | null = null

6-22: Don’t duplicate CSRF fetch logic (optional).

There’s an existing server util (src/server/fetchCsrfTokenServer.ts). Prefer importing/reusing to avoid drift, or centralize both behind a shared helper.


25-25: Exclude generated types from document scanning.

Prevents unnecessary parsing and speeds up codegen.

-  documents: ['src/**/*.{ts,tsx}'],
+  documents: ['src/**/*.{ts,tsx}', '!src/types/__generated__/**'],

Also applies to: 27-27

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2f2e260 and 5c8b6e1.

⛔ Files ignored due to path filters (2)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/src/types/__generated__/graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (13)
  • frontend/.prettierignore (1 hunks)
  • frontend/eslint.config.mjs (1 hunks)
  • frontend/graphql-codegen.ts (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/server/queries/chapterQueries.ts (2 hunks)
  • frontend/src/server/queries/committeeQueries.ts (2 hunks)
  • frontend/src/server/queries/moduleQueries.ts (3 hunks)
  • frontend/src/server/queries/organizationQueries.ts (2 hunks)
  • frontend/src/server/queries/programsQueries.ts (1 hunks)
  • frontend/src/server/queries/projectsHealthDashboardQueries.ts (1 hunks)
  • frontend/src/server/queries/repositoryQueries.ts (2 hunks)
  • frontend/src/server/queries/snapshotQueries.ts (1 hunks)
  • frontend/src/server/queries/userQueries.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/graphql-codegen.ts (1)
frontend/src/server/fetchCsrfTokenServer.ts (1)
  • fetchCsrfTokenServer (1-13)
🔇 Additional comments (15)
frontend/src/server/queries/committeeQueries.ts (1)

4-4: Consistent operation names — good; check for duplicates.

These renames align with codegen. Verify uniqueness across the codebase to prevent duplicate interface/type names.

Use the duplicate-name scan provided in my earlier comment; it applies here too.

Also applies to: 28-28

frontend/src/server/queries/snapshotQueries.ts (1)

58-58: Rename to Metadata-suffixed op — good; confirm uniqueness.

Same duplicate-name caution applies; ensure no other GetSnapshotDetailsMetadata exists.

Use the duplicate-name scan script from the first GraphQL comment.

frontend/src/server/queries/userQueries.ts (1)

4-4: The script ran without errors; please provide its output so I can inspect the queries.

frontend/src/server/queries/chapterQueries.ts (2)

4-4: PascalCase operation names are consistent and clear.

Renaming to GetChapterData/GetChapterMetadata improves consistency for codegen and tooling.

Also applies to: 29-29


4-4: No downstream dependencies on old operation names detected.

frontend/eslint.config.mjs (1)

30-39: Ignoring generated types directory is correct.

Excluding src/types/generated from lint keeps CI noise down and speeds linting.

frontend/src/server/queries/organizationQueries.ts (2)

4-4: Operation name standardization looks good.

GetOrganizationData/GetOrganizationMetadata align with codegen conventions.

Also applies to: 98-98


4-4: Validate external monitoring and persisted query implications
Scan found no persisted‐query hints or operationName references in the codebase. Ensure any external alerting/analytics dashboards or persisted-query configurations referencing GetOrganizationData or GetOrganizationMetadata are updated to match these changes.

frontend/package.json (1)

72-74: Compatibility confirmed: @graphql-codegen/cli@^5, typescript@^4, and typescript-operations@^4 support graphql@^16. No changes required.

frontend/src/server/queries/moduleQueries.ts (2)

4-4: Operation name updates LGTM.

Consistent GetX naming aids codegen type exports and DX.

Also applies to: 25-25, 46-46


15-19: Drop githubUser wrapper warning
Search across .ts/.tsx files found zero references to .githubUser, and all mentors projections use flat fields (login, name, etc.), so no consumers expect the old nested shape.

Likely an incorrect or invalid review comment.

frontend/src/server/queries/repositoryQueries.ts (2)

88-88: Operation rename verified: no occurrences of “GetRepository” remain in the frontend code.


4-4: No remaining references to GetRepository detected. Rename appears safe.

frontend/graphql-codegen.ts (2)

35-42: skipTypeNameForRoot is a valid option
skipTypeNameForRoot: true is supported by the @graphql-codegen/typescript-operations plugin to omit __typename on root operation types; no changes needed.

Likely an incorrect or invalid review comment.


49-56: Run GraphQL Codegen in the correct workspace
The pnpm error indicates no package.json at the repo root—please rerun the codegen command from the frontend package (e.g. cd frontend && pnpm graphql-codegen --config graphql-codegen.ts --verbose) or use pnpm --prefix frontend graphql-codegen … to verify the updated async export and added Origin header work as intended.

"dev": "next dev --port 3000",
"format": "prettier --log-level warn --write .",
"format:check": "prettier --check .",
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 29, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Generate types automatically during builds.

Prevent stale/missing types by invoking codegen before build.

   "scripts": {
-    "build": "next build",
+    "build": "pnpm run graphql-codegen && next build",
     "build:turbo": "next build --turbo",
@@
-    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
+    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
+    "predev": "pnpm run graphql-codegen",
+    "pretest:unit": "pnpm run graphql-codegen",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
"scripts": {
"build": "pnpm run graphql-codegen && next build",
"build:turbo": "next build --turbo",
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
"predev": "pnpm run graphql-codegen",
"pretest:unit": "pnpm run graphql-codegen",
}
🤖 Prompt for AI Agents
In frontend/package.json around line 11, the project invokes graphql-codegen via
a standalone script but does not ensure types are generated before building;
update package.json scripts to run codegen automatically before build—either add
a "prebuild" script that runs "graphql-codegen --config graphql-codegen.ts" or
prepend the build script with the codegen command (e.g., "graphql-codegen
--config graphql-codegen.ts && <existing build command>") so types are always
generated during CI/local builds.

Copy link
Collaborator Author

@rudransh-shrivastava rudransh-shrivastava Aug 30, 2025

Choose a reason for hiding this comment

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

how is this possible if we run backend separately? if we invoke codegen before build it may fail as backend may or may not be available. Codegen requires a server to query the GraphQL endpoint

Copy link
Contributor

Choose a reason for hiding this comment

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

@rudransh-shrivastava You're absolutely right! That's a critical oversight on my part. Running codegen during build would indeed fail when the backend isn't available, which is common in CI/CD pipelines or local development scenarios.

Here are better approaches to handle this:

Option 1: Use a static schema file

// In graphql-codegen.ts, replace the schema URL with a local file
- schema: `${PUBLIC_API_URL}/graphql/`,
+ schema: './schema.graphql',

Option 2: Make codegen conditional

{
  "scripts": {
    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
    "graphql-codegen:safe": "graphql-codegen --config graphql-codegen.ts || echo 'Codegen skipped - server unavailable'",
    "build": "pnpm run graphql-codegen:safe && next build"
  }
}

Option 3: Separate CI step
Run codegen only when backend is available (e.g., in a specific CI job) and commit the generated types.

Given that you've already committed the generated types, Option 3 seems to align with your current approach. The types would be generated when the backend is available and committed to the repo.

What's your preference for handling this in your deployment pipeline?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. to get a schema.graphql file, I run into the same problem. I need a backend server to generate that file.

I would like to know if there's a way to run graphql-codegen after backend is available? This is for local development purposes. I am assuming that for CI jobs -- all generated files are already present.

Copy link
Contributor

Choose a reason for hiding this comment

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

  • No changes needed to your current graphql-codegen.ts configuration
  • Generated files remain committed for CI/CD as you intended

The first solution with wait-on + concurrently is probably your best bet since it handles the server dependency gracefully and provides a smooth development experience.


export const GET_PROGRAM_ADMIN_DETAILS = gql`
query GetProgramDetails($programKey: String!) {
query GetProgramAdminDetails($programKey: String!) {
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 29, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Operation rename: verify no dependencies on old operation name (GetProgramDetails).

Check persisted queries, allowlists, dashboards, and tests that might assert on operationName.


🏁 Script executed:

#!/bin/bash
rg -nP -C2 --glob 'frontend/**' $'\\bquery\\s+GetProgramDetails\\b|operationName\\s*[:=]\\s*[\'"]GetProgramDetails[\'"]'

Length of output: 512


Update GraphQL operation rename and dependencies
Old operation GetProgramDetails and its constant GET_PROGRAM_DETAILS remain in frontend/src/server/queries/programsQueries.ts (lines 21–24); rename or remove them to match the new GetProgramAdminDetails operation. Then search persisted queries, allowlists, dashboards, and tests for any GetProgramDetails occurrences to ensure no breaking references.

🤖 Prompt for AI Agents
In frontend/src/server/queries/programsQueries.ts around lines 21–24 and 81, the
code still defines the old GraphQL operation/constant
GetProgramDetails/GET_PROGRAM_DETAILS while the operation has been renamed to
GetProgramAdminDetails; update or remove the old constant so the exported query
name matches the new operation (rename GET_PROGRAM_DETAILS to
GET_PROGRAM_ADMIN_DETAILS or remove the stale constant), update any local
imports/usages in this file to reference the new name, then run a repo-wide
search for "GetProgramDetails" and "GET_PROGRAM_DETAILS" and update persisted
queries, allowlists, dashboards, and tests to reference
"GetProgramAdminDetails"/new constant to prevent broken references.

Copy link
Collaborator Author

@rudransh-shrivastava rudransh-shrivastava Aug 31, 2025

Choose a reason for hiding this comment

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

This query is being used in places. we cannot remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

@rudransh-shrivastava You're absolutely right, and I apologize for the confusion. I can see now that GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two distinct queries serving different purposes:

  1. GET_PROGRAM_DETAILS - fetches comprehensive program information (status, menteesLimit, experienceLevels, domains, tags, etc.)
  2. GET_PROGRAM_ADMIN_DETAILS - fetches only admin-related program details (id, key, name, and admins)

The rename in the diff only affected the operation name within GET_PROGRAM_ADMIN_DETAILS from "GetProgramDetails" to "GetProgramAdminDetails", which makes sense to avoid naming conflicts. The existing GET_PROGRAM_DETAILS query should remain as it serves a different use case.

Let me verify where GET_PROGRAM_DETAILS is being used to better understand its importance in the codebase.


🏁 Script executed:

#!/bin/bash
# Search for usage of GET_PROGRAM_DETAILS in the codebase
rg -nP --type=ts --type=tsx -C2 'GET_PROGRAM_DETAILS' frontend/

Length of output: 91


@rudransh-shrivastava Thank you for the clarification. You're correct that GET_PROGRAM_DETAILS is being used elsewhere and cannot be removed. The rename operation only affected the GET_PROGRAM_ADMIN_DETAILS query's operation name, which is the appropriate approach to avoid naming conflicts between the two distinct queries.

The GraphQL codegen integration correctly handles having multiple queries with different purposes, and maintaining both queries ensures backward compatibility with existing components that depend on GET_PROGRAM_DETAILS.

  (\   /)
 ( ._.)
o_(")(")  *thoughtful rabbit after learning something new*

🏁 Script executed:

#!/bin/bash
# Search for usage of GET_PROGRAM_DETAILS in the codebase (corrected file types)
rg -nP --type=ts -g '*.tsx' -C2 'GET_PROGRAM_DETAILS' frontend/

Length of output: 1202


🏁 Script executed:

#!/bin/bash
# Alternative search without file type restrictions
rg -nP -C2 'GET_PROGRAM_DETAILS' frontend/

Length of output: 1569


Perfect! The search results confirm exactly what you said. GET_PROGRAM_DETAILS is actively being used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for the program edit functionality (imported on line 10 and used in a useQuery hook on line 26).

This makes complete sense - the program edit page needs the comprehensive program information that GET_PROGRAM_DETAILS provides (status, menteesLimit, experienceLevels, domains, tags, etc.), while GET_PROGRAM_ADMIN_DETAILS serves a different, more limited purpose.

Thank you for the correction! The GraphQL codegen integration and the operation name rename for GET_PROGRAM_ADMIN_DETAILS (from "GetProgramDetails" to "GetProgramAdminDetails") was the right approach to avoid naming conflicts while preserving the existing functionality.


✏️ Learnings added
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.832Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details.

Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.832Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details. These queries cannot be removed or merged as they serve different use cases in the application.

Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.833Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS is actively used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for program editing functionality and cannot be removed. It serves a different purpose than GET_PROGRAM_ADMIN_DETAILS, providing comprehensive program information needed for editing.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@rudransh-shrivastava
Copy link
Collaborator Author

rudransh-shrivastava commented Aug 29, 2025

I'm yet to integrate this in the CI/CD pipeline
Edit: its difficult as we discussed, skipping this.

@rudransh-shrivastava
Copy link
Collaborator Author

rudransh-shrivastava commented Aug 29, 2025

I will also add generated types to .gitignore as per coderabbit's suggestion
Edit: Not required anymore, we are committing types

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
frontend/graphql-codegen.ts (1)

3-3: Load envs via dotenv or fail fast if PUBLIC_API_URL isn’t set (DRY + CI).

This removes the need for duplicated CSRF logic elsewhere and avoids surprising localhost defaults in CI.

Option A (simple): add at top of file:

+import 'dotenv/config'

Option B (strict): replace the fallback with a hard error:

-const PUBLIC_API_URL = process.env.PUBLIC_API_URL || 'http://localhost:8000'
+const PUBLIC_API_URL = process.env.PUBLIC_API_URL
+if (!PUBLIC_API_URL) throw new Error('PUBLIC_API_URL is required for graphql-codegen')
🧹 Nitpick comments (3)
frontend/graphql-codegen.ts (3)

18-18: Exclude generated dir from documents to avoid accidental reprocessing.

-    documents: ['src/**/*.{ts,tsx}'],
+    documents: ['src/**/*.{ts,tsx}', '!src/types/__generated__/**'],

36-37: Consider generating TypedDocumentNode for safer usage with Apollo.

Adds strong typing for the actual gql documents; improves DX and narrows runtime mistakes.

-        plugins: ['typescript', 'typescript-operations'],
+        plugins: ['typescript', 'typescript-operations', 'typed-document-node'],

Follow-up: add devDependency @graphql-codegen/typed-document-node.


17-38: Pipeline strategy to decouple codegen from a live backend.

Prefer using a schema artifact to make CI deterministic and faster:

  • Backend job exports schema (SDL or introspection JSON) as an artifact.
  • Frontend job consumes it: schema: './schema.graphql' (or schema.json) without any CSRF/network.

If desired, I can draft the CI steps and modify this config to accept a local schema path with a simple env flag.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5c8b6e1 and 55f86cc.

📒 Files selected for processing (1)
  • frontend/graphql-codegen.ts (1 hunks)
🔇 Additional comments (2)
frontend/graphql-codegen.ts (2)

21-35: Config defaults look solid.

avoidOptionals, defaultScalarType, and typename settings align with Apollo usage.


39-42: LGTM on these flags.

ignoreNoDocuments and overwrite are appropriate here.

Comment on lines 5 to 10
const createCodegenConfig = async (): Promise<CodegenConfig> => {
const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
credentials: 'include',
method: 'GET',
})

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add timeout; drop ineffective credentials: 'include'.

Node’s fetch has no cookie jar; credentials is no-op here. Add an AbortController to avoid hanging if /csrf/ is slow/down.

-  const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
-    credentials: 'include',
-    method: 'GET',
-  })
+  const controller = new AbortController()
+  const timeout = setTimeout(() => controller.abort(), 5000)
+  const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
+    method: 'GET',
+    signal: controller.signal,
+  })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const createCodegenConfig = async (): Promise<CodegenConfig> => {
const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
credentials: 'include',
method: 'GET',
})
const createCodegenConfig = async (): Promise<CodegenConfig> => {
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 5000)
const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
method: 'GET',
signal: controller.signal,
})
🤖 Prompt for AI Agents
In frontend/graphql-codegen.ts around lines 5 to 10, the fetch call to
`${PUBLIC_API_URL}/csrf/` incorrectly includes credentials: 'include' (no-op in
Node) and lacks a timeout, risking hanging; remove the credentials option,
create an AbortController, pass its signal to fetch, set a short timeout (e.g.,
5s) that calls controller.abort(), and ensure you clear the timeout after fetch
completes and properly catch/handle the abort error so the function fails fast
when /csrf/ is slow or down.

Comment on lines 11 to 16
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
const data = await response.json()
const csrfToken = data.csrftoken

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden CSRF extraction and clear timeout.

Be resilient to different payload shapes and fall back to Set-Cookie. Fail fast if still missing.

-  if (!response.ok) {
+  clearTimeout(timeout)
+  if (!response.ok) {
     throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
   }
-  const data = await response.json()
-  const csrfToken = data.csrftoken
+  type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
+  const data = (await response.json().catch(() => ({}))) as CsrfResponse
+  let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
+  if (!csrfToken) {
+    const setCookie = response.headers.get('set-cookie') ?? ''
+    const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
+    if (m) csrfToken = m[1]
+  }
+  if (!csrfToken) {
+    throw new Error('Failed to extract CSRF token from CSRF endpoint response')
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
const data = await response.json()
const csrfToken = data.csrftoken
clearTimeout(timeout)
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
const data = (await response.json().catch(() => ({}))) as CsrfResponse
let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
if (!csrfToken) {
const setCookie = response.headers.get('set-cookie') ?? ''
const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
if (m) csrfToken = m[1]
}
if (!csrfToken) {
throw new Error('Failed to extract CSRF token from CSRF endpoint response')
}
🤖 Prompt for AI Agents
In frontend/graphql-codegen.ts around lines 11 to 16, the code assumes the CSRF
token is at data.csrftoken and doesn't clear the fetch timeout or handle
alternate payloads; update the logic to: parse JSON safely (guarding for
data.csrftoken, data.csrfToken, data.token, or nested properties), if JSON
parsing fails or none of those fields exist, check the
response.headers.get('set-cookie') (or other cookie headers) for a csrf token
fallback, and ensure any timeout/abort controller is cleared or aborted cleanup
is performed; if after these attempts the token is still missing, throw an
explicit error immediately to fail fast.

Comment on lines 43 to 49
[`${PUBLIC_API_URL}/graphql/`]: {
headers: {
Cookie: `csrftoken=${csrfToken}`,
'x-csrftoken': `${csrfToken}`,
},
},
},
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add Referer and normalize CSRF header casing (Django requires it over HTTPS).

Without a Referer that matches the target origin, Django will reject POST introspection requests even with a valid CSRF token. Also prefer the conventional header casing.

Apply:

       headers: {
-          Cookie: `csrftoken=${csrfToken}`,
-          'x-csrftoken': `${csrfToken}`,
+          Cookie: `csrftoken=${csrfToken}`,
+          'X-CSRFToken': csrfToken,
+          Referer: PUBLIC_API_URL,
       },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[`${PUBLIC_API_URL}/graphql/`]: {
headers: {
Cookie: `csrftoken=${csrfToken}`,
'x-csrftoken': `${csrfToken}`,
},
},
},
[`${PUBLIC_API_URL}/graphql/`]: {
headers: {
Cookie: `csrftoken=${csrfToken}`,
'X-CSRFToken': csrfToken,
Referer: PUBLIC_API_URL,
},
},
🤖 Prompt for AI Agents
In frontend/graphql-codegen.ts around lines 43 to 49, the request headers are
missing a Referer and use a nonstandard CSRF header casing; add a Referer header
that matches the target origin (e.g. PUBLIC_API_URL with trailing slash) and
change the header name from 'x-csrftoken' to the conventional 'X-CSRFToken' so
Django accepts POST introspection over HTTPS; keep the Cookie csrftoken as-is
and ensure the Referer value is exactly the API origin expected by Django.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

django does not reject them, it works fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

@rudransh-shrivastava Thank you for clarifying! I appreciate you testing this and confirming it works with your current Django configuration.

My suggestion was based on Django's default CSRF protection behavior, particularly for HTTPS environments where Django typically requires a Referer header that matches the target origin. However, since you've verified it works fine in your setup, it's likely that:

  1. Your Django configuration has appropriate CSRF settings for your use case
  2. The GraphQL introspection might be using GET requests rather than POST
  3. Your development/deployment environment doesn't trigger Django's stricter CSRF validation

Since you've confirmed the current implementation works, there's no need to make these changes. Thanks for the feedback!


✏️ Learnings added
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:0-0
Timestamp: 2025-08-31T13:48:09.785Z
Learning: In the OWASP/Nest project, Django's GraphQL endpoint accepts CSRF tokens via 'x-csrftoken' header (lowercase) without requiring a Referer header, working fine in their configuration for GraphQL codegen introspection.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
frontend/graphql-codegen.ts (3)

64-64: Replace top-level await with async default export

Top-level await is brittle across ESM/CJS and was reported as failing; GraphQL Codegen supports an async default export. Adopt the learned pattern.

-export default await createCodegenConfig()
+export default async function codegenConfig(): Promise<CodegenConfig> {
+  return createCodegenConfig()
+}

5-15: Fail fast and harden CSRF retrieval (timeout + robust parsing + fallback to Set-Cookie)

Prevents hangs, clears timeout, and avoids assuming a single JSON shape.

-const createCodegenConfig = async (): Promise<CodegenConfig> => {
-  const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
-    method: 'GET',
-  })
-
-  if (!response.ok) {
-    throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
-  }
-  const data = await response.json()
-  const csrfToken = data.csrftoken
+const createCodegenConfig = async (): Promise<CodegenConfig> => {
+  const controller = new AbortController()
+  const timeout = setTimeout(() => controller.abort(), 5000)
+  const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
+    method: 'GET',
+    signal: controller.signal,
+  })
+  clearTimeout(timeout)
+  if (!response.ok) {
+    throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
+  }
+  type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
+  const data = (await response.json().catch(() => ({}))) as CsrfResponse
+  let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
+  if (!csrfToken) {
+    const setCookie = response.headers.get('set-cookie') ?? ''
+    const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
+    if (m) csrfToken = m[1]
+  }
+  if (!csrfToken) {
+    throw new Error('Failed to extract CSRF token from CSRF endpoint response')
+  }

55-58: Add Referer for Django CSRF (HTTPS) and set Accept

Django’s CSRF checks require a matching Referer; Accept helps with content negotiation.

         headers: {
           Cookie: `csrftoken=${csrfToken}`,
           'X-CSRFToken': csrfToken,
+          Referer: PUBLIC_API_URL,
+          Accept: 'application/json',
         },
🧹 Nitpick comments (3)
frontend/graphql-codegen.ts (3)

17-17: Broaden documents globs; exclude generated output directory

Ensures .graphql/.gql files are picked up and avoids scanning generated files.

-    documents: ['src/**/*.{ts,tsx}'],
+    documents: ['src/**/*.{ts,tsx,graphql,gql}', '!src/types/__generated__/**'],

3-4: Normalize PUBLIC_API_URL to avoid accidental double slashes

Handles env values with a trailing slash.

-const PUBLIC_API_URL = process.env.PUBLIC_API_URL || 'http://localhost:8000'
+const PUBLIC_API_URL = (process.env.PUBLIC_API_URL || 'http://localhost:8000').replace(/\/+$/, '')

53-60: CI strategy: validate queries without committing generated files

Option A: commit schema (schema.graphql or schema.json) and generate types offline. Option B: spin up backend during CI and run codegen. Recommend adding a CI job.

Example (GitHub Actions step):

- name: Generate GraphQL types
  working-directory: frontend
  env:
    PUBLIC_API_URL: http://localhost:8000
  run: pnpm run graphql-codegen

If you choose to commit schema instead, add a scheduled job to refresh it and keep generated types out of git.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 55f86cc and 09b8ca5.

⛔ Files ignored due to path filters (18)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/src/types/__generated__/apiKeyQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/authQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/chapterQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/committeeQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/graphql.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/homeQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/mentorshipQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/moduleMutations.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/moduleQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/organizationQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/programsMutations.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/programsQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectsHealthDashboardQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/repositoryQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/snapshotQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/userQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (4)
  • frontend/.prettierignore (1 hunks)
  • frontend/eslint.config.mjs (1 hunks)
  • frontend/graphql-codegen.ts (1 hunks)
  • frontend/package.json (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/eslint.config.mjs
  • frontend/.prettierignore
  • frontend/package.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T12:52:32.180Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.

Applied to files:

  • frontend/graphql-codegen.ts
🔇 Additional comments (1)
frontend/graphql-codegen.ts (1)

1-1: Remove runtime verification comment
Node v24.3.0 confirms global fetch support and graphql-codegen --config graphql-codegen.ts correctly resolves async exports.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
frontend/graphql-codegen.ts (3)

6-8: Add timeout and harden CSRF extraction (fail fast, resilient to payload/cookie variants).

Prevent hangs with AbortController and clear the timer; parse JSON safely and fall back to Set-Cookie.

   const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
-    method: 'GET',
+    method: 'GET',
+    signal: controller.signal,
   })
 
+  clearTimeout(timeout)
   if (!response.ok) {
     throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
   }
-  const data = await response.json()
-  const csrfToken = data.csrftoken
+  type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
+  const data = (await response.json().catch(() => ({}))) as CsrfResponse
+  let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
+  if (!csrfToken) {
+    const setCookie = response.headers.get('set-cookie') ?? ''
+    const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
+    if (m) csrfToken = m[1]
+  }
+  if (!csrfToken) {
+    throw new Error('Failed to extract CSRF token from CSRF endpoint response')
+  }

Add the controller/timeout near the fetch:

+  const controller = new AbortController()
+  const timeout = setTimeout(() => controller.abort(), 5000)

Also applies to: 10-10, 13-15


5-5: Export an async function instead of an async IIFE (aligns with our learning).

Export the async function directly to avoid loader/TLA quirks and match GraphQL Codegen’s supported patterns. Applying your retrieved learning here.

-export default (async (): Promise<CodegenConfig> => {
+export default async function codegenConfig(): Promise<CodegenConfig> {
   // ...
-})()
+}

Also applies to: 62-62


54-58: Add Referer header; keep canonical CSRF header casing (Django HTTPS requirement).

Without a matching Referer, Django may reject POST introspection even with a valid token.

       headers: {
         Cookie: `csrftoken=${csrfToken}`,
         'X-CSRFToken': csrfToken,
+        Referer: PUBLIC_API_URL,
       },
🧹 Nitpick comments (3)
frontend/graphql-codegen.ts (3)

17-18: Broaden documents glob to include .graphql/.gql files.

Covers teams storing operations in SDL files alongside TS/TSX.

-    documents: ['src/**/*.{ts,tsx}', '!src/types/__generated__/**'],
+    documents: ['src/**/*.{ts,tsx,gql,graphql}', '!src/types/__generated__/**'],

37-44: Verify near-operation-file paths won’t scatter outputs under src/*/types/generated.

With folder set to '../../types/generated', outputs depend on each operation file’s depth (e.g., src/pages/foo → src/pages/types/generated). If your intent is a single central folder (src/types/generated), consider either:

  • Dropping near-operation-file and generating a single ops artifact, or
  • Keeping near-operation-file with a stable folder strategy per your directory layout.

If centralizing ops is desired, one option:

-      './src/': {
-        // near-operation-file ...
-      },
+      './src/types/__generated__/operations.ts': {
+        plugins: ['typescript-operations', 'typed-document-node'],
+        config: { importOperationTypesFrom: './graphql' }
+      },

Please run pnpm graphql-codegen locally and confirm generated paths land where you expect.


1-62: CI integration and offline schema strategy.

To meet “validate queries” reliably in CI:

  • Add a job that starts the backend before codegen, or
  • Commit an introspected schema (schema.graphql or schema.json) and point schema to that file; add a separate script to refresh it when backend changes.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 09b8ca5 and a239467.

📒 Files selected for processing (1)
  • frontend/graphql-codegen.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T12:52:32.180Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.

Applied to files:

  • frontend/graphql-codegen.ts
🔇 Additional comments (1)
frontend/graphql-codegen.ts (1)

20-37: Config choices look solid.

Good use of typed-document-node + operations, avoidOptionals, and typename settings. Order sensitivity called out—nice.

@github-actions github-actions bot added the ci label Aug 31, 2025
@rudransh-shrivastava
Copy link
Collaborator Author

rudransh-shrivastava commented Aug 31, 2025

@arkid15r Hey, this is ready for review.

I had to rename GraphQL queries for the codegen to work (unique names are required). I renamed them based on their variable name (GET_USER_DATA became GetUserData instead of GetUser). There is no official naming convention that I could find.

I say that we name the queries the same as their variable names but in PascalCase because these generated typed queries will be used instead of current query string variables (see Example code line 6).

I also think that we should refactor variable and query names as they are very inconsistent. The only constraint we have is that they should be unique.

Sources of documentation I followed:
Apollo GraphQL Codegen Guide
Official Codegen Presets Documentation

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
frontend/Makefile (3)

30-32: Add friendly pass/fail output to match format/lint targets.

Keep the UX consistent and surface failures clearly when running locally.

-graphql-codegen:
-	@cd frontend && pnpm run graphql-codegen
+graphql-codegen:
+	@(cd frontend && pnpm run graphql-codegen >/dev/null 2>&1 \
+	&& (printf "pnpm run graphql-codegen"; for i in $$(seq 1 44); do printf "."; done; printf "\033[30;42mPassed\033[0m\n") \
+	|| (printf "pnpm run graphql-codegen"; for i in $$(seq 1 44); do printf "."; done; printf "\033[37;41mFailed\033[0m\n" \
+		&& pnpm run graphql-codegen))

30-32: Consider gating check-frontend on codegen or add a “check-graphql-codegen” target.

Prevents stale types from slipping in before lint/tests.

If you want, I can propose a tiny Makefile snippet that runs codegen and fails on dirty git diff to ensure generated files are committed.


30-32: Allow environment override/documentation for PUBLIC_API_URL.

Codegen hits the live schema/CSRF endpoint; make it obvious how to point at non-default backends.

Examples:

  • Run against staging: PUBLIC_API_URL=https://staging.example.com make graphql-codegen
  • Optional: declare a default at the top of the Makefile:
    PUBLIC_API_URL ?= http://localhost:8000 (env can still override).
  • Optional: mark the new target as phony: .PHONY: graphql-codegen
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cb90877 and bcf8d26.

📒 Files selected for processing (1)
  • frontend/Makefile (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.
⏰ 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). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
frontend/src/server/queries/userQueries.ts (1)

4-12: Consider renaming $key → $login for clarity.

All three queries pass a user login; $login is clearer and avoids confusion with other “key” usages (programKey/moduleKey). Low-touch change; generated types will also read better (e.g., GetUserDataQueryVariables.login).

Also applies to: 15-87, 89-97

frontend/src/server/queries/moduleQueries.ts (2)

25-25: Rename operation to match actual selector (key, not id).

The operation is named GetModuleByID but takes moduleKey/programKey. Rename to avoid misleading generated type names.

Apply:

-export const GET_MODULE_BY_ID = gql`
-  query GetModuleByID($moduleKey: String!, $programKey: String!) {
+export const GET_MODULE_BY_ID = gql`
+  query GetModuleByKey($moduleKey: String!, $programKey: String!) {

Optional follow-up (breaking for importers): also rename the constant to keep names aligned.

-export const GET_MODULE_BY_ID = gql`
+export const GET_MODULE_BY_KEY = gql`

15-19: Deduplicate repeated user fields with a fragment (optional).

Admins/mentors repeat id/login/name/avatarUrl. A shared fragment will reduce drift and produce reusable fragment types from codegen.

Also applies to: 36-41, 50-55, 70-74

frontend/src/server/queries/programsQueries.ts (1)

84-97: Optional: extract admin user fields into a shared fragment.

id/login/name/avatarUrl repeats across program queries; a fragment will reduce duplication and help codegen produce consistent types.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bcf8d26 and 4babd73.

📒 Files selected for processing (9)
  • frontend/src/server/queries/chapterQueries.ts (2 hunks)
  • frontend/src/server/queries/committeeQueries.ts (2 hunks)
  • frontend/src/server/queries/moduleQueries.ts (3 hunks)
  • frontend/src/server/queries/organizationQueries.ts (2 hunks)
  • frontend/src/server/queries/programsQueries.ts (1 hunks)
  • frontend/src/server/queries/projectsHealthDashboardQueries.ts (2 hunks)
  • frontend/src/server/queries/repositoryQueries.ts (2 hunks)
  • frontend/src/server/queries/snapshotQueries.ts (1 hunks)
  • frontend/src/server/queries/userQueries.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • frontend/src/server/queries/snapshotQueries.ts
  • frontend/src/server/queries/repositoryQueries.ts
  • frontend/src/server/queries/organizationQueries.ts
  • frontend/src/server/queries/committeeQueries.ts
  • frontend/src/server/queries/projectsHealthDashboardQueries.ts
  • frontend/src/server/queries/chapterQueries.ts
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.
📚 Learning: 2025-08-31T13:47:15.832Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.832Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details. These queries cannot be removed or merged as they serve different use cases in the application.

Applied to files:

  • frontend/src/server/queries/programsQueries.ts
  • frontend/src/server/queries/moduleQueries.ts
📚 Learning: 2025-08-31T13:47:15.833Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.833Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS is actively used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for program editing functionality and cannot be removed. It serves a different purpose than GET_PROGRAM_ADMIN_DETAILS, providing comprehensive program information needed for editing.

Applied to files:

  • frontend/src/server/queries/programsQueries.ts
  • frontend/src/server/queries/moduleQueries.ts
📚 Learning: 2025-08-31T13:47:15.832Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.832Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details.

Applied to files:

  • frontend/src/server/queries/programsQueries.ts
  • frontend/src/server/queries/moduleQueries.ts
⏰ 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). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (6)
frontend/src/server/queries/userQueries.ts (1)

4-4: Approve operation-name rename
Ran a workspace search for "GetUser" references; none found—no dashboards or persisted-query allowlists require updates.

frontend/src/server/queries/moduleQueries.ts (4)

4-4: Unique operation name: LGTM.

This aligns with codegen’s uniqueness requirement.


17-19: Schema fix for mentors: LGTM.

Switching from the non-existent githubUser nesting to direct fields resolves the reported codegen error.


47-47: Rename to GetProgramAdminsAndModules: LGTM.

Clearer intent and unique for codegen.


4-4: No external dependencies on old operation names found.

frontend/src/server/queries/programsQueries.ts (1)

84-84: Rename to GetProgramAdminDetails: LGTM.

Keeps it distinct from GET_PROGRAM_DETAILS (different purpose) and avoids name clashes in generated types.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Looks good, let's improve the workflow a bit:

- name: Run pre-commit
env:
SKIP: graphql-codegen
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should probably be part of make check target if you skip it here.
Also this way we'll avoid adding local pre-commit hook

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've made this change. Thank you

"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^3.0.1",
"@graphql-typed-document-node/core": "^3.2.0",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does apollo pick up the generated types automagically based on the location?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, We need to import the types in each file where useQuery hook is used.
Example

Is it okay if I refactor all this in a different PR? I will need to update the tests too. I believe this refactor should complete the apollo migration.

For now, the generated files are unused.

It's recommended by apollo to separate out queries (one generated file for each query/mutation file) for larger applications. If we don't do this, all the queries and mutation are generated in the graphql.ts file.

@github-actions github-actions bot removed the ci label Sep 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
.pre-commit-config.yaml (1)

67-67: Anchor the exclude regex so all generated files are skipped.

Current pattern may not exclude nested files reliably. Use an anchored directory regex to avoid the hook touching generated outputs.

-        exclude: frontend/src/types/__generated__
+        exclude: ^frontend/src/types/__generated__/
frontend/Makefile (3)

5-6: Run codegen before lint to avoid “module not found”/type-resolver hiccups on clean clones.

If eslint uses type-aware rules, missing generated types can cause false negatives. Safer to generate first, then lint.

 check-frontend: \
 	format-frontend-code \
-	lint-frontend-code \
-	generate-graphql-types
+	generate-graphql-types \
+	lint-frontend-code

31-33: Minor: keep subshell style consistent with other targets.

Other targets use (cd … && …). Align for readability.

-graphql-codegen:
-	@cd frontend && pnpm run graphql-codegen
+graphql-codegen:
+	@(cd frontend && pnpm run graphql-codegen)

Additionally, declare new targets as phony to avoid filename collisions:

+.PHONY: graphql-codegen generate-graphql-types

46-51: Good UX: quiet run + on-failure re-run with logs.

Nice touch. Consider forcing color for CI logs and a clearer non-zero exit on second failure (already implied, just making it explicit).

-	@(cd frontend && pnpm run graphql-codegen >/dev/null 2>&1 \
+	@(cd frontend && FORCE_COLOR=1 pnpm run graphql-codegen >/dev/null 2>&1 \
 	&& (printf "pnpm run graphql-codegen"; for i in $$(seq 1 49); do printf "."; done; printf "\033[30;42mPassed\033[0m\n") \
 	|| (printf "pnpm run graphql-codegen"; for i in $$(seq 1 49); do printf "."; done; printf "\033[37;41mFailed\033[0m\n" \
-		&& pnpm run graphql-codegen))
+		&& pnpm run graphql-codegen || exit $$?))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4babd73 and 3316cce.

⛔ Files ignored due to path filters (14)
  • frontend/src/types/__generated__/apiKeyQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/authQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/chapterQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/committeeQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/graphql.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/homeQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/moduleQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/organizationQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/programsQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectsHealthDashboardQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/repositoryQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/snapshotQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/userQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (3)
  • .pre-commit-config.yaml (1 hunks)
  • frontend/Makefile (3 hunks)
  • frontend/src/server/queries/authQueries.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/server/queries/authQueries.ts
⏰ 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). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)

@sonarqubecloud
Copy link

sonarqubecloud bot commented Sep 2, 2025

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
frontend/graphql-codegen.ts (3)

5-5: Export an async function instead of an async IIFE.

Avoids immediate execution on import and aligns with Codegen’s async-config pattern used in this repo.

-export default (async (): Promise<CodegenConfig> => {
+export default async function codegenConfig(): Promise<CodegenConfig> {
...
-})()
+}

Also applies to: 69-69


9-16: Add a fetch timeout and fail fast; don’t return undefined config.

Prevents hanging runs and surfaces a clear error instead of exporting undefined.

   try {
-    response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
-      method: 'GET',
-    })
-  } catch {
-    /* eslint-disable no-console */
-    console.log('Failed to fetch CSRF token: make sure the backend is running.')
-    return
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 5000)
+    response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
+      method: 'GET',
+      signal: controller.signal,
+    })
+    clearTimeout(timeout)
+  } catch (err: unknown) {
+    // Ensure we fail fast with a helpful message
+    const isAbort = typeof err === 'object' && err !== null && (err as any).name === 'AbortError'
+    throw new Error(`${isAbort ? 'Timed out' : 'Failed'} to fetch CSRF token from ${PUBLIC_API_URL}/csrf/`)
   }

21-21: Harden CSRF extraction; validate presence before proceeding.

Handles alternate payloads and falls back to Set-Cookie.

-  const csrfToken = (await response.json()).csrftoken
+  type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
+  const data = (await response.json().catch(() => ({}))) as CsrfResponse
+  const csrfToken =
+    data.csrftoken ??
+    data.csrfToken ??
+    data.token ??
+    (() => {
+      const setCookie = response.headers.get('set-cookie') ?? ''
+      const m = /(?:^|;\s*)csrftoken=([^;]+)/i.exec(setCookie)
+      return m ? m[1] : undefined
+    })()
+  if (!csrfToken) {
+    throw new Error('CSRF token missing in CSRF endpoint response')
+  }
🧹 Nitpick comments (3)
frontend/graphql-codegen.ts (3)

44-51: Prevent potential filename collisions from the flattened target folder.

Set an explicit extension for near-operation-file outputs.

       presetConfig: {
         // This should be the file generated by the "typescript" plugin above,
         // relative to the directory specified for this configuration
         baseTypesPath: './types/__generated__/graphql.ts',
         // Relative to the source files
         folder: '../../types/__generated__',
+        extension: '.generated.ts',
       },

3-3: Nit: avoid possible “//” in URLs when PUBLIC_API_URL has a trailing slash.

Optionally normalize: const API_URL = PUBLIC_API_URL.replace(/\/+$/, '') and use API_URL for /csrf/ and /graphql/.


5-69: Reduce coupling to a live backend for codegen.

Consider generating from a committed schema artifact (SDL or introspection JSON) updated via a CI job, so local/CI runs don’t depend on CSRF/network availability.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3316cce and 6bb7ed0.

📒 Files selected for processing (1)
  • frontend/graphql-codegen.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-30T12:52:32.180Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.180Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.

Applied to files:

  • frontend/graphql-codegen.ts
📚 Learning: 2025-08-31T13:48:09.785Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/graphql-codegen.ts:0-0
Timestamp: 2025-08-31T13:48:09.785Z
Learning: In the OWASP/Nest project, Django's GraphQL endpoint accepts CSRF tokens via 'x-csrftoken' header (lowercase) without requiring a Referer header, working fine in their configuration for GraphQL codegen introspection.

Applied to files:

  • frontend/graphql-codegen.ts
⏰ 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). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
frontend/graphql-codegen.ts (2)

27-41: Typegen config choices look solid.

Good defaults: avoidOptionals.field=true, defaultScalarType=unknown, nonOptionalTypename, skipTypeNameForRoot.


61-67: CSRF headers OK.

Header names are case-insensitive; this matches the project’s working setup.

@arkid15r arkid15r enabled auto-merge September 2, 2025 21:41
Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

LGTM

@arkid15r arkid15r added this pull request to the merge queue Sep 2, 2025
Merged via the queue into OWASP:main with commit b6caf36 Sep 2, 2025
25 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Sep 3, 2025
2 tasks
arkid15r added a commit that referenced this pull request Sep 4, 2025
* configure graphql-codegen

* refactor query names to be unique

* Update code (sort alphabetically)

* ignore graphql-codegen generated files

* Run graphql-codegen

* remove fetchCsrfTokenServer and use a config constructor

* Update code

* use near-operation-file-preset

* use typed-document-node plugin

* Update code (sort alphabetically)

* Update code

* add graphql-codegen generated types to end-of-file-fixer

* add hook for graphql-codegen for schema validation

* Update code

* skip graphql-codegen pre-commit hook

* add graphql-codegen

* add generate-graphql-types to make check

* run make check

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
Dishant1804 pushed a commit to Dishant1804/Nest that referenced this pull request Sep 6, 2025
* configure graphql-codegen

* refactor query names to be unique

* Update code (sort alphabetically)

* ignore graphql-codegen generated files

* Run graphql-codegen

* remove fetchCsrfTokenServer and use a config constructor

* Update code

* use near-operation-file-preset

* use typed-document-node plugin

* Update code (sort alphabetically)

* Update code

* add graphql-codegen generated types to end-of-file-fixer

* add hook for graphql-codegen for schema validation

* Update code

* skip graphql-codegen pre-commit hook

* add graphql-codegen

* add generate-graphql-types to make check

* run make check

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
@rudransh-shrivastava rudransh-shrivastava deleted the feature/integrate-graphql-codegen branch October 7, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement codegen schema validation

2 participants