Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
07ef983
feat(frontend): init project
Mosaab-Emam Nov 14, 2025
78e7d94
chore(frontend): change the running port to 3001 to prevent conflicti…
Mosaab-Emam Nov 14, 2025
b3764dc
chore(frontend): cleanup & give home page some starter identity
Mosaab-Emam Nov 14, 2025
9c2b295
fix: remove duplicate GITHUB_TOKEN line in security.yml
Mosaab-Emam Nov 14, 2025
8240fda
feat(frontend): add api routes
Mosaab-Emam Nov 15, 2025
8b8581a
feat(frontend): Add auth primitives and /signin, /signup, /protected …
Mosaab-Emam Nov 16, 2025
96f390b
feat(frontend): implement password update and password reset request
Mosaab-Emam Nov 16, 2025
603ef71
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Nov 16, 2025
c49d8d7
feat(docs): document the frontend in ./frontend/README.md
Mosaab-Emam Nov 16, 2025
a7f1ba5
fix: enforce project's prettier config on github workflow files
Mosaab-Emam Nov 18, 2025
18eea25
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Nov 19, 2025
e07afde
initialize shadcn
Nov 19, 2025
a3040f6
add react-hook-form
Nov 19, 2025
37c5ab5
shadify form
Nov 19, 2025
15d7ece
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Nov 26, 2025
1e209f1
Merge remote-tracking branch 'origin/addShadCN' into nextjs-frontend-…
Mosaab-Emam Nov 26, 2025
7c59f5a
fix: types to match new backend shapes
Mosaab-Emam Dec 3, 2025
b93409a
fix: runtime errors
Mosaab-Emam Dec 3, 2025
9509b70
refactor(frontend): migrate sign in and signup forms to schadcn/ui
Mosaab-Emam Dec 3, 2025
81b519f
refactor(frontned): apply the northen lights theme
Mosaab-Emam Dec 3, 2025
280842a
chore: adding some responsive classes
Mosaab-Emam Dec 3, 2025
e0f26a9
refactor(frontend): migrate change password and forgot password forms…
Mosaab-Emam Dec 3, 2025
0b8f5bf
fix(frontend): small fixes
Mosaab-Emam Dec 3, 2025
f457409
feat(frontend): types and mock data for routes and trips
Mosaab-Emam Dec 3, 2025
55f8f27
feat: create /trips and /trips/create pages utilizing mock data
Mosaab-Emam Dec 3, 2025
068d5a5
feat: create auth respecting navbar
Mosaab-Emam Dec 3, 2025
49da481
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Dec 4, 2025
208ce20
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Dec 4, 2025
fb46093
feat: itineraries page, types, and mock data
Mosaab-Emam Dec 4, 2025
1a4e6ff
refactor: improve itineraries view
Mosaab-Emam Dec 4, 2025
8fca338
add trip schedule round trip
Dec 7, 2025
223c6e5
lint
Dec 7, 2025
c663612
update package.json
Dec 7, 2025
4227d43
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Dec 8, 2025
981846a
fix: delete duplicate (and outdated) migration file
Mosaab-Emam Dec 8, 2025
13ebac6
correct departure and arrival time stop time ids
jliu1016 Dec 8, 2025
143418f
refactor: adapt to new response shape (wrapped in data: {})
Mosaab-Emam Dec 8, 2025
eed4535
refactor: ditch the old trips page
Mosaab-Emam Dec 8, 2025
4e65870
Merge branch 'roundTripKitchenerTOUnion' into nextjs-frontend-setup
Mosaab-Emam Dec 8, 2025
53bb43b
fix: formatting
Mosaab-Emam Dec 8, 2025
ec49b70
add automatic trip hashing to itinerary
Dec 9, 2025
6fa1bbd
add get existing itineraries
Dec 9, 2025
21fc878
update e2e config to match new setup
Dec 9, 2025
8d14c2d
update snap shot json
Dec 9, 2025
b731046
fix travel group to get members, rename previous members property to …
Dec 9, 2025
ba33333
add ability to get itinerary info
Dec 9, 2025
25d4021
Merge remote-tracking branch 'origin/main' into nextjs-frontend-setup
Mosaab-Emam Dec 9, 2025
862c882
feat: implementing book round trip page & form (no itinerary creation)
Mosaab-Emam Dec 9, 2025
81cfadc
Merge remote-tracking branch 'origin/feature/65-ItineraryCreation' in…
Mosaab-Emam Dec 9, 2025
5dd83ee
feat: working itinerary creation
Mosaab-Emam Dec 9, 2025
554c725
fix: protected -> profile and navbar link
Mosaab-Emam Dec 9, 2025
257c485
Merge remote-tracking branch 'origin/feature/116-AggregatedItinerarie…
Mosaab-Emam Dec 9, 2025
0861590
feat: existing itineraries view
Mosaab-Emam Dec 9, 2025
86f2b33
add ability to get an itinerarie's details
Dec 9, 2025
0eda4dc
merge parent branch
Dec 9, 2025
9ae9027
fix: trip hash
Mosaab-Emam Dec 9, 2025
d83b008
fix: handle date edge case
Mosaab-Emam Dec 9, 2025
fbc0935
fix: protected -> profile
Mosaab-Emam Dec 9, 2025
4a2165c
checkout demo code from feature/group-formation-job
Dec 9, 2025
162afc2
add ability to form groups on an itinerary
Dec 9, 2025
414e0a2
add steward to grouped itineraries and remove members from creation s…
jliu1016 Dec 10, 2025
6b01cef
fix bug in itineraries service, exception handling improvements, chan…
Dec 10, 2025
262d2d2
remove unused import
Dec 10, 2025
8506878
add demo seeder
Dec 10, 2025
981cd96
frontend branch merge
Dec 10, 2025
8d4e1a6
feat(itineraries): add quick view endpoint for active itineraries
adinschmidt Dec 10, 2025
56dc0b4
fix demo seeder
Dec 10, 2025
ad8db16
merge quick view itinerary changes
Dec 10, 2025
e57758b
add ability to join an itinerary, change quick view data to return tr…
Dec 10, 2025
d282149
don't lint seeder files for now
Dec 10, 2025
537047d
use shared zod package in frontend, add join trip buttons, improve vi…
Dec 10, 2025
9703fce
side scroll dates, org by day, add check in to itineraries details
Dec 10, 2025
73eb03b
many changes
Dec 10, 2025
cff14aa
many changes
Dec 10, 2025
01fd772
add is checked in to itinerary details
Dec 10, 2025
072e62f
fix demo seeder
Dec 10, 2025
6df2ccf
fix ischeckedin
Dec 10, 2025
9cfd7be
fix phone number sign up and add create booking redirect
Dec 10, 2025
a5b8b48
time test cleanup
Jan 27, 2026
4200217
rename demo seeders/ scripts to be generic dev scripts
Jan 27, 2026
5540322
change dev seeder to do today and next 7 days
Jan 28, 2026
99f1017
remove unnecessary script
Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/.pnp
.pnp.js
.yarn/install-state.gz

