MVP Build

This commit is contained in:
Eric Gullickson
2025-08-09 12:47:15 -05:00
parent 2e8816df7f
commit 8f5117a4e2
92 changed files with 5910 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
/**
* @ai-summary HTTP request handlers for stations
*/
import { Request, Response, NextFunction } from 'express';
import { StationsService } from '../domain/stations.service';
import { logger } from '../../../core/logging/logger';
export class StationsController {
constructor(private service: StationsService) {}
search = async (req: Request, res: Response, next: NextFunction) => {
try {
const userId = req.user?.sub;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { latitude, longitude, radius, fuelType } = req.body;
if (!latitude || !longitude) {
return res.status(400).json({ error: 'Latitude and longitude are required' });
}
const result = await this.service.searchNearbyStations({
latitude,
longitude,
radius,
fuelType
}, userId);
res.json(result);
} catch (error: any) {
logger.error('Error searching stations', { error: error.message });
return next(error);
}
}
save = async (req: Request, res: Response, next: NextFunction) => {
try {
const userId = req.user?.sub;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { placeId, nickname, notes, isFavorite } = req.body;
if (!placeId) {
return res.status(400).json({ error: 'Place ID is required' });
}
const result = await this.service.saveStation(placeId, userId, {
nickname,
notes,
isFavorite
});
res.status(201).json(result);
} catch (error: any) {
logger.error('Error saving station', { error: error.message });
if (error.message.includes('not found')) {
return res.status(404).json({ error: error.message });
}
return next(error);
}
}
getSaved = async (req: Request, res: Response, next: NextFunction) => {
try {
const userId = req.user?.sub;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
const result = await this.service.getUserSavedStations(userId);
res.json(result);
} catch (error: any) {
logger.error('Error getting saved stations', { error: error.message });
return next(error);
}
}
removeSaved = async (req: Request, res: Response, next: NextFunction) => {
try {
const userId = req.user?.sub;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { placeId } = req.params;
await this.service.removeSavedStation(placeId, userId);
res.status(204).send();
} catch (error: any) {
logger.error('Error removing saved station', { error: error.message });
if (error.message.includes('not found')) {
return res.status(404).json({ error: error.message });
}
return next(error);
}
}
}

View File

@@ -0,0 +1,27 @@
/**
* @ai-summary Route definitions for stations API
*/
import { Router } from 'express';
import { StationsController } from './stations.controller';
import { StationsService } from '../domain/stations.service';
import { StationsRepository } from '../data/stations.repository';
import { authMiddleware } from '../../../core/security/auth.middleware';
import pool from '../../../core/config/database';
export function registerStationsRoutes(): Router {
const router = Router();
// Initialize layers
const repository = new StationsRepository(pool);
const service = new StationsService(repository);
const controller = new StationsController(service);
// Define routes
router.post('/api/stations/search', authMiddleware, controller.search);
router.post('/api/stations/save', authMiddleware, controller.save);
router.get('/api/stations/saved', authMiddleware, controller.getSaved);
router.delete('/api/stations/saved/:placeId', authMiddleware, controller.removeSaved);
return router;
}