Skip to content

feat(backend): implement core backend logic#22

Merged
naheel0 merged 11 commits intomainfrom
backend
Mar 15, 2026
Merged

feat(backend): implement core backend logic#22
naheel0 merged 11 commits intomainfrom
backend

Conversation

@jaseel0
Copy link
Collaborator

@jaseel0 jaseel0 commented Mar 15, 2026

This pull request introduces a major backend refactor, adding authentication, database integration, and new endpoints for users, issues, and projects. The most important changes are grouped below by theme.

Authentication & Security

  • Added a new AuthController implementing GitHub OAuth login, user sync, and JWT token generation, enabling secure authentication for the API.
  • Updated IssuesController to require JWT authentication for most endpoints, ensuring only authenticated users can claim and submit quests.

Database Integration

  • Integrated Entity Framework Core and SQL Server by adding relevant package references in Backend.csproj.
  • Added initial database migration files, defining tables for users, issues, projects, and contributions, and establishing relationships between them. [1] [2]

API Endpoints

  • Implemented endpoints for user leaderboard and profile in UsersController, and project listing and details in ProjectsController, supporting new features for user and project management. [1] [2]
  • Enhanced IssuesController with endpoints for discovering issues, claiming quests, submitting quests, and retrieving a user's active quests.

Summary by CodeRabbit

  • New Features

    • GitHub OAuth login issuing JWTs; issue discovery, project listing, quest claim/submit with XP and streak handling; user leaderboard and profile (includes contributions).
  • Chores

    • Database models, migrations and schema for issues, projects, quests, users and contributions.
    • App configuration and startup updates: authentication, Swagger security UI, CORS, DB context, HTTP client and design-time DB factory.

@jaseel0 jaseel0 requested a review from naheel0 March 15, 2026 12:12
@github-actions github-actions bot added the configuration Configuration file changes label Mar 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a full ASP.NET Core backend: EF Core models, migrations and DbContext factory; GitHubService with OAuth and issue discovery; Auth controller issuing JWTs; controllers for issues/projects/users with JWT enforcement; Program DI/middleware (JWT, CORS, Swagger); project deps and appsettings config.

Changes