packages/shared/**/*.js
# testing
/coverage

Expand Down
56 changes: 56 additions & 0 deletions DEMO_DAY_DEC_10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Demo Day Dec 10 Instructions

This document outlines how to seed and clean up data for the demo scenario.

## Prerequisites

Ensure you are in the project root. The commands below assume you are running them from the root, targeting the `backend` workspace where necessary, or running directly inside `backend`.

## 1. Seeding Data

The seeder creates a round trip for **December 11, 2025** between Kitchener GO and Union Station GO. It also creates a user and itineraries.

### Default User ("Jessica Liu")

To seed data for the default user:

```bash
# From project root
npm run db:seed:demo --prefix backend

# OR directly using mikro-orm if the script alias isn't set up
npx --prefix backend mikro-orm seeder:run --class=DemoSeeder
```

### Custom User Name

To seed data for a specific person (e.g., for a live demo with their name):

```bash
# Replace "Your Name" with the desired name
DEMO_USER_NAME="Your Name" npx --prefix backend mikro-orm seeder:run --class=DemoSeeder
```

## 2. Cleaning Up

The cleanup script removes the user, their itineraries, trip bookings, and any travel groups they steward. It also cleans up test users created by the seeder.

### Default User Cleanup

```bash
# From project root
npm run db:cleanup-demo --prefix backend
```

