Skip to content

js->ts#3112

Merged
ajhollid merged 1 commit intodevelopfrom
fix/status-page-controller
Jan 9, 2026
Merged

js->ts#3112
ajhollid merged 1 commit intodevelopfrom
fix/status-page-controller

Conversation

@ajhollid
Copy link
Collaborator

@ajhollid ajhollid commented Jan 9, 2026

Convert StatusPageController to TS

Summary by CodeRabbit

  • Refactor
    • Refactored the status page management module with modernized infrastructure improvements. The system now uses TypeScript for enhanced type safety and improved code reliability. Dependency injection mechanisms have been carefully optimized to streamline internal architecture while maintaining complete compatibility with all existing status page operations, including creation, updates, retrieval, and deletion functions.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

Note

.coderabbit.yml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'release_notes'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

A JavaScript StatusPageController file is migrated to TypeScript while its dependency injection is updated from commonDependencies to services.db in the configuration layer. The controller's CRUD methods remain functionally equivalent.

Changes

Cohort / File(s) Summary
Controller Migration to TypeScript
server/src/controllers/v1/statusPageController.js, server/src/controllers/v1/statusPageController.ts
Removed JavaScript implementation (108 lines) and introduced TypeScript equivalent (109 lines) with identical CRUD operations: createStatusPage, updateStatusPage, getStatusPage, getStatusPageByUrl, getStatusPagesByTeamId, deleteStatusPage. Maintains request validation, error handling, and response patterns.
Dependency Injection Update
server/src/config/controllers.js
Changed StatusPageController instantiation argument from commonDependencies to services.db as the sole constructor parameter.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 From scripts to types, a hoppy migration,
TypeScript's strong arms hold our station,
Simpler deps, cleaner embrace,
One controller hops to its new place! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is significantly incomplete, missing most required checklist items and detailed change information compared to the template. Fill out the complete PR template including the issue number, all required checkboxes (local deployment and self-review), and any i18n/formatting details.
Title check ❓ Inconclusive The title 'js->ts' is vague and generic, using non-descriptive notation that doesn't clearly convey what file or component is being converted. Use a more descriptive title like 'Convert StatusPageController from JavaScript to TypeScript' to clearly indicate the specific change.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

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: 4

🤖 Fix all issues with AI agents
In @server/src/controllers/v1/statusPageController.ts:
- Around line 19-38: The controller uses req.user in createStatusPage but
Express Request lacks a user property; add a module augmentation file (e.g.,
express.d.ts) that extends the 'express-serve-static-core' Request interface to
include user?: { _id: string; teamId: string; /* other props */ }, ensure the
file is included by tsconfig.json (or add it to the "types"/"include"), then
recompile to let TypeScript validate accesses to req.user in createStatusPage
and other handlers.
- Around line 10-13: Replace the loose any on the controller's db property and
constructor parameter by declaring a proper interface/type that models the DB
dependency (e.g., an interface with a statusPageModule field or the existing
StatusPageModule type if available) and use that type for the private db
property and constructor param in the StatusPageController class; define the
interface in a shared types file or at top of this module and import existing
module types if present so references to statusPageModule methods are
type-checked.
- Around line 97-106: deleteStatusPage uses req.params.url without validating
it; mirror the validation from getStatusPageByUrl by checking req.params.url
before calling this.db.statusPageModule.deleteStatusPage. If url is missing or
invalid, return a 400 response (or call next with a validation error) and avoid
calling deleteStatusPage; otherwise proceed with the deletion and the existing
200 response. Use the same validation helper or logic used by getStatusPageByUrl
to keep behavior consistent.
- Around line 70-83: The getStatusPageByUrl handler validates req.query
(getStatusPageQueryValidation) but never uses it; either pass the validated
query values (e.g., type and optional timeFrame from req.query) into
this.db.statusPageModule.getStatusPageByUrl (update the call and, if needed, the
module method signature in statusPageModule to accept { url, type, timeFrame })
or remove the getStatusPageQueryValidation.validateAsync(req.query) line and any
related query schema if the query is not needed; ensure you reference the
validated values (use the result of validateAsync or req.query) when calling
getStatusPageByUrl so validation is not wasted.
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7ad3c0 and 1d7f3b1.

