Skip to content

Aditya-feat: Phase 2 - API for interactive list of open issues with filters and actions#2032

Open
Aditya-gam wants to merge 24 commits intodevelopmentfrom
fix/Create_an_interactive_list_of_open_issues
Open

Aditya-feat: Phase 2 - API for interactive list of open issues with filters and actions#2032
Aditya-gam wants to merge 24 commits intodevelopmentfrom
fix/Create_an_interactive_list_of_open_issues

Conversation

@Aditya-gam
Copy link
Contributor

@Aditya-gam Aditya-gam commented Feb 6, 2026

Description

This PR implements the interactive list of open issues feature for the Building Management (BM) dashboard.

IssueDescription BackendRequirements1 BackendRequirments2

It adds a dedicated API surface under /api/bm to fetch open issues with optional filters (projects, date range, tag), to rename/close/reopen/delete issues, and to list projects for dropdowns. Date filtering follows “ongoing during range” semantics (issues open at any time in the range, using createdDate and closedDate). The status enum is corrected from 'close' to 'closed', issueDate is stored as a Date, and closedDate is set/cleared automatically on close/reopen. The issue chart endpoint is updated to use issueDate (Date) for year filtering. Comprehensive unit tests for the BM issue controller and an automated API test script (with report and verification doc) are included.

Related PRs (if any):

Main changes explained:

Created/Updated Files:

  • src/controllers/bmdashboard/bmIssueController.js

    • bmGetOpenIssue: Builds a query with optional projectIds (comma-separated, validated ObjectIds), startDate, endDate, and tag. With no date filter, returns only status: 'open'. With date range: “ongoing during range” — createdDate <= endDate and either status === 'open' or closedDate >= startDate. Uses endOfDay from date-fns for end date. Returns array or [].
    • bmUpdateIssue: Validates body is an object; on status: 'closed' sets closedDate = new Date(); on status: 'open' sets closedDate = null. Uses findByIdAndUpdate with $set, returns 404 when the issue is not found, 400 for invalid update data.
    • bmDeleteIssue: findByIdAndDelete; 404 with { message: 'Issue not found.' } when not found, 200 with { message: 'Issue deleted successfully.' } on success.
    • bmGetIssueChart: Filtering by issueType and year applied via matchQuery; year filter uses issueDate (Date) with $gte/$lte for Jan 1–Dec 31 of given year. Aggregation groups by issueType and year, returns a formatted object { [issueType]: { [year]: count } }.
    • getUniqueProjectIds: Unchanged in behavior; returns { projectId, projectName } from aggregation + lookup on buildingProjects. Other handlers: bmPostIssue, bmGetIssue, getLongestOpenIssues retained.
  • src/models/bmdashboard/buildingIssue.js

    • issueDate: Type changed from String to Date, required.
    • closedDate: New field { type: Date, default: null } for close/reopen tracking.
    • status: Enum corrected from 'close' to 'closed'; allowed values ['open', 'closed'].
    • person: Added { name: String, role: String } subdocument.
    • createdDate: Already present; used in open-issues date filtering.
  • src/routes/bmdashboard/bmIssueRouter.js

    • Routes under BM router: GET /issues/openbmGetOpenIssue; POST /issue/addbmPostIssue; PATCH /issues/:idbmUpdateIssue; DELETE /issues/:idbmDeleteIssue; GET /issues/projectsgetUniqueProjectIds; GET /issuesbmGetIssue; GET /issue/issue-chartbmGetIssueChart; GET /issues/longest-opengetLongestOpenIssues. Route order/registration clarified (no path changes).
  • src/startup/routes.js

    • Blank line added for readability; buildingIssue and bmIssueRouter were already required and mounted at app.use('/api/bm', bmIssueRouter).
  • src/controllers/bmdashboard/__tests__/bmIssueController.test.js

    • bmGetOpenIssue: No filters (status 'open' only); empty result; filter by projectIds (valid/invalid/combined); startDate+endDate, startDate only, endDate only; “ongoing during range” cases (created before range still open, closed during range, not closed before range, created during range); tag filter; combined filters; 500 on DB error.
    • getUniqueProjectIds: Success, null/undefined projectName → "Unknown Project", empty array, 500.
    • bmUpdateIssue: Success (including closed → closedDate set, open → closedDate null); 400 invalid body; 404 not found; 500 on error.
    • bmDeleteIssue: Success; 404 not found; 500 on error.
    • bmGetIssueChart: By issueType, by year, both, neither; result shape; 500 on error.
    • bmPostIssue, bmGetIssue, getLongestOpenIssues: Covered. Overall controller test coverage raised to ~99%.

Key Implementation Details:

  • Date “ongoing during range”: For startDate and endDate, an issue is included if createdDate <= endOfDay(endDate) and either status === 'open' or closedDate >= startDate. For startDate only: status === 'open' or closedDate >= startDate. For endDate only: createdDate <= endOfDay(endDate) (no status filter). No date filter ⇒ only status: 'open'.
  • closedDate: Set to new Date() when PATCH sets status: 'closed'; set to null when PATCH sets status: 'open'. Enables correct date-range filtering and audit.
  • Chart: bmGetIssueChart uses issueDate (Date) for year filter; aggregation groups by issueType and year, returns { [issueType]: { [year]: count } }.
  • Validation: projectIds parsed and validated with ObjectId.isValid; invalid IDs dropped. Update body must be a non-null object. 404 for missing issue on PATCH/DELETE; 400 for invalid update data.