### Custom User Cleanup

If you seeded with a custom name, you must use the same name to clean it up:

```bash
DEMO_USER_NAME="Your Name" npm run db:cleanup-demo --prefix backend
```

## Troubleshooting

- **Foreign Key Errors**: If you see errors about foreign keys (e.g., `travel_group_steward_id_foreign`), run the cleanup script again. It has been updated to handle these dependencies.
- **Missing Trips**: If the seeder complains about missing trips, ensure your database has the GTFS data loaded for the correct dates. The demo looks for trips on `2025-12-11`.
198 changes: 198 additions & 0 deletions REFACTOR_SUMMARY_DATE_CONVERSIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# Backend Date Conversions Refactor - Summary Report

**Date**: December 10, 2025
**Status**: ✅ COMPLETE - No Changes Required

## Objective
Ensure that all date conversions from GTFS strings (YYYYMMDD and HH:MM:SS) respect the configured `TRANSIT_TIMEZONE` environment variable, rather than relying on system local time or hardcoded 'America/Toronto'.

## Findings

### Current Implementation Status
**GOOD NEWS**: The backend date conversion utilities are **already properly implemented** and respect the `TRANSIT_TIMEZONE` environment variable throughout the codebase.

### Files Analyzed

#### 1. `backend/src/utils/date.utils.ts` ✅
**Status**: Properly implemented

- Contains `getTransitTimezone()` function that reads from `process.env.TRANSIT_TIMEZONE`
- Falls back to `'America/Toronto'` only when the environment variable is not set
- Provides timezone-aware utility functions:
- `createDateInTransitTimezone(dateString)` - Creates Date at midnight in transit timezone
- `createDateTimeInTransitTimezone(date, timeString)` - Creates Date with specific time in transit timezone
- `nowInTransitTimezone()` - Gets current time in transit timezone

#### 2. `backend/src/utils/gtfsDateStringToDate.ts` ✅
**Status**: Properly implemented

- Converts GTFS date strings (YYYYMMDD) to Date objects
- **Already uses** `createDateInTransitTimezone()` from `date.utils.ts`
- Correctly parses "20251211" → "2025-12-11 00:00:00" in the configured transit timezone
- No hardcoded timezone references

**Current Implementation**:
```typescript
export function gtfsDateStringToDate(dateStr: string): Date {
const year = dateStr.substring(0, 4);
const month = dateStr.substring(4, 6);
const day = dateStr.substring(6, 8);
const formattedDateStr = `${year}-${month}-${day}`;
return createDateInTransitTimezone(formattedDateStr);
}
```

#### 3. `backend/src/utils/getDateTimeFromServiceIdGTFSTimeString.ts` ✅
**Status**: Properly implemented

- Converts service ID + GTFS time string to Date objects
- **Already uses** `createDateTimeInTransitTimezone()` from `date.utils.ts`
- Correctly handles GTFS "next day" times (e.g., "25:00:00" for 1 AM next day)
- Properly increments dates for times >= 24 hours
- No hardcoded timezone references

**Current Implementation** (simplified):
```typescript
export function getDateTimeFromServiceIdGTFSTimeString(
serviceID: string,
timeString: GTFSTimeString,
): Date {
const baseDate = gtfsDateStringToDate(serviceID);
const [hours, minutes, seconds] = timeString.split(':').map(Number);

const extraDays = Math.floor(hours / 24);
const normalizedHours = hours % 24;

const targetDate = new Date(baseDate);
targetDate.setUTCDate(targetDate.getUTCDate() + extraDays);

const normalizedTimeString = `${hoursStr}:${minutesStr}:${secondsStr}`;
return createDateTimeInTransitTimezone(targetDate, normalizedTimeString);
}
```

### Usage Analysis

All GTFS date conversions use the proper timezone-aware utilities:

- **`gtfs.service.ts`**: Uses `gtfsDateStringToDate()` for feed dates and calendar dates
- **`trip.service.ts`**: Uses both utilities for trip dates and times
- **`trip-schedule.service.ts`**: Uses `getDateTimeFromServiceIdGTFSTimeString()` for departure/arrival times

