Skip to content

feat: extend API to support all 4 college years - #4

Open
kanithi01karthik wants to merge 2 commits into
Opensource-NITJ:mainfrom
kanithi01karthik:feat/all-year-timetable-and-student-group
Open

feat: extend API to support all 4 college years#4
kanithi01karthik wants to merge 2 commits into
Opensource-NITJ:mainfrom
kanithi01karthik:feat/all-year-timetable-and-student-group

Conversation

@kanithi01karthik

@kanithi01karthik kanithi01karthik commented Jul 20, 2026

Copy link
Copy Markdown

Resolves #3

Summary

Extends the API to support 2nd, 3rd, and 4th year students across both the student group lookup and timetable endpoints, fulfilling all structural and parameter guidelines.


Acceptance Criteria Met

1. Support Additional Years

  • Added timetable data ingestion and semester calculation for 2nd, 3rd, and 4th Year schedules (using dynamic Odd/Even academic session mapping via Xceed).

2. Subsection Support

  • Added query parameter subSection (e.g. 1, 2).
  • Modified getHigherYearGroup patterns to match subsection variations: e.g. B.Tech-CSE-4A1 and B.Tech-CSE-4A-1.

3. Improved Timetable Structure

Raw response strings are parsed on-the-fly to return highly structured, machine-readable objects. Response schema matches the issue request fields:

  • Subject Name & Subject Code (extracted using regex, e.g. CSX-201)
  • Faculty Name
  • Room / Venue
  • Day
  • Start Time, End Time, & Duration (resolved based on standard NITJ period slots)
  • Branch/Department, Year, Section, & Subsection
  • Course Type (Derived as Lecture, Tutorial, or Practical based on subject title analysis)

Changes

New Endpoints

  • GET /timetable/year/:year — Returns live structured timetable for years 2, 3, and 4 by department, section, and optional subsection.

Updated Endpoints

  • GET /students/getGroup — Now supports all batches (2022–2026). Batch is auto-detected from the roll number prefix.

New Files

  • lib/higherYears.ts — Department mapping, semester resolution with optional subsection.
  • routes/timetable/year/higherYears.ts — Route handler for /timetable/year/:year mapping raw text to structured properties.
  • test.spec.ts — Integration tests verifying response structures (9 tests, ~65ms).
  • seed.ts — Initialises and seeds all batch tables in database.sqlite.

Schema

  • Added batch2022, batch2023, batch2024, batch2026 tables to lib/db/schema.ts.

Testing

bun test v1.3.14

 9 pass
 0 fail
 32 expect() calls
Ran 9 tests across 1 file. [65ms]

Copilot AI review requested due to automatic review settings July 20, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the API beyond first-year support by adding a higher-year timetable endpoint (Years 2–4) and expanding student group lookup across multiple batches, alongside security middleware and updated docs/tests.

Changes:

  • Added GET /timetable/year/:year for years 2–4 with branch/section querying and Xceed-backed fetching.
  • Updated student group lookup to support multiple batch tables (2022–2026) and relaxed response schema types.
  • Added integration tests, a DB seeding script, security middleware, and expanded README documentation.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test.spec.ts Adds integration tests and mocks Xceed fetches to validate student group + timetable endpoints.
seed.ts Adds a script to create batch tables and seed sample student records into database.sqlite.
routes/timetable/year/higherYears.ts Introduces the higher-year timetable route (/timetable/year/:year) with input validation and Xceed fetch timeout.
routes/timetable/year/1.ts Adds fetch timeout and improves error handling/response codes for year-1 timetable fetch.
routes/timetable/index.ts Wires the new higher-year timetable router under /timetable/year.
routes/students/getGroup.ts Expands student group response types beyond first-year enum constraints.
README.md Updates documentation to include higher-year timetables, expanded group lookup, setup/testing notes, and schema/security details.
package-lock.json Adds an npm lockfile (in addition to existing Bun lockfile).
lib/higherYears.ts Adds Xceed department/semester resolution logic for years 2–4 based on current session.
lib/firstYear.ts Improves Basic Sciences lookup and expands DB table selection/roll validation across batches.
lib/db/schema.ts Adds SQLite schema tables for batches 2022–2024 and 2026.
app.ts Adds CORS + secure headers middleware and global error/404 handlers.
Comments suppressed due to low confidence (1)