📒 Files selected for processing (3)
  • server/src/config/controllers.js
  • server/src/controllers/v1/statusPageController.js
  • server/src/controllers/v1/statusPageController.ts
💤 Files with no reviewable changes (1)
  • server/src/controllers/v1/statusPageController.js
🧰 Additional context used
🧬 Code graph analysis (2)
server/src/config/controllers.js (1)
server/src/config/services.js (1)
  • services (225-246)
server/src/controllers/v1/statusPageController.ts (1)
server/src/validation/joi.js (3)
  • createStatusPageBodyValidation (453-484)
  • getStatusPageParamValidation (444-446)
  • getStatusPageQueryValidation (448-451)
🔇 Additional comments (1)
server/src/config/controllers.js (1)

48-48: Constructor change is correct and safe.

The controller only requires the db dependency. It does not use errorService, logger, or stringService from the previous commonDependencies, so removing them has no impact on functionality.

Comment on lines +10 to +13
private db: any;
constructor(db: any) {
this.db = db;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Type the db parameter properly instead of using any.

Using any defeats the purpose of TypeScript migration. The db object has a known structure with a statusPageModule property. Consider creating a proper interface or type for the database dependency.

🔷 Suggested type-safe approach

Create a type or interface for the database:

+interface Database {
+  statusPageModule: {
+    createStatusPage: (params: any) => Promise<any>;
+    updateStatusPage: (body: any, file: any) => Promise<any>;
+    getStatusPage: () => Promise<any>;
+    getStatusPageByUrl: (url: string) => Promise<any>;
+    getStatusPagesByTeamId: (teamId: string) => Promise<any>;
+    deleteStatusPage: (url: string) => Promise<void>;
+  };
+}
+
 class StatusPageController {
 	static SERVICE_NAME = SERVICE_NAME;
-	private db: any;
-	constructor(db: any) {
+	private db: Database;
+	constructor(db: Database) {
 		this.db = db;
 	}
📝 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
private db: any;
constructor(db: any) {
this.db = db;
}
interface Database {
statusPageModule: {
createStatusPage: (params: any) => Promise<any>;
updateStatusPage: (body: any, file: any) => Promise<any>;
getStatusPage: () => Promise<any>;
getStatusPageByUrl: (url: string) => Promise<any>;
getStatusPagesByTeamId: (teamId: string) => Promise<any>;
deleteStatusPage: (url: string) => Promise<void>;
};
}
class StatusPageController {
static SERVICE_NAME = SERVICE_NAME;
private db: Database;
constructor(db: Database) {
this.db = db;
}
🤖 Prompt for AI Agents
In @server/src/controllers/v1/statusPageController.ts around lines 10 - 13,
Replace the loose any on the controller's db property and constructor parameter
by declaring a proper interface/type that models the DB dependency (e.g., an
interface with a statusPageModule field or the existing StatusPageModule type if
available) and use that type for the private db property and constructor param
in the StatusPageController class; define the interface in a shared types file
or at top of this module and import existing module types if present so
references to statusPageModule methods are type-checked.

Comment on lines +19 to +38
createStatusPage = async (req: Request, res: Response, next: NextFunction) => {
try {
await createStatusPageBodyValidation.validateAsync(req.body);
await imageValidation.validateAsync(req.file);

const { _id, teamId } = req.user;
const statusPage = await this.db.statusPageModule.createStatusPage({
statusPageData: req.body,
image: req.file,
userId: _id,
teamId,
});
return res.status(200).json({
msg: "Status page created successfully",
data: statusPage,
});
} catch (error) {
next(error);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Extend the Express Request type to include the user property.

Line 24 accesses req.user._id and req.user.teamId, but the Express Request type doesn't include a user property by default. TypeScript won't catch runtime errors if req.user is undefined.

🔷 Add type declarations for req.user

Create a type declaration file (e.g., server/src/types/express.d.ts):

import { Request } from 'express';

declare module 'express-serve-static-core' {
  interface Request {
    user?: {
      _id: string;
      teamId: string;
      // Add other user properties as needed
    };
  }
}

Then ensure this declaration is included in your tsconfig.json.

🤖 Prompt for AI Agents
In @server/src/controllers/v1/statusPageController.ts around lines 19 - 38, The
controller uses req.user in createStatusPage but Express Request lacks a user
property; add a module augmentation file (e.g., express.d.ts) that extends the
'express-serve-static-core' Request interface to include user?: { _id: string;
teamId: string; /* other props */ }, ensure the file is included by
tsconfig.json (or add it to the "types"/"include"), then recompile to let
TypeScript validate accesses to req.user in createStatusPage and other handlers.

Comment on lines +70 to +83
getStatusPageByUrl = async (req: Request, res: Response, next: NextFunction) => {
try {
await getStatusPageParamValidation.validateAsync(req.params);
await getStatusPageQueryValidation.validateAsync(req.query);

const statusPage = await this.db.statusPageModule.getStatusPageByUrl(req.params.url);
return res.status(200).json({
msg: "Status page retrieved successfully",
data: statusPage,
});
} catch (error) {
next(error);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the statusPageModule implementation
fd -t f -e ts -e js | grep -i "module\|service" | grep -i "status" | head -20

Repository: bluewave-labs/Checkmate

Length of output: 165


🏁 Script executed:

#!/bin/bash
# Search for statusPageModule definition and getStatusPageByUrl implementation
rg "statusPageModule|getStatusPageByUrl" -t ts --max-count 20

Repository: bluewave-labs/Checkmate

Length of output: 975


🏁 Script executed:

#!/bin/bash
# Look at the controllers directory structure
find server/src/controllers -type f -name "*.ts" | head -10

Repository: bluewave-labs/Checkmate

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Read the statusPageModule to understand getStatusPageByUrl implementation
cat server/src/db/v1/modules/statusPageModule.js

Repository: bluewave-labs/Checkmate

Length of output: 7100


🏁 Script executed:

#!/bin/bash
# Read the statusPageController to see validation definitions and full context
cat server/src/controllers/v1/statusPageController.ts

Repository: bluewave-labs/Checkmate

Length of output: 3147


🏁 Script executed:

#!/bin/bash
# Find the validation definitions
fd -t f -name "joi.js" -o -name "joi.ts"

Repository: bluewave-labs/Checkmate

Length of output: 297


🏁 Script executed:

#!/bin/bash
# Search for getStatusPageQueryValidation definition
rg "getStatusPageQueryValidation" -A 5 -B 2

Repository: bluewave-labs/Checkmate

Length of output: 2437


Query parameters validated but never used.

Line 73 validates req.query expecting required type ("uptime") and optional timeFrame parameters, but these values are never passed to this.db.statusPageModule.getStatusPageByUrl() on line 75. The method only receives req.params.url.

Either pass the query parameters to the module method or remove the unnecessary validation on line 73.

🤖 Prompt for AI Agents
In @server/src/controllers/v1/statusPageController.ts around lines 70 - 83, The
getStatusPageByUrl handler validates req.query (getStatusPageQueryValidation)
but never uses it; either pass the validated query values (e.g., type and
optional timeFrame from req.query) into
this.db.statusPageModule.getStatusPageByUrl (update the call and, if needed, the
module method signature in statusPageModule to accept { url, type, timeFrame })
or remove the getStatusPageQueryValidation.validateAsync(req.query) line and any
related query schema if the query is not needed; ensure you reference the
validated values (use the result of validateAsync or req.query) when calling
getStatusPageByUrl so validation is not wasted.

Comment on lines +97 to +106
deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
try {
await this.db.statusPageModule.deleteStatusPage(req.params.url);
return res.status(200).json({
msg: "Status page deleted successfully",
});
} catch (error) {
next(error);
}
};
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

Missing parameter validation in deleteStatusPage.

Line 99 uses req.params.url without validation, while other methods like getStatusPageByUrl (line 72) validate parameters before use. This inconsistency could lead to issues if req.params.url is undefined or invalid.

➕ Add parameter validation
 deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
 	try {
+		await getStatusPageParamValidation.validateAsync(req.params);
 		await this.db.statusPageModule.deleteStatusPage(req.params.url);
 		return res.status(200).json({
 			msg: "Status page deleted successfully",
 		});
 	} catch (error) {
 		next(error);
 	}
 };
📝 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
deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
try {
await this.db.statusPageModule.deleteStatusPage(req.params.url);
return res.status(200).json({
msg: "Status page deleted successfully",
});
} catch (error) {
next(error);
}
};
deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
try {
await getStatusPageParamValidation.validateAsync(req.params);
await this.db.statusPageModule.deleteStatusPage(req.params.url);
return res.status(200).json({
msg: "Status page deleted successfully",
});
} catch (error) {
next(error);
}
};
🤖 Prompt for AI Agents
In @server/src/controllers/v1/statusPageController.ts around lines 97 - 106,
deleteStatusPage uses req.params.url without validating it; mirror the
validation from getStatusPageByUrl by checking req.params.url before calling
this.db.statusPageModule.deleteStatusPage. If url is missing or invalid, return
a 400 response (or call next with a validation error) and avoid calling
deleteStatusPage; otherwise proceed with the deletion and the existing 200
response. Use the same validation helper or logic used by getStatusPageByUrl to
keep behavior consistent.

@ajhollid ajhollid merged commit 11e3cac into develop Jan 9, 2026
8 checks passed
Copy link

@llamapreview llamapreview bot left a comment

Choose a reason for hiding this comment

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

AI Code Review by LlamaPReview

🎯 TL;DR & Recommendation

Recommendation: Request Changes

This PR converts the controller to TypeScript but introduces critical breaking changes to its constructor and error handling mechanisms, potentially disrupting existing integrations and observability.

Priority File Category Impact Summary (≤12 words) Anchors
P1 controllers/v1/.../statusPageController.ts Architecture Breaking constructor change risks runtime failures and loss of BaseController features.
P1 controllers/v1/.../statusPageController.ts Maintainability Manual error handling reduces debugging ability and breaks observability patterns.
P2 controllers/v1/.../statusPageController.ts Maintainability any type on db dependency negates TypeScript benefits, risking runtime errors.
P2 controllers/v1/.../statusPageController.ts Architecture Direct req.user access without type checking may cause runtime errors. method:createStatusPage
P2 controllers/v1/.../statusPageController.ts Correctness and Business Logic Lack of URL validation in delete method may cause database errors. method:deleteStatusPage

🔍 Notable Themes

  • Architectural Inconsistency: The refactor breaks away from established patterns like BaseController inheritance and common dependency injection, increasing integration risks.
  • Compromised Type Safety: Several changes undermine TypeScript's benefits, such as using any types and unsafe type assertions, which could lead to runtime issues.

📈 Risk Diagram

This diagram illustrates the risks associated with the breaking constructor change and manual error handling in the status page controller.

sequenceDiagram
participant A as Client
participant E as Express App
participant C as StatusPageController
participant D as Database
A->>E: HTTP Request
E->>C: Instantiate with services.db
note over C: R1(P1): Breaking constructor change risks runtime failures for direct instantiations
C->>D: Call db.statusPageModule.method
alt Error occurs
    C-->>E: Error passed via next(error)
    note over C: R2(P1): Manual error handling loses service context and logging
end
E-->>A: Response
Loading

💡 Have feedback? We'd love to hear it in our GitHub Discussions.
✨ This review was generated by LlamaPReview Advanced, which is free for all open-source projects. Learn more.

Comment on lines +8 to +13
class StatusPageController {
static SERVICE_NAME = SERVICE_NAME;
private db: any;
constructor(db: any) {
this.db = db;
}
Copy link

Choose a reason for hiding this comment

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

P1 | Confidence: High

The controller's constructor signature has been changed from accepting commonDependencies to a single db: any parameter. This is a breaking change to the public API of StatusPageController. The instantiation in controllers.js confirms this change (new StatusPageController(services.db)). Any existing code that instantiates this controller directly (e.g., in tests, other configs, or via dynamic imports) will now fail because it expects the old signature. Furthermore, the class no longer extends BaseController, stripping it of all inherited functionality (like this.errorService, this.stringService, and the centralized asyncHandler). This loss is evident in the new method implementations, which now handle errors and responses manually. The change violates the established architectural pattern (dependency injection via commonDependencies and inheritance from BaseController) used by all other controllers in the codebase.

Suggested change
class StatusPageController {
static SERVICE_NAME = SERVICE_NAME;
private db: any;
constructor(db: any) {
this.db = db;
}
import BaseController from "./baseController.js"; // Ensure the import path is correct
const SERVICE_NAME = "statusPageController";
class StatusPageController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies) {
super(commonDependencies);
}

}
};

updateStatusPage = async (req: Request, res: Response, next: NextFunction) => {
Copy link

Choose a reason for hiding this comment

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

P1 | Confidence: High

The original asyncHandler utility (from BaseController) provided a standard, centralized mechanism for error handling and logging. Its removal introduces inconsistent, manual try-catch blocks that must be replicated in every method. More critically, it has broken the structured error logging and service attribution. The old asyncHandler took SERVICE_NAME and the method name ("updateStatusPage") as parameters, which was presumably used for logging and error context. This information is now lost, making debugging and observability significantly harder. The error messages are also hardcoded (e.g., "Status page not found"), deviating from the pattern of using a string service (this.stringService) for internationalization or centralized message management.

Comment on lines +10 to +13
private db: any;
constructor(db: any) {
this.db = db;
}
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: High

The db dependency is typed as any, which defeats a primary benefit of converting to TypeScript: type safety and improved developer experience (autocompletion, refactoring). The db object likely has a defined shape (e.g., containing a statusPageModule). Using any means the compiler cannot catch typos (e.g., statusPageModuel) or validate the structure of calls to this.db.statusPageModule.*. This increases the risk of runtime errors that would have been caught at compile time with proper typing.

Code Suggestion:

interface DatabaseService {
    statusPageModule: {
        createStatusPage: (params: any) => Promise<any>;
        updateStatusPage: (data: any, file: any) => Promise<any | null>;
        // ... other methods
    };
}

private db: DatabaseService;
constructor(db: DatabaseService) {
    this.db = db;
}

return StatusPageController.SERVICE_NAME;
}

createStatusPage = async (req: Request, res: Response, next: NextFunction) => {
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: High

The method directly destructures req.user ({ _id, teamId }) without any prior null/type checking. While this may be safe if an authentication middleware always populates req.user, TypeScript does not know this. The Request type from express does not have a standard user property. This creates a type safety issue; the code will compile but could fail at runtime if the middleware chain changes. It also reduces code clarity for developers unfamiliar with the project's middleware setup.

Code Suggestion:

// Option: Type assertion (if confident)
const user = req.user as { _id: string; teamId: string }; // or a proper User type
const { _id, teamId } = user;
// Or, a runtime check for safety in development
if (!req.user) {
    throw new Error('Authentication middleware failed to set req.user');
}

Evidence: method:createStatusPage, search:req.user

Comment on lines +97 to +106
deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
try {
await this.db.statusPageModule.deleteStatusPage(req.params.url);
return res.status(200).json({
msg: "Status page deleted successfully",
});
} catch (error) {
next(error);
}
};
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: Medium

Speculative: The deleteStatusPage method does not validate req.params.url before passing it to the database module. The old JavaScript file showed that getStatusPageByUrl used getStatusPageParamValidation.validateAsync(req.params). It's plausible that deleteStatusPage should also validate its parameter (the URL) for format, length, or safety to prevent malformed queries or potential injection vectors at the application layer. The absence of validation here is inconsistent with the pattern used in getStatusPageByUrl and could lead to unexpected database errors or behavior.

Code Suggestion:

deleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {
    try {
        await getStatusPageParamValidation.validateAsync(req.params); // Re-use the same validation
        await this.db.statusPageModule.deleteStatusPage(req.params.url);
        return res.status(200).json({
            msg: "Status page deleted successfully",
        });
    } catch (error) {
        next(error);
    }
};

Evidence: method:deleteStatusPage

@ajhollid ajhollid deleted the fix/status-page-controller branch January 21, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant