feat: implement backend API for Pantree Phase 1 MVP
- Project setup: package.json, tsconfig.json, jest.config.js, .env.example - Config: env.ts, constants.ts (ALLOWED_UNITS, bcrypt rounds, JWT, deletion windows) - DB: Knex connection, knexfile, migrations 001-006 (users, password_reset_tokens, pantry_items, recipes+recipe_ingredients, shopping_lists+items, deleted_records) - Seeds: 10 seeded recipes with full ingredient lists - Middleware: JWT authMiddleware (validates token + user existence), errorHandler - Utils: Pino logger, JWT sign helper, Zod validators for all request shapes - Services: authService (signup/signin/google/pwd-reset/soft-delete/restore), pantryService (CRUD + case-insensitive duplicate guard), recipeService (browse+filter+scale), shoppingListService (CRUD+merge logic), syncService (delta sync + tombstone cleanup), emailService (SendGrid) - Routes: /v1/auth, /v1/pantry, /v1/recipes, /v1/shopping-lists, /v1/sync - App: Express factory (createApp), server entry point - Jobs: node-cron daily hard-delete + tombstone cleanup - Tests: validators, utils, auth, pantry, recipes, shopping lists, sync
This commit is contained in:
31
src/routes/recipes.ts
Normal file
31
src/routes/recipes.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Router, Response, NextFunction } from 'express';
|
||||
import { authMiddleware, AuthenticatedRequest } from '../middleware/auth';
|
||||
import { recipeService } from '../services/recipeService';
|
||||
import { recipeQuerySchema, recipeDetailQuerySchema } from '../utils/validators';
|
||||
|
||||
const router = Router();
|
||||
router.use(authMiddleware);
|
||||
|
||||
// GET /recipes
|
||||
router.get('/', async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { filter, page, limit, search } = recipeQuerySchema.parse(req.query);
|
||||
const result = await recipeService.getRecipes(req.userId!, filter, page, limit, search);
|
||||
res.status(200).json({ ...result, synced_at: new Date().toISOString() });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// GET /recipes/:recipe_id
|
||||
router.get('/:recipe_id', async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { scale } = recipeDetailQuerySchema.parse(req.query);
|
||||
const recipe = await recipeService.getRecipeById(req.params.recipe_id, req.userId!, scale);
|
||||
res.status(200).json({ recipe });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user