Cohort / File(s) Summary
Project / Config
Backend/Backend/Backend.csproj, Backend/Backend/appsettings.json
Added NuGet packages for EF Core/SQL Server and JWT auth; added GitHub/JWT/ConnectionStrings config in appsettings; new folder entry.
Program / Startup
Backend/Backend/Program.cs
Registered DbContext, JWT authentication, Swagger bearer config, CORS policy, HttpClient and GitHubService; configured middleware order and validation of JwtSettings.
Auth
Backend/Backend/Controllers/AuthController.cs
New controller: exchanges GitHub code for access token, fetches GitHub user, upserts user in DB, saves, and returns generated JWT and user info.
Issues & Quests
Backend/Backend/Controllers/IssuesController.cs, Backend/Backend/Models/Quest.cs
Reworked controller: issue discovery, claim quest, list user active quests, submit quest (award XP, record contribution); enforces JWT auth, concurrency handling; adds Quest model.
Projects API
Backend/Backend/Controllers/ProjectsController.cs, Backend/Backend/Models/Project.cs
Added ProjectsController with list/get endpoints; defined Project entity with data annotations.
Users API
Backend/Backend/Controllers/UsersController.cs, Backend/Backend/Models/User.cs
Added leaderboard and profile endpoints; expanded User model with gamification fields and Contributions navigation.
Contributions model
Backend/Backend/Models/Contribution.cs
Added UserContribution entity to record completed issues and optional PR URL.
GitHub Integration
Backend/Backend/Services/GitHubService.cs
Implemented GitHubService: OAuth token exchange, fetch authenticated user, search/suggest issues, DTOs and helpers; registered via DI.
DbContext & Factory
Backend/Backend/Models/GitQuestContext.cs, Backend/Backend/Models/GitQuestContextFactory.cs
Added DbSet properties, OnModelCreating with unique and composite filtered index for active quests, and a design-time DbContext factory.
Migrations / Snapshots
Backend/Backend/Migrations/*
Added initial and subsequent EF Core migrations, designers and model snapshot to create/evolve schema (Issues, Projects, Users, Contributions, Quests, unique constraints).

Sequence Diagram

sequenceDiagram
    participant Client
    participant AuthController as Auth Controller
    participant GitHubService as GitHub Service
    participant GitHubAPI as GitHub API
    participant DbContext as Database

    Client->>AuthController: POST /api/auth/github-login (code)
    AuthController->>GitHubService: GetAccessToken(code)
    GitHubService->>GitHubAPI: POST /login/oauth/access_token
    GitHubAPI-->>GitHubService: access_token
    GitHubService-->>AuthController: token

    AuthController->>GitHubService: GetGitHubUser(token)
    GitHubService->>GitHubAPI: GET /user
    GitHubAPI-->>GitHubService: user profile
    GitHubService-->>AuthController: GitHubUserResponse

    AuthController->>DbContext: Find user by GitHubId
    DbContext-->>AuthController: user or null

    alt exists
        AuthController->>DbContext: Update user
    else
        AuthController->>DbContext: Create user
    end

    AuthController->>DbContext: SaveChangesAsync()
    DbContext-->>AuthController: saved
    AuthController->>AuthController: GenerateJwtToken(user)
    AuthController-->>Client: return JWT + user
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'feat(backend): implement core backend logic' is related to the changes but uses overly broad language. While it correctly identifies the backend feature scope, 'core backend logic' is vague and doesn't convey the specific primary changes (authentication, database integration, API endpoints). Consider a more specific title that highlights the main change, such as 'feat(backend): add GitHub OAuth authentication and database integration' or 'feat(backend): implement authentication and entity framework integration'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch backend
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jaseel0 jaseel0 changed the title add logic to backend feat(backend): implement core backend logic Mar 15, 2026
Copy link

@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: 13

🧹 Nitpick comments (3)
Backend/Backend/Backend.csproj (1)

21-22: Remove placeholder folder entry unless intentionally required.

Line 22 (<Folder Include="NewFolder\" />) looks like scaffold noise and adds maintenance clutter in source control.

Suggested cleanup
-  <ItemGroup>
-    <Folder Include="NewFolder\" />
-  </ItemGroup>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Backend.csproj` around lines 21 - 22, Remove the scaffold
placeholder Folder entry by deleting the XML element <Folder
Include="NewFolder\" /> from the project file (or replace it with the intended
folder name if it was meant to be tracked); ensure no other build/runtime logic
depends on the placeholder before committing the removal.
Backend/Backend/Models/GitQuestContext.cs (1)

19-25: Enforce uniqueness on GitHubId too.

AuthController.cs Line 39 uses GitHubId as the lookup key, but the schema only guarantees uniqueness for GitHubUsername. If GitHubId is the identity you trust, the database should enforce it as well.

Suggested model change
         modelBuilder.Entity<User>()
             .HasIndex(u => u.GitHubUsername)
             .IsUnique();
+
+        modelBuilder.Entity<User>()
+            .HasIndex(u => u.GitHubId)
+            .IsUnique();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Models/GitQuestContext.cs` around lines 19 - 25, The User
lookup in AuthController.cs uses GitHubId but the EF model only enforces
uniqueness for GitHubUsername; add a unique index on the GitHubId property in
GitQuestContext by adding a HasIndex(u => u.GitHubId).IsUnique() call for the
User entity (next to the existing GitHubUsername index), then create and apply a
new EF migration so the database enforces uniqueness at the schema level.
Backend/Backend/Controllers/ProjectsController.cs (1)

16-20: Add pagination to the projects list endpoint.

ToListAsync() makes response size and query cost grow with the entire table. A capped page/pageSize contract will keep this endpoint predictable once the catalog grows.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/ProjectsController.cs` around lines 16 - 20, The
GetProjects endpoint currently returns the entire table via
_context.Projects.ToListAsync(), which will grow unbounded; change the action
GetProjects to accept optional query params (int page = 1, int pageSize = 20),
validate they are >=1 and enforce a max pageSize, compute totalCount = await
_context.Projects.CountAsync(), then apply pagination with .OrderBy(/*id or
created*/) .Skip((page-1)*pageSize).Take(pageSize) on _context.Projects and
return the page results plus pagination metadata (totalCount, page, pageSize) in
the response instead of the raw ToListAsync() call. Ensure method signature and
route binding support query parameters and return BadRequest for invalid values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/Backend/appsettings.json`:
- Around line 13-20: The file contains committed secrets: JwtSettings:Key and
GitHub:ClientSecret (and the GitHub:ClientId shown) — remove these values from
the checked-in appsettings.json, replace them with non-sensitive placeholders,
and move the real values into secure configuration (user-secrets for local dev
or environment variables / secret store for deployments). Update any
configuration binding that reads JwtSettings:Key or GitHub:ClientSecret (e.g.,
IConfiguration access in Program/Startup that uses "JwtSettings:Key" and
"GitHub:ClientSecret") to fall back to environment variables, and rotate/revoke
any currently provisioned keys/secrets that were exposed in the repo.

In `@Backend/Backend/Backend.csproj`:
- Around line 10-18: The project uses floating package versions for critical
dependencies (PackageReference entries for
Microsoft.AspNetCore.Authentication.JwtBearer, Microsoft.EntityFrameworkCore,
Microsoft.EntityFrameworkCore.Design, and
Microsoft.EntityFrameworkCore.SqlServer) which should be pinned; update those
PackageReference Version attributes to specific fixed versions (or adopt central
package/version management) so restores are reproducible—locate the
PackageReference elements for the symbols
Microsoft.AspNetCore.Authentication.JwtBearer, Microsoft.EntityFrameworkCore,
Microsoft.EntityFrameworkCore.Design, and
Microsoft.EntityFrameworkCore.SqlServer in the project file and replace the
"8.0.*" wildcard with explicit version numbers (or wire them to a central
version source).

In `@Backend/Backend/Controllers/AuthController.cs`:
- Around line 67-86: GetGitHubAccessToken currently calls client.SendAsync and
response.Content.ReadFromJsonAsync<GitHubTokenResponse>() without handling
transport or deserialization exceptions; wrap the SendAsync and
ReadFromJsonAsync calls in try-catch blocks inside GetGitHubAccessToken, catch
HttpRequestException/TaskCanceledException/JsonException (or general Exception
as needed), and return null or throw a controlled exception that the controller
can translate into a 502/401 response; ensure you still check
response.IsSuccessStatusCode before attempting deserialization and handle
non-success responses by returning null or a specific error indicator so
upstream code can map it to the proper 502/401 response.

In `@Backend/Backend/Controllers/IssuesController.cs`:
- Around line 43-58: Add a database-level unique constraint/index to enforce no
more than one active quest per (UserId, GitHubIssueId, Status) (e.g. a unique
index on UserId+GitHubIssueId+Status or a filtered index where Status='In
Progress' in the migration for the Quest entity), and update the controller
around the _context.Quests.Add(quest); await _context.SaveChangesAsync(); call
in IssuesController to catch the DbUpdateException/unique-key violation (thrown
by SaveChangesAsync) and return a 409 Conflict instead of letting duplicates
slip through; reference the Quest entity and _context.Quests to locate where to
add the migration/constraint and the SaveChangesAsync call to add the exception
handling.
- Around line 48-58: The current claim handler creates a Quest from the
client-supplied id and the submit handler marks it complete without server-side
verification, allowing clients to self-award quests/XP; change both handlers so
they look up the authoritative Issue row in the Issues table (check
Issue.IsActive and use its persisted reward fields), reject unknown or inactive
Issue ids, and require recording and verifying a corresponding
UserContribution/Contribution entry before changing Quest.Status to "Completed"
and awarding XP; update the Quest creation logic (where _context.Quests.Add and
SaveChangesAsync are called) to derive UserId/GitHubIssueId/Reward from the
validated Issue and only create a Quest after verification, and similarly ensure
the submit flow verifies a persisted Contribution/UserContribution record before
applying rewards.
- Around line 89-94: The CurrentStreak is being incremented on every submission
which allows multiple same-day increments and never resets; change the logic in
the method that updates the user (where you call _context.Users.FindAsync and
modify user.ExperiencePoints and user.CurrentStreak) to compute streaks from
LastContributionDate: if LastContributionDate is the same UTC calendar day as
today do not increment CurrentStreak, if LastContributionDate is exactly one day
before today increment CurrentStreak by 1, otherwise set CurrentStreak = 1; then
set LastContributionDate = today (use UTC date only) and add ExperiencePoints as
before, and ensure you persist changes (e.g., save the user via the DbContext).
- Around line 63-71: GetMyQuests currently returns all quests for the user but
the route requires only active quests; update the LINQ query against
_context.Quests in GetMyQuests to filter out non-active rows by adding the
appropriate predicate (e.g., check q.Status == QuestStatus.Active or q.IsActive
== true / exclude q.IsCompleted/q.IsAbandoned) so only active quests for the
given userId are returned, then return that filtered list.

In `@Backend/Backend/Controllers/UsersController.cs`:
- Around line 33-40: The action in UsersController currently returns the EF
entity graph (_context.Users including Contributions -> Issue) which exposes
sensitive fields (Email, GitHubId) and causes JSON reference cycles
(UserContribution -> User); instead create and return a projected DTO (e.g.,
PublicUserDto or UserProfileDto) and use a LINQ Select on _context.Users to map
only safe fields (public name, avatar, bio, username, and a trimmed
contributions collection with Issue summary but no User back-reference),
removing the Include chain to avoid cycles; ensure the controller action returns
Ok(projectedDto) and do not serialize EF navigation properties or the
UserContribution.User back-reference.

In `@Backend/Backend/Migrations/20260315082912_InitialCreate.cs`:
- Around line 57-59: Add a unique index on the stable GitHubId column to prevent
duplicate Users for the same external account: in the migration's Up method (the
class containing Up and Down), create a unique index on GitHubId for the Users
table (in addition to existing GitHubUsername column definition), and in the
Down method drop that index; reference the GitHubId column and ensure the index
name is deterministic so the Down method can remove it cleanly.

In `@Backend/Backend/Program.cs`:
- Around line 51-53: The code currently supplies a hard-coded JWT fallback
secret in Program.cs (variables jwtSettings, secretKey, key) and uses
Encoding.ASCII while AuthController uses Encoding.UTF8, which is unsafe and
causes encoding mismatch; update Program.cs to refuse to start (throw/exit) if
JwtSettings:Key is missing (or load a secure secret from a properly provisioned
source like an environment variable or a secrets store) instead of using a
hard-coded value, and change the key byte encoding to Encoding.UTF8 to match
AuthController (or otherwise ensure both places use the same UTF8 encoding);
ensure failure behavior logs a clear error and prevents the app from running
with an insecure default.

In `@Backend/Backend/Services/GitHubService.cs`:
- Around line 96-103: The GitHubIssueItem record's Body property must be
nullable because the GitHub API can return null; change the Body declaration to
a nullable string (e.g., string? Body) in the GitHubIssueItem record and update
any mapping logic that assigns GitHubIssueItem.Body to Issue.Description to
handle nulls (e.g., coalesce to an empty string or handle null safely) so
deserialization and downstream mapping won't throw.
- Around line 74-75: The label check in GitHubService.cs that sets Difficulty
and XPReward uses a case-sensitive Contains("good first issue") and will miss
variants; update the predicate used on item.Labels (where Difficulty and
XPReward are set) to perform a case-insensitive, normalized match (e.g., compare
l.Name.ToLowerInvariant() or use IndexOf with
StringComparison.OrdinalIgnoreCase) and also handle common variants like
"good-first-issue" by normalizing separators (replace '-' with ' ') or checking
both forms so labels like "Good First Issue" or "good-first-issue" correctly
yield Beginner/15.
- Around line 34-40: The Accept header is being added after sending the POST;
move the header setup on _httpClient (set Accept to "application/json") before
calling PostAsJsonAsync so GitHub returns JSON, then check
response.IsSuccessStatusCode before attempting ReadFromJsonAsync; if
non-success, surface/log the status and body (use
response.Content.ReadAsStringAsync) or throw an appropriate exception. Also
handle a null result from ReadFromJsonAsync when deserializing to
GitHubTokenResponse and only return result?.AccessToken if result is non-null
(otherwise handle as error/return null).

---

Nitpick comments:
In `@Backend/Backend/Backend.csproj`:
- Around line 21-22: Remove the scaffold placeholder Folder entry by deleting
the XML element <Folder Include="NewFolder\" /> from the project file (or
replace it with the intended folder name if it was meant to be tracked); ensure
no other build/runtime logic depends on the placeholder before committing the
removal.

In `@Backend/Backend/Controllers/ProjectsController.cs`:
- Around line 16-20: The GetProjects endpoint currently returns the entire table
via _context.Projects.ToListAsync(), which will grow unbounded; change the
action GetProjects to accept optional query params (int page = 1, int pageSize =
20), validate they are >=1 and enforce a max pageSize, compute totalCount =
await _context.Projects.CountAsync(), then apply pagination with .OrderBy(/*id
or created*/) .Skip((page-1)*pageSize).Take(pageSize) on _context.Projects and
return the page results plus pagination metadata (totalCount, page, pageSize) in
the response instead of the raw ToListAsync() call. Ensure method signature and
route binding support query parameters and return BadRequest for invalid values.

In `@Backend/Backend/Models/GitQuestContext.cs`:
- Around line 19-25: The User lookup in AuthController.cs uses GitHubId but the
EF model only enforces uniqueness for GitHubUsername; add a unique index on the
GitHubId property in GitQuestContext by adding a HasIndex(u =>
u.GitHubId).IsUnique() call for the User entity (next to the existing
GitHubUsername index), then create and apply a new EF migration so the database
enforces uniqueness at the schema level.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e287c02a-7455-46f4-ab55-c7f5a05d1365

📥 Commits

Reviewing files that changed from the base of the PR and between a86d25a and ed64b0e.

📒 Files selected for processing (19)
  • Backend/Backend/Backend.csproj
  • Backend/Backend/Controllers/AuthController.cs
  • Backend/Backend/Controllers/IssuesController.cs
  • Backend/Backend/Controllers/ProjectsController.cs
  • Backend/Backend/Controllers/UsersController.cs
  • Backend/Backend/Migrations/20260315082912_InitialCreate.Designer.cs
  • Backend/Backend/Migrations/20260315082912_InitialCreate.cs
  • Backend/Backend/Migrations/20260315104521_AddQuestTable.Designer.cs
  • Backend/Backend/Migrations/20260315104521_AddQuestTable.cs
  • Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs
  • Backend/Backend/Models/Contribution.cs
  • Backend/Backend/Models/GitQuestContext.cs
  • Backend/Backend/Models/Issue.cs
  • Backend/Backend/Models/Project.cs
  • Backend/Backend/Models/Quest.cs
  • Backend/Backend/Models/User.cs
  • Backend/Backend/Program.cs
  • Backend/Backend/Services/GitHubService.cs
  • Backend/Backend/appsettings.json

Comment on lines +96 to +103
public record GitHubIssueItem(
[property: JsonPropertyName("id")] long Id,
[property: JsonPropertyName("title")] string Title,
[property: JsonPropertyName("body")] string Body,
[property: JsonPropertyName("html_url")] string HtmlUrl,
[property: JsonPropertyName("repository_url")] string RepositoryUrl,
[property: JsonPropertyName("labels")] List<GitHubLabel> Labels
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Body property should be nullable.

GitHub API can return null for the issue body when it's empty. Declaring it as non-nullable string may cause JSON deserialization issues or unexpected behavior when mapping to Issue.Description.

🛠️ Suggested fix
 public record GitHubIssueItem(
     [property: JsonPropertyName("id")] long Id,
     [property: JsonPropertyName("title")] string Title,
-    [property: JsonPropertyName("body")] string Body,
+    [property: JsonPropertyName("body")] string? Body,
     [property: JsonPropertyName("html_url")] string HtmlUrl,
     [property: JsonPropertyName("repository_url")] string RepositoryUrl,
     [property: JsonPropertyName("labels")] List<GitHubLabel> Labels
 );
📝 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 record GitHubIssueItem(
[property: JsonPropertyName("id")] long Id,
[property: JsonPropertyName("title")] string Title,
[property: JsonPropertyName("body")] string Body,
[property: JsonPropertyName("html_url")] string HtmlUrl,
[property: JsonPropertyName("repository_url")] string RepositoryUrl,
[property: JsonPropertyName("labels")] List<GitHubLabel> Labels
);
public record GitHubIssueItem(
[property: JsonPropertyName("id")] long Id,
[property: JsonPropertyName("title")] string Title,
[property: JsonPropertyName("body")] string? Body,
[property: JsonPropertyName("html_url")] string HtmlUrl,
[property: JsonPropertyName("repository_url")] string RepositoryUrl,
[property: JsonPropertyName("labels")] List<GitHubLabel> Labels
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Services/GitHubService.cs` around lines 96 - 103, The
GitHubIssueItem record's Body property must be nullable because the GitHub API
can return null; change the Body declaration to a nullable string (e.g., string?
Body) in the GitHubIssueItem record and update any mapping logic that assigns
GitHubIssueItem.Body to Issue.Description to handle nulls (e.g., coalesce to an
empty string or handle null safely) so deserialization and downstream mapping
won't throw.