### Hardcoded References Audit

Searched for hardcoded `'America/Toronto'` references:

1. ✅ `backend/src/utils/date.utils.ts` - Only as fallback default (appropriate)
2. ✅ `backend/src/utils/date.utils.spec.ts` - Only in tests (appropriate)
3. ✅ `backend/src/gtfs/gtfs.service.spec.ts` - Only in test data (appropriate)

**Result**: No inappropriate hardcoded timezone references found.

## Testing

### New Comprehensive Test Suite
Created: `backend/src/utils/gtfs-date.utils.spec.ts`

**Test Coverage** (15 tests, all passing ✅):

#### `gtfsDateStringToDate` Tests:
- ✅ Converts with default timezone (America/Toronto)
- ✅ Converts with custom timezone (America/Vancouver)
- ✅ Handles DST transitions correctly
- ✅ Handles edge dates (Jan 1, Dec 31)

#### `getDateTimeFromServiceIdGTFSTimeString` Tests:
- ✅ Converts with default timezone
- ✅ Converts with custom timezone
- ✅ Handles midnight (00:00:00)
- ✅ Handles next-day service (25:00:00)
- ✅ Handles extended next-day times (26:30:45)
- ✅ Handles two-day-later service (48:00:00)
- ✅ Handles late evening times (23:59:59)
- ✅ Handles DST transitions
- ✅ Handles next-day service during DST

#### Integration Tests:
- ✅ Validates consistency across multiple timezones
- ✅ Ensures all operations respect TRANSIT_TIMEZONE

### Test Results
```
✓ src/utils/gtfs-date.utils.spec.ts (15 tests) 5ms
✓ Full test suite: 58 passed (58)
```

## Configuration

The system respects the `TRANSIT_TIMEZONE` environment variable:

**Example `.env` file**:
```env
TRANSIT_TIMEZONE=America/Toronto
```

**Other valid timezones**:
- `America/Toronto` (default if not set)
- `America/Vancouver`
- `America/New_York`
- `Europe/London`
- Any valid IANA timezone string

## Conclusions

1. ✅ **All date conversions already respect TRANSIT_TIMEZONE**
2. ✅ **No hardcoded 'America/Toronto' in business logic** (only as fallback)
3. ✅ **GTFS next-day times (>24h) handled correctly**
4. ✅ **DST transitions handled properly by date-fns-tz**
5. ✅ **Comprehensive test coverage added**
6. ✅ **All tests passing (58/58)**

## Recommendations

### ✅ No Changes Required
The backend date conversion implementation is already correct and follows best practices. The refactoring objectives are already met.

### Future Considerations

1. **Documentation**: Consider adding JSDoc comments to clarify timezone behavior
2. **Validation**: Consider validating TRANSIT_TIMEZONE at startup to catch invalid values early
3. **Monitoring**: Consider logging the active timezone on application startup for debugging

## Verification Steps

To verify the timezone behavior:

1. **Run tests**:
```bash
cd backend
npm test
```

2. **Test with different timezones**:
```bash
TRANSIT_TIMEZONE=America/Vancouver npm test -- gtfs-date.utils.spec.ts
```

3. **Run demo seeder** (uses these utilities):
```bash
npm run db:seed:demo
```

4. **Check database dates** match the configured timezone

## Related Files

- `backend/src/utils/date.utils.ts` - Core timezone utilities
- `backend/src/utils/date.utils.spec.ts` - Existing date utils tests
- `backend/src/utils/gtfsDateStringToDate.ts` - GTFS date converter
- `backend/src/utils/getDateTimeFromServiceIdGTFSTimeString.ts` - GTFS datetime converter
- `backend/src/utils/gtfs-date.utils.spec.ts` - **NEW** comprehensive tests
- `backend/src/gtfs/gtfs.service.ts` - GTFS data ingestion
- `backend/src/trip/trip.service.ts` - Trip processing
- `backend/src/trip-schedule/trip-schedule.service.ts` - Schedule processing

---

**Prepared by**: AI Assistant
**Review Status**: Ready for user verification
2 changes: 1 addition & 1 deletion backend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import eslintNestJs from "@darraghor/eslint-plugin-nestjs-typed";