routes/students/getGroup.ts:49

  • /students/getGroup currently returns 404 for malformed roll numbers because validation happens inside getGroup() and both 'invalid input' and 'not found' collapse to null. This makes it hard for API consumers to distinguish bad input from missing data and contradicts the documented roll-number validation behavior. Validate rollNumber in the route and return 400 for invalid values.
    async c => {
        const { rollNumber } = c.req.valid("query");
        const studentGroup = await getGroup(rollNumber);
        if (studentGroup) {
            return c.json({
                group: studentGroup.group,
                subGroup: studentGroup.subGroup,
            });
        }
        return c.json({ message: "Group not found for the provided roll number." }, 404);
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread routes/timetable/year/higherYears.ts Outdated
Comment on lines +136 to +141
} catch (error: unknown) {
const message = error instanceof Error && error.name === "AbortError"
? "Timetable fetch timed out"
: "An error occurred while fetching timetable data";
return c.json({ error: message }, 500);
}
Comment on lines +12 to +25
const querySchema = z.object({
branch: z
.string()
.min(2)
.max(5)
.regex(/^[A-Za-z]+$/, "Branch must contain only letters")
.openapi({ example: "CSE" }),
group: z
.string()
.max(3)
.regex(/^[A-Za-z0-9]*$/, "Group must be alphanumeric")
.default("A")
.openapi({ example: "A" }),
});
Comment thread lib/firstYear.ts
Comment on lines +18 to +21
const dept = sessionDeptData.uniqueDept.find(d => d === "Basic Sciences");
if (!dept) {
throw new Error("Basic Sciences department not found in Xceed session data");
}
Comment thread lib/higherYears.ts Outdated
Comment on lines +89 to +93
entry.code === code &&
entry.sem.toUpperCase().includes(branchInfo.semPrefix.toUpperCase()) &&
entry.sem.includes(`${semNumber}`) &&
entry.sem.toUpperCase().includes(group.trim().toUpperCase())
);
Comment thread lib/higherYears.ts Outdated
Comment on lines +34 to +35
const sessions = await fetch(config.url.sessionAndDept);
const sessionDeptData = (await sessions.json()) as sessionDeptDataType;
Comment thread test.spec.ts Outdated
Comment on lines +115 to +116
return originalFetch(url, init);
}) as any;
## What's New

### Student Group Endpoint
- Extended /students/getGroup to support all batches (2022–2026)
- Batch auto-detected from roll number prefix (e.g. 24xxxxxx → batch2024)
- Removed first-year-only enum constraint; now returns generic group/subGroup strings

### Timetable Endpoints
- Added GET /timetable/year/:year for 2nd, 3rd, and 4th year students
- New lib/higherYears.ts maps branch abbreviations to Xceed department names
- Automatically resolves odd/even semester from live Xceed session API
- Supports 12 branch abbreviations (CSE, IT, ECE, EE, ME, CE, BT, CH, ICE, IPE, TT, MCE)

### Database Schema
- Added batch2022, batch2023, batch2024, batch2026 tables to schema.ts
- Added seed.ts to initialise and populate all batch tables

### Testing
- Added test.spec.ts with 9 integration tests covering all new endpoints
- Tests use global fetch mocking for fast, network-isolated runs (79ms)

### Security Hardening
- Added CORS (GET-only), secureHeaders, and global error handler middleware
- Roll numbers validated: 8–10 digits, year prefix 20–35
- All external Xceed fetches wrapped with 8-second AbortController timeout
- Input parameters constrained via Zod: branch 2–5 alpha chars, group max 3 alphanumeric
- Error messages scrubbed — internal details logged server-side only
- Fixed uniqueDept[0] assumption: now searches by name ('Basic Sciences')
- Validated Xceed code response shape before using in URL construction
- All parseInt calls use explicit radix 10

### Documentation
- Fully rewrote README.md with setup instructions, all endpoint docs,
  branch abbreviation table, database schema section, and security notes
@kanithi01karthik
kanithi01karthik force-pushed the feat/all-year-timetable-and-student-group branch from 6a4dc9c to ac20027 Compare July 20, 2026 20:03
@aumanshkaushal

Copy link
Copy Markdown
Member

I found a few issues while testing the higher-year timetable endpoints.

1. slots.map crashes for some timetables

Endpoint

GET /timetable/year/2?branch=CSE

The request fails with:

TypeError: slots.map is not a function

The parser currently assumes every period is an array of concurrent slot lists:

structuredTimetable[day][periodName] = slots.map(...)

However, some timetable data appears to have a different structure (or a single object instead of an array), causing the parser to crash.


2. Some branches return a generic error

Example

GET /timetable/year/2?branch=CHE

Response:

{
  "error": "An error occurred while fetching timetable data"
}

3. Branch enum in OpenAPI documentation

The branch mappings are currently defined internally:

CSE
CS
IT
ECE
EC
EE
ME
CE
BT
CH
CHE
ICE
IPE
TT
MNC
MC

However, these aliases are not properly reflected in the generated OpenAPI schema.

The OpenAPI documentation should explicitly define the allowed enum values so that:

  • Swagger UI shows all supported branches.
  • Client SDKs are generated correctly.
  • Future contributors have a single source of truth.
  • Validation and documentation remain consistent.

Ideally, the schema should expose something like:

enum: [
  "CSE",
  "CS",
  "IT",
  "ECE",
  "EC",
  "EE",
  "ME",
  "CE",
  "BT",
  "CH",
  "CHE",
  "ICE",
  "IPE",
  "TT",
  "MNC",
  "MC",
]

instead of relying solely on the internal lookup object to GET /openapi

@kanithi01karthik

Copy link
Copy Markdown
Author

Expect a commit to this PR by 12PM today @aumanshkaushal

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.

Extend timetable module to year 2, 3 & 4

3 participants