@jaseel0
Copy link
Collaborator Author

jaseel0 commented Mar 15, 2026

@copilot
fix all menstion by coderabbite

Copy link
Contributor

Copilot AI commented Mar 15, 2026

@jaseel0 I've opened a new pull request, #23, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 15, 2026 12:59
fix(backend): address all CodeRabbit security and correctness issues
@github-actions github-actions bot added the feature New feature or request label Mar 15, 2026
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Copy link

@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: 3

♻️ Duplicate comments (1)
Backend/Backend/Program.cs (1)

55-55: ⚠️ Potential issue | 🟠 Major

Encoding mismatch: ASCII here vs UTF8 in AuthController.

Line 55 uses Encoding.ASCII.GetBytes(secretKey) but AuthController.GenerateJwtToken (line 117) uses Encoding.UTF8.GetBytes. If the JWT key contains non-ASCII characters, token validation will fail because the signing keys won't match.

🐛 Proposed fix
-var key = Encoding.ASCII.GetBytes(secretKey);
+var key = Encoding.UTF8.GetBytes(secretKey);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Program.cs` at line 55, Replace the ASCII encoding used when
deriving the signing key so it matches AuthController.GenerateJwtToken: change
the code that creates the variable key (var key =
Encoding.ASCII.GetBytes(secretKey)) to use UTF8 encoding
(Encoding.UTF8.GetBytes(secretKey)) so the signing key bytes align with the
token generation logic and avoid validation failures for non-ASCII characters.
🧹 Nitpick comments (11)
Backend/Backend/Backend.csproj (1)

21-22: Remove empty placeholder folder.

NewFolder appears to be an empty placeholder that serves no purpose and should be removed from the project.

🧹 Proposed fix
   </ItemGroup>

-  <ItemGroup>
-    <Folder Include="NewFolder\" />
-  </ItemGroup>
-
 </Project>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Backend.csproj` around lines 21 - 22, Remove the empty