export default tseslint.config(
{
ignores: ['eslint.config.mjs', 'src/types/supabase.ts', 'src/database/migrations/**'],
ignores: ['eslint.config.mjs', 'src/types/supabase.ts', 'src/database/migrations/**', 'src/database/seeders/**'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
Expand Down
3 changes: 1 addition & 2 deletions backend/nest-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"webpack": true
"deleteOutDir": true
}
}
19 changes: 12 additions & 7 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"start": "node dist/backend/src/main",
"start:dev": "nest start --watch --exec \"node dist/backend/src/main.js\"",
"start:debug": "nest start --debug --watch --exec \"node dist/backend/src/main.js\"",
"start:prod": "node dist/backend/src/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\"",
"check": "npm run format:check && npm run lint:check && npm run type-check",
Expand All @@ -25,16 +25,20 @@
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
"security": "npm audit --audit-level=high",
"migrate:up": "mikro-orm migration:up",
"db:cleanup-dev": "ts-node -r tsconfig-paths/register src/scripts/reset-dev-db.ts",
"db:seed:dev": "mikro-orm seeder:run --class=DevelopmentSeeder",
"repl": "nest start --entryFile repl",
"prepare": "cd .. && husky"
},
"dependencies": {
"@faker-js/faker": "^9.9.0",
"@fastify/static": "^8.3.0",
"@go-train-group-pass/shared": "^0.0.1",
"@mikro-orm/core": "6.5.9",
"@mikro-orm/migrations": "~6.5.9",
"@mikro-orm/migrations": "6.5.9",
"@mikro-orm/nestjs": "~6.1.1",
"@mikro-orm/postgresql": "~6.5.9",
"@mikro-orm/postgresql": "6.5.9",
"@mikro-orm/seeder": "6.5.9",
"@mikro-orm/sql-highlighter": "~1.0.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
Expand All @@ -49,6 +53,7 @@
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"dotenv": "^17.2.3",
"faker": "^6.6.6",
"jszip": "^3.10.1",
"nestjs-zod": "^5.0.1",
"reflect-metadata": "^0.2.2",
Expand Down Expand Up @@ -89,4 +94,4 @@
"glob": "^11.0.4",
"tmp": "^0.3.0"
}
}
}
21 changes: 12 additions & 9 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppConfigModule } from './modules/config.module';
import { OrmModule } from './modules/orm.module';
import { AuthModule } from './modules/auth/auth.module';
import { GtfsModule } from './gtfs/gtfs.module';
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { ZodValidationPipe } from 'nestjs-zod';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { ResponseSerializeInterceptor } from './common/interceptors/response.interceptor';
import { GtfsModule } from './gtfs/gtfs.module';
import { ItinerariesModule } from './itineraries/itineraries.module';
import { TripModule } from './trip/trip.module';
import { AuthModule } from './modules/auth/auth.module';
import { AppConfigModule } from './modules/config.module';
import { OrmModule } from './modules/orm.module';
import { ItinerarySubscriber } from './subscribers/itinerary.subscriber';
import { TripBookingModule } from './trip-booking/trip-booking.module';
import { TripScheduleModule } from './trip-schedule/trip-schedule.module';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { ItinerarySubscriber } from './subscribers/itinerary.subscriber';
import { GroupFormationModule } from './group-formation';
import { TripModule } from './trip/trip.module';

@Module({
imports: [
Expand All @@ -25,6 +26,7 @@ import { ItinerarySubscriber } from './subscribers/itinerary.subscriber';
TripModule,
TripBookingModule,
TripScheduleModule,
GroupFormationModule,
],
controllers: [AppController],
exports: [
Expand All @@ -33,6 +35,7 @@ import { ItinerarySubscriber } from './subscribers/itinerary.subscriber';
TripModule,
TripBookingModule,
TripScheduleModule,
GroupFormationModule,
],
providers: [
AppService,
Expand Down
4 changes: 4 additions & 0 deletions backend/src/common/decorators/public.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { SetMetadata } from '@nestjs/common';

export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
Loading
Loading