Skip to content

Location - #30

Open
indunil-k wants to merge 64 commits into
mainfrom
location
Open

Location#30
indunil-k wants to merge 64 commits into
mainfrom
location

Conversation

@indunil-k

Copy link
Copy Markdown
Collaborator

geolocation searching

Yasith763 and others added 30 commits August 4, 2025 19:11
create backend of catagory and services
migrate entire codebase from JavaScript to TypeScript
refactor: update Dockerfile to install TypeScript and run transpiled …
…on Prisma client pattern and enhancing connection pool configuration

docs: add troubleshooting guide for database connection issues and optimizations implemented

perf: optimize backend performance by implementing caching, response compression, and database indexing

feat: create comprehensive monitoring for connection pool and performance metrics

chore: add tests for connection pool and database performance to ensure stability and efficiency
…th checks

- Added @types/aws-sdk to dependencies for TypeScript support.
- Removed unused quick-db-test.js, performance.middleware.ts, connection-monitor.ts, and related test files.
- Simplified health route by removing unnecessary database stats and connection time logging.
- Updated user.service.ts to improve performance by counting services instead of fetching them.
- Cleaned up database connection logic in database.ts and removed retry logic.
- Removed various test scripts related to admin and connection testing.
- Created a new empty dev.db file for Prisma.
indunil-k and others added 25 commits September 4, 2025 20:06
… reviews by rating, and show rating distribution.
- Created Admin model in Prisma schema with fields: id, username, password, firstName, lastName.
- Implemented admin authentication middleware to protect routes and validate JWT tokens.
- Developed AdminController with methods for registration, login, profile retrieval, and updates.
- Added validation schemas for admin registration, login, and updates using Joi.
- Updated routes to include admin-specific endpoints for registration, login, profile management, and admin listing.
- Created admin service for handling database operations related to admin users.
- Added SQL migration for creating the Admin table in the database.
@indunil-k
indunil-k requested review from UmeshaJayakody and Copilot and removed request for UmeshaJayakody October 9, 2025 05:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request introduces comprehensive geolocation search functionality to the platform, enabling location-based service discovery. The changes migrate the codebase from JavaScript to TypeScript for better type safety and include extensive location-aware features.

  • Added geolocation search capabilities with Google Maps integration for address geocoding and distance calculations
  • Migrated core services and validators from JavaScript to TypeScript with proper type definitions
  • Enhanced service validation with location fields and geospatial search parameters

Reviewed Changes

Copilot reviewed 98 out of 124 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/validators/services.validator.ts New TypeScript validator with location fields and geospatial search schemas
src/services/services.service.ts Enhanced service layer with location processing and PostGIS spatial queries
src/services/googleMaps.service.ts New Google Maps integration for geocoding and reverse geocoding
src/controllers/services.controller.ts Updated controllers with hybrid search combining semantic and location-based filtering
src/routes/services.route.ts Expanded API routes for location-based search endpoints
src/utils/database.ts New singleton database manager for improved connection handling

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +287 to +302
lat: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
lng: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
}),
latitude: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
longitude: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
})

Copilot AI Oct 9, 2025

Copy link

Choose a reason for hiding this comment

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

The reverseGeocodeSchema duplicates latitude/longitude validation by supporting both 'lat/lng' and 'latitude/longitude' formats. Consider creating a reusable coordinate validation helper to reduce code duplication and ensure consistency across all coordinate validations.

Copilot uses AI. Check for mistakes.
Comment on lines +286 to +303
export const reverseGeocodeSchema = Joi.object({
lat: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
lng: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
}),
latitude: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
longitude: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
})
}).or('lat', 'latitude').or('lng', 'longitude');

Copilot AI Oct 9, 2025

Copy link

Choose a reason for hiding this comment

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

The .or() chain requires either 'lat' OR 'latitude' and either 'lng' OR 'longitude', but doesn't enforce that coordinates come in matching pairs (lat+lng or latitude+longitude). This could allow invalid combinations like 'lat' with 'longitude'. Consider using .and() with conditional validation to ensure coordinate pairs are consistent.

Suggested change
export const reverseGeocodeSchema = Joi.object({
lat: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
lng: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
}),
latitude: Joi.number().min(-90).max(90).optional().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90'
}),
longitude: Joi.number().min(-180).max(180).optional().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180'
})
}).or('lat', 'latitude').or('lng', 'longitude');
export const reverseGeocodeSchema = Joi.alternatives().try(
Joi.object({
lat: Joi.number().min(-90).max(90).required().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90',
'any.required': 'Latitude is required'
}),
lng: Joi.number().min(-180).max(180).required().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180',
'any.required': 'Longitude is required'
})
}),
Joi.object({
latitude: Joi.number().min(-90).max(90).required().messages({
'number.min': 'Latitude must be between -90 and 90',
'number.max': 'Latitude must be between -90 and 90',
'any.required': 'Latitude is required'
}),
longitude: Joi.number().min(-180).max(180).required().messages({
'number.min': 'Longitude must be between -180 and 180',
'number.max': 'Longitude must be between -180 and 180',
'any.required': 'Longitude is required'
})
})
);

Copilot uses AI. Check for mistakes.
// Execute queries
const [servicesResult, countResult] = await Promise.all([
prisma.$queryRawUnsafe(servicesQuery, ...queryParams),
prisma.$queryRawUnsafe(countQuery, longitude, latitude, radius * 1000, ...queryParams.slice(5, paramIndex - 1))

Copilot AI Oct 9, 2025

Copy link

Choose a reason for hiding this comment

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

The parameter slicing logic queryParams.slice(5, paramIndex - 1) may pass incorrect parameters to the count query. The count query expects the same base parameters (longitude, latitude, radius) plus additional filters, but the slice range doesn't account for the paramIndex offset correctly. This could cause parameter mismatch errors.

Suggested change
prisma.$queryRawUnsafe(countQuery, longitude, latitude, radius * 1000, ...queryParams.slice(5, paramIndex - 1))
prisma.$queryRawUnsafe(countQuery, longitude, latitude, radius * 1000, ...queryParams.slice(6, -2))

Copilot uses AI. Check for mistakes.
Comment on lines +584 to +585
const clientIP = req.ip || req.connection.remoteAddress || req.headers['x-forwarded-for'] as string;

Copilot AI Oct 9, 2025

Copy link

Choose a reason for hiding this comment

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

The IP extraction logic has potential type safety issues. req.connection.remoteAddress is deprecated, and req.headers['x-forwarded-for'] can be an array. Consider using a more robust IP extraction approach that handles arrays and uses the standard req.socket.remoteAddress instead of the deprecated property.

Suggested change
const clientIP = req.ip || req.connection.remoteAddress || req.headers['x-forwarded-for'] as string;
// Robust client IP extraction
let clientIP: string | undefined;
if (req.ip) {
clientIP = req.ip;
} else if (req.headers['x-forwarded-for']) {
const xff = req.headers['x-forwarded-for'];
if (Array.isArray(xff)) {
clientIP = xff[0];
} else if (typeof xff === 'string') {
clientIP = xff.split(',')[0].trim();
}
} else if (req.socket && req.socket.remoteAddress) {
clientIP = req.socket.remoteAddress;
}
if (!clientIP) {
clientIP = '';
}

Copilot uses AI. Check for mistakes.
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.

4 participants