placeholder Folder entry from the project file: delete the <Folder
Include="NewFolder\" /> element (the ItemGroup containing that Folder) so the
project no longer references the unused NewFolder placeholder; ensure no other
project XML depends on that Folder element before committing.
Backend/Backend/Models/GitQuestContext.cs (1)

2-2: Remove unused import.

System.Reflection.Emit is not used anywhere in this file and appears to be a leftover from scaffolding.

🧹 Proposed fix
 using Microsoft.EntityFrameworkCore;
-using System.Reflection.Emit;
 
 namespace GitQuest.Backend.Models;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Models/GitQuestContext.cs` at line 2, Remove the unused using
directive System.Reflection.Emit from the top of GitQuestContext.cs; edit the
file containing the GitQuestContext class to delete that import so only required
namespaces remain (i.e., clean up the using declarations).
Backend/Backend/Controllers/UsersController.cs (1)

33-62: Consider query-level projection for better efficiency.

The current approach loads the full User entity with Include chains, then projects in memory. While the response correctly excludes sensitive fields (Email, GitHubId), fetching and materializing the full entity graph is unnecessary.

♻️ Proposed optimization using query-level projection
-        var user = await _context.Users
-            .Include(u => u.Contributions)
-            .ThenInclude(c => c.Issue)
-            .FirstOrDefaultAsync(u => u.GitHubUsername == username);
-
-        if (user == null) return NotFound();
-
-        var profile = new
-        {
-            user.GitHubUsername,
-            user.AvatarUrl,
-            user.ExperiencePoints,
-            user.CurrentStreak,
-            user.LastContributionDate,
-            Contributions = user.Contributions.Select(c => new
+        var profile = await _context.Users
+            .AsNoTracking()
+            .Where(u => u.GitHubUsername == username)
+            .Select(u => new
             {
-                c.CompletedAt,
-                c.PullRequestUrl,
-                Issue = c.Issue == null ? null : new
+                u.GitHubUsername,
+                u.AvatarUrl,
+                u.ExperiencePoints,
+                u.CurrentStreak,
+                u.LastContributionDate,
+                Contributions = u.Contributions.Select(c => new
                 {
-                    c.Issue.Title,
-                    c.Issue.RepoFullName,
-                    c.Issue.IssueUrl,
-                    c.Issue.Difficulty,
-                    c.Issue.XPReward
-                }
+                    c.CompletedAt,
+                    c.PullRequestUrl,
+                    Issue = new
+                    {
+                        c.Issue.Title,
+                        c.Issue.RepoFullName,
+                        c.Issue.IssueUrl,
+                        c.Issue.Difficulty,
+                        c.Issue.XPReward
+                    }
+                }).ToList()
             })
-        };
+            .FirstOrDefaultAsync();
 
+        if (profile == null) return NotFound();
+
         return Ok(profile);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/UsersController.cs` around lines 33 - 62, The
current code materializes the full User entity via _context.Users with
Include/ThenInclude and then projects to the anonymous profile, which is
inefficient; change to a query-level projection on _context.Users (remove
Include/ThenInclude) that selects the needed anonymous shape (GitHubUsername,
AvatarUrl, ExperiencePoints, CurrentStreak, LastContributionDate and
Contributions mapped to CompletedAt, PullRequestUrl and nested Issue fields) and
then call FirstOrDefaultAsync(u => u.GitHubUsername == username) on that
projection; keep the null check for the resulting projected object and return
Ok(profile) or NotFound() as before to preserve behavior in UsersController.
Backend/Backend/Controllers/IssuesController.cs (1)

100-141: Consider recording a UserContribution on quest submission.