How to test:

  1. Check out the branch: fix/Create_an_interactive_list_of_open_issues
  2. Reinstall dependencies and clean cache using rm -rf node_modules package-lock.json && npm cache clean --force
  3. Run npm install to install dependencies, then start the backend locally (npm run dev)
  4. Test open issues API:
    • GET open (no filters):
      GET http://localhost:4500/api/bm/issues/open
      Header: Authorization: <valid JWT>
      Expect: 200, JSON array of open issues (or []).
    • GET open (filters):
      GET http://localhost:4500/api/bm/issues/open?projectIds=65419e61105441587e2dec99&startDate=2024-01-01&endDate=2024-12-31&tag=In-person
      Expect: 200, array of issues ongoing in range and matching project/tag.
    • GET projects:
      GET http://localhost:4500/api/bm/issues/projects
      Expect: 200, array of { projectId, projectName }.
    • PATCH close:
      PATCH http://localhost:4500/api/bm/issues/<id>
      Body: { "status": "closed" }
      Expect: 200, body includes status: "closed" and closedDate set.
    • PATCH reopen:
      Body: { "status": "open" }
      Expect: 200, closedDate null.
    • PATCH rename:
      Body: { "issueTitle": ["New title"] }
      Expect: 200, updated issue with new title.
    • DELETE:
      DELETE http://localhost:4500/api/bm/issues/<id>
      Expect: 200 with { message: "Issue deleted successfully." } or 404 with { message: "Issue not found." }.
  5. Auth/errors:
    • Omit Authorization or use an invalid JWT on GET open or GET projects → 401.
    • PATCH/DELETE with non-existent but valid ObjectId → 404, message: "Issue not found."
  6. Unit tests:
    • npm test -- --testPathPattern=bmIssueController (or project’s Jest config for unit tests)

Screenshots or videos of changes:

  • API Endpoint Tests:
EndpointTests
  • Test video:
TestVideo.mov

Note:

  • Breaking Changes: If any client used status: 'close' or string issueDate, they must switch to 'closed' and Date/ISO string for issueDate.
  • Database Changes: No migrations. Schema change is additive/compatible: closedDate (default null), issueDate as Date, status enum ['open','closed'], person subdocument. Existing documents may need a one-time fix if they are stored status: 'close' or string issueDate (handled by app logic where applicable).
  • Performance Considerations: Open-issues query uses indexed fields where available (projectId, status, createdDate, closedDate, tag).
  • Validation: projectIds filtered to valid ObjectIds; invalid IDs ignored. PATCH body must be an object; 400 otherwise. Model validation (required fields, enums) applies to POST and on PATCH updates.

vamsikrishna1704 and others added 23 commits May 9, 2025 13:15
- Fixes grammatical error in status enum value
- Maintains compatibility with original schema from development branch
- Resolves validation errors for existing documents with status='closed'
- Aligns with standard REST API conventions

The incorrect enum value 'close' (verb) has been changed to 'closed'
(past participle), which is the grammatically correct form and matches
the original implementation before this feature branch.
- Fixes aggregation pipeline errors in bmGetIssueChart controller
- Enables proper use of $year operator (line 176) which requires Date type
- Resolves incorrect date comparisons using $gte/$lte operators
- Ensures chronological sorting instead of lexicographic string sorting
- Improves type safety and prevents invalid date strings

The String type was causing the $year aggregation to return null values,
resulting in empty chart data. Date type enables proper date operations
and maintains compatibility with MongoDB date operators.
…er functions

- Add 46 comprehensive tests covering all 8 controller functions
- Test bmGetOpenIssue with projectIds, date range, and tag filters
- Test getUniqueProjectIds aggregation and Unknown Project fallback
- Test bmUpdateIssue validation, 400/404/500 error handling
- Test bmDeleteIssue success and error paths
- Test bmGetIssueChart with issueType and year filters
- Test getLongestOpenIssues with date/project filtering and sorting
- Achieve 99.21% statement and 94.23% branch coverage
…ogic

Add closedDate field to track when issues are closed and fix the date
filtering logic to correctly show issues that were open during a date range.

Changes:
- Add closedDate field to BuildingIssue schema with default null
- Auto-set closedDate when issue status changes to 'closed'
- Auto-clear closedDate when issue is reopened (status -> 'open')
- Fix bmGetOpenIssue to show issues "open during range" instead of
  only "created during range"
- Use date-fns endOfDay() for consistent date handling across codebase
- Prevent req.body mutation by creating a copy before modification

Date filtering now correctly includes:
- Issues created before range but still open
- Issues created during range (whether open or closed later)
- Issues closed during range (even if created before)
…losedDate

Update existing tests and add new test cases to cover the new date filtering
logic and automatic closedDate tracking functionality.

Changes:
- Update existing date filter tests to match new query structure ($and/$or)
- Add test: show issue created before range and still open
- Add test: show issue created before range and closed during range
- Add test: NOT show issue closed before range
- Add test: show issue created during range regardless of closed status
- Add test: auto-set closedDate when closing an issue
- Add test: auto-clear closedDate when reopening an issue
- Update "combine all filters" test for new query structure
- Update "update issue successfully" test to expect closedDate

All 52 tests passing with 100% coverage of new functionality.
…er, tests

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

2 participants

Comments