The schema includes a UserContribution entity for tracking completed contributions, but SubmitQuest doesn't create one. This may be intentional, but contributions data is used by GetProfile to display user history.

♻️ Proposed addition
         quest.Status = "Completed";
         quest.CompletedAt = DateTime.UtcNow;
 
+        // Record the contribution for user profile/history
+        var contribution = new UserContribution
+        {
+            Id = Guid.NewGuid(),
+            UserId = userId,
+            IssueId = issue.Id,
+            CompletedAt = DateTime.UtcNow
+        };
+        _context.Contributions.Add(contribution);
+
         var user = await _context.Users.FindAsync(userId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/IssuesController.cs` around lines 100 - 141, When
completing a quest in IssuesController (the SubmitQuest flow that sets
quest.Status, quest.CompletedAt, updates user XP/streak), also create and
persist a new UserContribution record so contribution history is populated for
GetProfile: instantiate a UserContribution with references to the user (userId),
the issue/quest identifiers (use issue.GitHubIssueId and/or quest.Id), the
contribution date (DateTime.UtcNow), XP awarded (issue.XPReward) and any other
required fields, add it via _context.UserContributions.Add(...) and save with
the existing await _context.SaveChangesAsync(); ensure this runs only when user
!= null and the issue/quest is valid.
Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs (1)

17-31: Add MaxLength(450) attributes to User.GitHubId and Quest.Status properties.

The migration alters these columns from nvarchar(max) to nvarchar(450) for indexing eligibility, but the model properties lack corresponding [MaxLength(450)] annotations. This drift between model and database schema can cause future scaffolded migrations to attempt reverting these columns. Add [MaxLength(450)] to both User.GitHubId and Quest.Status in their respective model classes, or configure via fluent API in OnModelCreating.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs` around
lines 17 - 31, The model properties are missing the MaxLength constraint that
the migration expects; update the User.GitHubId and Quest.Status properties to
include a maximum length of 450 (either add the [MaxLength(450)] attribute to
the User.GitHubId and Quest.Status properties in their model classes or
configure them in DbContext.OnModelCreating with
modelBuilder.Entity<User>().Property(u => u.GitHubId).HasMaxLength(450) and
modelBuilder.Entity<Quest>().Property(q => q.Status).HasMaxLength(450)) so the
EF model matches the migration and prevents future scaffolded migrations from
reverting the column sizes.
Backend/Backend/Controllers/AuthController.cs (3)

138-140: Duplicate DTO records conflict with GitHubService definitions.

These records duplicate GitHubTokenResponse and GitHubUserResponse from GitHubService.cs but with different property names (snake_case vs PascalCase with JsonPropertyName). This creates potential namespace conflicts and inconsistent JSON mapping.

If you adopt the refactor to delegate to GitHubService, remove these duplicate records.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/AuthController.cs` around lines 138 - 140, Remove
the duplicate DTO records GitHubTokenResponse and GitHubUserResponse from
AuthController.cs and delegate to the existing types defined in GitHubService
(use the GitHubService's DTOs with their JsonPropertyName mappings); ensure all
references in AuthController (e.g., any return types or deserialization targets)
use the GitHubService types instead of the locally declared records to avoid
namespace conflicts and inconsistent JSON mapping.

67-113: Consider delegating to GitHubService instead of duplicating OAuth logic.

AuthController implements its own GetGitHubAccessToken and GetGitHubUser methods, duplicating the same logic in GitHubService.GetAccessToken and GitHubService.GetGitHubUser. This creates maintenance burden and divergence risk.

Since GitHubService is already registered in DI (see Program.cs line 48), inject it and delegate:

♻️ Proposed refactor
 public class AuthController : ControllerBase
 {
     private readonly IConfiguration _config;
     private readonly GitQuestContext _context;
-    private readonly IHttpClientFactory _httpClientFactory;
+    private readonly GitHubService _gitHubService;

-    public AuthController(IConfiguration config, GitQuestContext context, IHttpClientFactory httpClientFactory)
+    public AuthController(IConfiguration config, GitQuestContext context, GitHubService gitHubService)
     {
         _config = config;
         _context = context;
-        _httpClientFactory = httpClientFactory;
+        _gitHubService = gitHubService;
     }

     [HttpPost("github-login")]
     public async Task<IActionResult> GitHubLogin([FromBody] string code)
     {
-        var githubToken = await GetGitHubAccessToken(code);
+        var githubToken = await _gitHubService.GetAccessToken(code);
         if (string.IsNullOrEmpty(githubToken)) return Unauthorized("Invalid GitHub Code");

-        var githubUser = await GetGitHubUser(githubToken);
+        var githubUser = await _gitHubService.GetGitHubUser(githubToken);
         if (githubUser is null) return BadRequest("Could not fetch GitHub profile");
         // ... rest unchanged, but update property access to PascalCase
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/AuthController.cs` around lines 67 - 113,
AuthController currently duplicates OAuth logic in GetGitHubAccessToken and
GetGitHubUser that already exists in GitHubService.GetAccessToken and
GitHubService.GetGitHubUser; inject GitHubService into AuthController (add a
constructor parameter and assign a private readonly field) and replace calls to
the local GetGitHubAccessToken/GetGitHubUser methods with calls to the
corresponding GitHubService methods, then remove the duplicated private methods
from AuthController to avoid divergence and maintenance burden.

91-94: Consider logging swallowed exceptions for debugging.

The generic catch at lines 91-94 (and 109-112) correctly prevents unhandled exceptions from turning login into a 500, but swallowing exceptions silently makes debugging difficult in production.

🔧 Optional: Add logging
+    private readonly ILogger<AuthController> _logger;
+
+    public AuthController(IConfiguration config, GitQuestContext context, IHttpClientFactory httpClientFactory, ILogger<AuthController> logger)
+    {
+        // ...
+        _logger = logger;
+    }
+
     catch (Exception)
     {
+        _logger.LogWarning(ex, "Failed to exchange GitHub code for access token");
         return null;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/AuthController.cs` around lines 91 - 94, The
catch blocks in AuthController that currently read "catch (Exception) { return
null; }" are swallowing exceptions; change them to capture the exception (e.g.,
"catch (Exception ex)") and log it before returning null using the controller's
logger (e.g., call _logger.LogError(ex, \"Failed to authenticate user\" ) or
inject ILogger<AuthController> if one doesn't exist), and apply this change to
both occurrences around the authentication/login methods so errors are recorded
for debugging.
Backend/Backend/Program.cs (2)

86-86: CORS origin is hardcoded to localhost:3000.

For production deployment, this will need to be configurable. Consider moving to appsettings.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Program.cs` at line 86, The CORS origin is hardcoded in the
call to policy.WithOrigins("http://localhost:3000"); change this to read allowed
origins from configuration (e.g., an "AllowedOrigins" setting in
appsettings.json) and pass it to policy.WithOrigins(...) after splitting on a
separator; update Program.cs to obtain IConfiguration (builder.Configuration)
and use configuration["AllowedOrigins"]?.Split(';') (or similar) when building
the policy so origins are configurable per environment, and add the
AllowedOrigins key to appsettings.json (and override in production secrets/ENV
as needed).

64-64: Reminder: Enable RequireHttpsMetadata in production.

The comment notes this should be true in production. Consider using environment-based configuration to avoid accidentally deploying with this disabled.

🔧 Environment-based configuration
-.AddJwtBearer(options =>
-{
-    options.RequireHttpsMetadata = false; // Set to true in production
+.AddJwtBearer(options =>
+{
+    options.RequireHttpsMetadata = !builder.Environment.IsDevelopment();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Program.cs` at line 64, The code currently sets
options.RequireHttpsMetadata = false; which should be true in production—change
it to read from environment or config and enable it for production, e.g. use
builder.Environment.IsProduction() or an IConfiguration key to set
options.RequireHttpsMetadata (referencing options.RequireHttpsMetadata,
builder.Environment.IsProduction(), IConfiguration/Settings) so non-prod can
remain false while production is true; update Program.cs to set the value from
the environment/config and document the required production setting.
Backend/Backend/Services/GitHubService.cs (1)

40-44: HTTP calls lack exception handling.

SendAsync (line 40) and ReadFromJsonAsync (line 43) can throw HttpRequestException, TaskCanceledException, or JsonException. Unlike AuthController's version, this method doesn't wrap calls in try-catch.

🛡️ Add exception handling
+        try
+        {
             var response = await _httpClient.SendAsync(request);
             if (!response.IsSuccessStatusCode) return null;

             var result = await response.Content.ReadFromJsonAsync<GitHubTokenResponse>();
             return result?.AccessToken;
+        }
+        catch (Exception)
+        {
+            return null;
+        }

Apply similar handling to GetGitHubUser and GetSuggestedIssues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Services/GitHubService.cs` around lines 40 - 44, Wrap the
HTTP calls in the GitHubService methods (the method that calls
_httpClient.SendAsync and response.Content.ReadFromJsonAsync to return
result?.AccessToken, and similarly GetGitHubUser and GetSuggestedIssues) in a
try-catch that catches HttpRequestException, TaskCanceledException, and
JsonException; inside the catch log the exception via the service logger or
_logger with contextual messages and return null (or an appropriate failure
value) instead of allowing exceptions to propagate. Ensure you wrap the calls to
_httpClient.SendAsync(...) and response.Content.ReadFromJsonAsync<T>(...)
specifically, handle each exception type generically (same remediation), and
keep the existing null-return behavior on failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/Backend/Controllers/AuthController.cs`:
- Line 75: The OAuth redirect URI config key is mismatched: in AuthController
where the POST body/dictionary adds { "redirect_uri",
_config["GitHub:RedirectUri"] ?? "" } replace the config lookup to use the
existing appsettings key "GitHub:CallbackUrl" (i.e., change
_config["GitHub:RedirectUri"] to _config["GitHub:CallbackUrl"]) so the
"redirect_uri" value is populated correctly during the token exchange;
alternatively, if you prefer changing appsettings, rename the GitHub key to
"RedirectUri" to match AuthController—ensure AuthController's lookup and
appsettings use the same key.

In `@Backend/Backend/Controllers/IssuesController.cs`:
- Line 41: In IssuesController, avoid throwing on malformed JWT claims by
replacing Guid.Parse(userIdClaim) with Guid.TryParse(userIdClaim, out var
userId) and handling the false case (e.g., return BadRequest("Invalid user id
claim") or Unauthorized()) so the action methods gracefully respond instead of
throwing; apply the same change for the other occurrences where you parse the
claim (the other Guid.Parse usages that produce userId in this controller).

In `@Backend/Backend/Services/GitHubService.cs`:
- Line 31: The code reads section["RedirectUri"] into redirect_uri in
GitHubService (the redirect_uri assignment), but appsettings.json defines the
key as GitHub:CallbackUrl so redirect_uri will be null; fix by using the correct
configuration key (e.g., replace section["RedirectUri"] with
section["CallbackUrl"] or section["GitHub:CallbackUrl"] as appropriate) or
change appsettings.json to use RedirectUri to keep keys consistent so the OAuth
token exchange uses a valid redirect URI.

---

Duplicate comments:
In `@Backend/Backend/Program.cs`:
- Line 55: Replace the ASCII encoding used when deriving the signing key so it
matches AuthController.GenerateJwtToken: change the code that creates the
variable key (var key = Encoding.ASCII.GetBytes(secretKey)) to use UTF8 encoding
(Encoding.UTF8.GetBytes(secretKey)) so the signing key bytes align with the
token generation logic and avoid validation failures for non-ASCII characters.

---

Nitpick comments:
In `@Backend/Backend/Backend.csproj`:
- Around line 21-22: Remove the empty placeholder Folder entry from the project
file: delete the <Folder Include="NewFolder\" /> element (the ItemGroup
containing that Folder) so the project no longer references the unused NewFolder
placeholder; ensure no other project XML depends on that Folder element before
committing.

In `@Backend/Backend/Controllers/AuthController.cs`:
- Around line 138-140: Remove the duplicate DTO records GitHubTokenResponse and
GitHubUserResponse from AuthController.cs and delegate to the existing types
defined in GitHubService (use the GitHubService's DTOs with their
JsonPropertyName mappings); ensure all references in AuthController (e.g., any
return types or deserialization targets) use the GitHubService types instead of
the locally declared records to avoid namespace conflicts and inconsistent JSON
mapping.
- Around line 67-113: AuthController currently duplicates OAuth logic in
GetGitHubAccessToken and GetGitHubUser that already exists in
GitHubService.GetAccessToken and GitHubService.GetGitHubUser; inject
GitHubService into AuthController (add a constructor parameter and assign a
private readonly field) and replace calls to the local
GetGitHubAccessToken/GetGitHubUser methods with calls to the corresponding
GitHubService methods, then remove the duplicated private methods from
AuthController to avoid divergence and maintenance burden.
- Around line 91-94: The catch blocks in AuthController that currently read
"catch (Exception) { return null; }" are swallowing exceptions; change them to
capture the exception (e.g., "catch (Exception ex)") and log it before returning
null using the controller's logger (e.g., call _logger.LogError(ex, \"Failed to
authenticate user\" ) or inject ILogger<AuthController> if one doesn't exist),
and apply this change to both occurrences around the authentication/login
methods so errors are recorded for debugging.

In `@Backend/Backend/Controllers/IssuesController.cs`:
- Around line 100-141: When completing a quest in IssuesController (the
SubmitQuest flow that sets quest.Status, quest.CompletedAt, updates user
XP/streak), also create and persist a new UserContribution record so
contribution history is populated for GetProfile: instantiate a UserContribution
with references to the user (userId), the issue/quest identifiers (use
issue.GitHubIssueId and/or quest.Id), the contribution date (DateTime.UtcNow),
XP awarded (issue.XPReward) and any other required fields, add it via
_context.UserContributions.Add(...) and save with the existing await
_context.SaveChangesAsync(); ensure this runs only when user != null and the
issue/quest is valid.

In `@Backend/Backend/Controllers/UsersController.cs`:
- Around line 33-62: The current code materializes the full User entity via
_context.Users with Include/ThenInclude and then projects to the anonymous
profile, which is inefficient; change to a query-level projection on
_context.Users (remove Include/ThenInclude) that selects the needed anonymous
shape (GitHubUsername, AvatarUrl, ExperiencePoints, CurrentStreak,
LastContributionDate and Contributions mapped to CompletedAt, PullRequestUrl and
nested Issue fields) and then call FirstOrDefaultAsync(u => u.GitHubUsername ==
username) on that projection; keep the null check for the resulting projected
object and return Ok(profile) or NotFound() as before to preserve behavior in
UsersController.

In `@Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs`:
- Around line 17-31: The model properties are missing the MaxLength constraint
that the migration expects; update the User.GitHubId and Quest.Status properties
to include a maximum length of 450 (either add the [MaxLength(450)] attribute to
the User.GitHubId and Quest.Status properties in their model classes or
configure them in DbContext.OnModelCreating with
modelBuilder.Entity<User>().Property(u => u.GitHubId).HasMaxLength(450) and
modelBuilder.Entity<Quest>().Property(q => q.Status).HasMaxLength(450)) so the
EF model matches the migration and prevents future scaffolded migrations from
reverting the column sizes.

In `@Backend/Backend/Models/GitQuestContext.cs`:
- Line 2: Remove the unused using directive System.Reflection.Emit from the top
of GitQuestContext.cs; edit the file containing the GitQuestContext class to
delete that import so only required namespaces remain (i.e., clean up the using
declarations).

In `@Backend/Backend/Program.cs`:
- Line 86: The CORS origin is hardcoded in the call to
policy.WithOrigins("http://localhost:3000"); change this to read allowed origins
from configuration (e.g., an "AllowedOrigins" setting in appsettings.json) and
pass it to policy.WithOrigins(...) after splitting on a separator; update
Program.cs to obtain IConfiguration (builder.Configuration) and use
configuration["AllowedOrigins"]?.Split(';') (or similar) when building the
policy so origins are configurable per environment, and add the AllowedOrigins
key to appsettings.json (and override in production secrets/ENV as needed).
- Line 64: The code currently sets options.RequireHttpsMetadata = false; which
should be true in production—change it to read from environment or config and
enable it for production, e.g. use builder.Environment.IsProduction() or an
IConfiguration key to set options.RequireHttpsMetadata (referencing
options.RequireHttpsMetadata, builder.Environment.IsProduction(),
IConfiguration/Settings) so non-prod can remain false while production is true;
update Program.cs to set the value from the environment/config and document the
required production setting.

In `@Backend/Backend/Services/GitHubService.cs`:
- Around line 40-44: Wrap the HTTP calls in the GitHubService methods (the
method that calls _httpClient.SendAsync and response.Content.ReadFromJsonAsync
to return result?.AccessToken, and similarly GetGitHubUser and
GetSuggestedIssues) in a try-catch that catches HttpRequestException,
TaskCanceledException, and JsonException; inside the catch log the exception via
the service logger or _logger with contextual messages and return null (or an
appropriate failure value) instead of allowing exceptions to propagate. Ensure
you wrap the calls to _httpClient.SendAsync(...) and
response.Content.ReadFromJsonAsync<T>(...) specifically, handle each exception
type generically (same remediation), and keep the existing null-return behavior
on failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 972a0602-8f81-4ff4-ad68-11f9358e4f1a

📥 Commits

Reviewing files that changed from the base of the PR and between ed64b0e and c753130.

📒 Files selected for processing (12)
  • Backend/Backend/Backend.csproj
  • Backend/Backend/Controllers/AuthController.cs
  • Backend/Backend/Controllers/IssuesController.cs
  • Backend/Backend/Controllers/UsersController.cs
  • Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.Designer.cs
  • Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs
  • Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs
  • Backend/Backend/Models/GitQuestContext.cs
  • Backend/Backend/Models/GitQuestContextFactory.cs
  • Backend/Backend/Program.cs
  • Backend/Backend/Services/GitHubService.cs
  • Backend/Backend/appsettings.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • Backend/Backend/appsettings.json

@jaseel0
Copy link
Collaborator Author

jaseel0 commented Mar 15, 2026

@copilot fix the all problem coderabbit mention

Copy link
Contributor

Copilot AI commented Mar 15, 2026

@jaseel0 I've opened a new pull request, #24, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 15, 2026 13:46
fix: config key mismatch and safe Guid parsing in backend controllers
Copy link

@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: 1

🧹 Nitpick comments (2)
Backend/Backend/Controllers/IssuesController.cs (1)

26-33: Unnecessary null check.

GetSuggestedIssues returns new List<Issue>() on failure, never null. The null check at line 31 is dead code.

♻️ Optional cleanup
     [HttpGet("discover")]
     [AllowAnonymous]
     public async Task<IActionResult> GetIssues([FromQuery] string language = "typescript")
     {
         var issues = await _githubService.GetSuggestedIssues(language);
-        if (issues == null) return BadRequest("Could not fetch issues.");
         return Ok(issues);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/IssuesController.cs` around lines 26 - 33, The
null check in GetIssues is unnecessary because
_githubService.GetSuggestedIssues(language) never returns null (it returns an
empty List<Issue> on failure); remove the dead if (issues == null) return
BadRequest(...) branch in the GetIssues method and simply return Ok(issues)
after awaiting GetSuggestedIssues, leaving any handling of an empty list to
callers or implement a check for issues.Count == 0 if you want to return a
different response.
Backend/Backend/Services/GitHubService.cs (1)

13-18: Use AddHttpClient<GitHubService>() for proper HttpClient lifecycle management.

Currently, GitHubService is registered with AddScoped<GitHubService>() at line 48 of Program.cs, which bypasses IHttpClientFactory lifecycle management. This can lead to socket exhaustion and poor DNS rotation under load.

Change the registration to:

builder.Services.AddHttpClient<GitHubService>();

This automatically registers GitHubService as scoped while ensuring HttpClient lifecycle is managed correctly through the factory's socket pooling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Services/GitHubService.cs` around lines 13 - 18, The service
registration currently uses AddScoped for GitHubService which bypasses
IHttpClientFactory; update the DI registration to use
AddHttpClient<GitHubService>() so the HttpClient injected into the
GitHubService(HttpClient httpClient, IConfiguration config) constructor is
managed by IHttpClientFactory (ensuring proper socket pooling and DNS rotation)
and remove or replace the existing AddScoped<GitHubService>() registration
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/Backend/Controllers/IssuesController.cs`:
- Around line 110-144: The code assumes user is non-null and still returns "XP
Awarded!" even when _context.Users.FindAsync(userId) yields null; change the
flow to treat a missing user as an error: after calling var user = await
_context.Users.FindAsync(userId) check if user == null and immediately return an
error response (e.g., NotFound or BadRequest) without modifying anything or
calling _context.SaveChangesAsync(), and only perform the XP/streak update, set
user.LastContributionDate, call _context.SaveChangesAsync(), and return Ok(...)
when user is present; update references around user.ExperiencePoints,
CurrentStreak, and LastContributionDate accordingly so they are only accessed
when user != null.

---

Nitpick comments:
In `@Backend/Backend/Controllers/IssuesController.cs`:
- Around line 26-33: The null check in GetIssues is unnecessary because
_githubService.GetSuggestedIssues(language) never returns null (it returns an
empty List<Issue> on failure); remove the dead if (issues == null) return
BadRequest(...) branch in the GetIssues method and simply return Ok(issues)
after awaiting GetSuggestedIssues, leaving any handling of an empty list to
callers or implement a check for issues.Count == 0 if you want to return a
different response.

In `@Backend/Backend/Services/GitHubService.cs`:
- Around line 13-18: The service registration currently uses AddScoped for
GitHubService which bypasses IHttpClientFactory; update the DI registration to
use AddHttpClient<GitHubService>() so the HttpClient injected into the
GitHubService(HttpClient httpClient, IConfiguration config) constructor is
managed by IHttpClientFactory (ensuring proper socket pooling and DNS rotation)
and remove or replace the existing AddScoped<GitHubService>() registration
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23a803c7-dc6c-4e94-a0fb-1155220594ed

📥 Commits

Reviewing files that changed from the base of the PR and between 57ccd91 and 9b19beb.

📒 Files selected for processing (3)
  • Backend/Backend/Controllers/AuthController.cs
  • Backend/Backend/Controllers/IssuesController.cs
  • Backend/Backend/Services/GitHubService.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Backend/Backend/Controllers/AuthController.cs

@jaseel0
Copy link
Collaborator Author

jaseel0 commented Mar 15, 2026

@copilot fix the all problem coderabbit mention

Copy link
Contributor

Copilot AI commented Mar 15, 2026

@jaseel0 I've opened a new pull request, #25, to work on those changes. Once the pull request is ready, I'll request review from you.

fix: address remaining CodeRabbit review issues in backend
Copy link

@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.

♻️ Duplicate comments (2)
Backend/Backend/Controllers/IssuesController.cs (2)

62-70: ⚠️ Potential issue | 🟠 Major

Only map duplicate-claim violations to 409.

DbUpdateException here also covers FK failures and transient SQL errors, so callers can get "Quest already active." even when the claim never persisted. Filter this catch to the unique-constraint case for your SQL Server provider and let unrelated database failures surface normally.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Controllers/IssuesController.cs` around lines 62 - 70, The
catch for DbUpdateException in IssuesController around the call to
_context.SaveChangesAsync() should only translate unique-constraint violations
to 409; change the handler to inspect the DbUpdateException's inner exception
(SqlException from System.Data.SqlClient or Microsoft.Data.SqlClient) and check
the SQL Server error numbers for duplicate key (usually 2601 and 2627) before
returning Conflict("Quest already active."); for other DbUpdateException cases
rethrow the exception (throw;) so FK failures and transient errors surface
normally.

98-115: ⚠️ Potential issue | 🔴 Critical

submit still lets clients self-complete quests.

This path awards XP as soon as an In Progress quest exists. A caller can claim an issue and immediately submit it with no persisted contribution/proof, and parallel submits can race the same status transition. Require a verified contribution record and make the In Progress -> Completed update atomic before applying rewards.

🧹 Nitpick comments (1)
Backend/Backend/Program.cs (1)

82-89: Externalize the allowed CORS origins.

Hard-coding http://localhost:3000 means every non-local frontend origin needs a code change and redeploy before browser calls will work. Move the origin list into configuration so dev/staging/prod can diverge safely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Backend/Program.cs` around lines 82 - 89, Replace the hard-coded
origin in the CORS policy by reading allowed origins from configuration: change
the builder.Services.AddCors(...) usage that defines "GitQuestPolicy" so
policy.WithOrigins(...) receives an array sourced from configuration (e.g.,
builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>() or a
comma-split value), and update appsettings (appsettings.Development/Production)
to list the allowed origins; ensure null/empty handling (fall back to no origins
or throw) and keep AllowAnyHeader/AllowAnyMethod as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Backend/Backend/Controllers/IssuesController.cs`:
- Around line 62-70: The catch for DbUpdateException in IssuesController around
the call to _context.SaveChangesAsync() should only translate unique-constraint
violations to 409; change the handler to inspect the DbUpdateException's inner
exception (SqlException from System.Data.SqlClient or Microsoft.Data.SqlClient)
and check the SQL Server error numbers for duplicate key (usually 2601 and 2627)
before returning Conflict("Quest already active."); for other DbUpdateException
cases rethrow the exception (throw;) so FK failures and transient errors surface
normally.

---

Nitpick comments:
In `@Backend/Backend/Program.cs`:
- Around line 82-89: Replace the hard-coded origin in the CORS policy by reading
allowed origins from configuration: change the builder.Services.AddCors(...)
usage that defines "GitQuestPolicy" so policy.WithOrigins(...) receives an array
sourced from configuration (e.g.,
builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>() or a
comma-split value), and update appsettings (appsettings.Development/Production)
to list the allowed origins; ensure null/empty handling (fall back to no origins
or throw) and keep AllowAnyHeader/AllowAnyMethod as-is.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 24a988a4-bc07-40b9-b4b2-2d1b50542e66

📥 Commits

Reviewing files that changed from the base of the PR and between 9b19beb and 17bceb5.

📒 Files selected for processing (5)
  • Backend/Backend/Controllers/IssuesController.cs
  • Backend/Backend/Migrations/20260315082912_InitialCreate.Designer.cs
  • Backend/Backend/Migrations/20260315082912_InitialCreate.cs
  • Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs
  • Backend/Backend/Program.cs
🚧 Files skipped from review as they are similar to previous changes (2)
  • Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs
  • Backend/Backend/Migrations/20260315082912_InitialCreate.Designer.cs

@naheel0 naheel0 merged commit 85d3d4d into main Mar 15, 2026
11 checks passed
@naheel0 naheel0 deleted the backend branch March 15, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration Configuration file changes feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants