Skip to content

feat(api): implement TypeORM REST endpoints, 3-tier architecture, and… - #2

Merged
pireu2 merged 1 commit into
mainfrom
feat/core-rest-api-and-services
Aug 25, 2026
Merged

feat(api): implement TypeORM REST endpoints, 3-tier architecture, and…#2
pireu2 merged 1 commit into
mainfrom
feat/core-rest-api-and-services

Conversation

@pireu2

@pireu2 pireu2 commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary of Changes

  • 3-Tier Architecture: Organized routes/ -> controllers/ -> services/ -> entities/.
  • Pure TypeORM Repository Queries: Replaced custom query builder strings with native TypeORM repository methods (findAndCount, findOne, find, ILike, In, Between, MoreThanOrEqual, LessThanOrEqual).
  • REST Endpoints:
    • GET /categories & GET /categories/:slug (with product counts and category metadata).
    • GET /products (multi-faceted search, price bounds, category/manufacturer filtering, pagination).
    • GET /products/:identifier (single product spec sheet).
    • GET/POST/PUT/DELETE /projects (saved builds and chat history CRUD).
  • Middlewares: Global rate limiting (60 req/min per IP) and centralized error handling.

@pireu2
pireu2 requested a lite review from Copilot and removed request for Copilot August 25, 2026 14:57
@pireu2
pireu2 merged commit 6d7a2a9 into main Aug 25, 2026
1 check passed
@pireu2
pireu2 deleted the feat/core-rest-api-and-services branch August 25, 2026 14:58
@pireu2
pireu2 requested a lite review from Copilot August 25, 2026 15:48

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.

🟡 Changes recommended

Multiple confirmed security/data-exposure issues exist around projects access control and unverified header-based authentication, plus input validation gaps that can cause runtime errors.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Implements a new REST API surface for core domain objects (categories, products, projects) using a 3-tier routing/controller/service architecture over TypeORM repositories, and adds global middleware for rate limiting and centralized error handling.

Changes:

  • Added controllers, services, and routes for /categories, /products, and /projects.
  • Implemented product listing/search with filtering, sorting, and pagination via repository methods (findAndCount, ILike, In, Between, etc.).
  • Added global middleware: IP rate limiting and centralized JSON error handling; updated migration rollback to use repositories.
File summaries
File Description
api/src/services/projects.service.ts Implements CRUD logic for projects using TypeORM repositories.
api/src/services/products.service.ts Implements product search/listing and identifier lookup with repository operators.
api/src/services/categories.service.ts Implements category listing and slug lookup.
api/src/routes/projects.routes.ts Registers /projects CRUD routes.
api/src/routes/products.routes.ts Registers /products list and identifier routes.
api/src/routes/index.ts Aggregates category/product/project routers under a single router.
api/src/routes/categories.routes.ts Registers /categories list and slug routes.
api/src/migrations/1740441600000-SeedInitialData.ts Updates seed migration rollback to clear via repositories.
api/src/middlewares/rateLimiter.ts Adds a global 60 req/min IP-based rate limiter.
api/src/middlewares/errorHandler.ts Adds centralized JSON error handling middleware.
api/src/middlewares/auth.ts Adds optional/required auth middleware based on request headers.
api/src/index.ts Mounts routes, rate limiter, and error handler; updates startup logging and paths.
api/src/controllers/projects.controller.ts Adds request/response handling for project endpoints.
api/src/controllers/products.controller.ts Adds request/response handling for product endpoints and query parsing.
api/src/controllers/categories.controller.ts Adds request/response handling for category endpoints.
api/package.json Adds express-rate-limit dependency.
api/package-lock.json Locks express-rate-limit (and updates metadata).
.env.example Adds Neon Auth-related environment variable examples.
Review details

Files not reviewed (1)

  • api/package-lock.json: Generated file
  • Files reviewed: 17/18 changed files
  • Comments generated: 10
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +6 to +10
router.get('/', (req, res, next) => projectsController.getProjects(req, res, next));
router.get('/:id', (req, res, next) => projectsController.getProjectById(req, res, next));
router.post('/', (req, res, next) => projectsController.createProject(req, res, next));
router.put('/:id', (req, res, next) => projectsController.updateProject(req, res, next));
router.delete('/:id', (req, res, next) => projectsController.deleteProject(req, res, next));
Comment on lines +5 to +9
async getProjects(req: Request, res: Response, next: NextFunction) {
try {
const userId = typeof req.query.userId === 'string' ? req.query.userId : undefined;
const projects = await projectsService.getProjects(userId);

Comment on lines +20 to +27
async getProjects(userId?: string) {
const where: FindOptionsWhere<Project> = userId ? { user: { id: userId } } : {};

return await this.projectRepo.find({
where,
relations: { user: true },
order: { updatedAt: 'DESC' },
});
Comment on lines +5 to +9
export interface CreateProjectInput {
title: string;
userId?: string;
data?: Record<string, any>;
}
Comment on lines +53 to +58
if (params.manufacturer) {
const manufacturers = Array.isArray(params.manufacturer)
? params.manufacturer
: params.manufacturer.split(",").map((m) => m.trim());
where.manufacturer = In(manufacturers);
}
Comment on lines +60 to +67
// 4. Price Filter
if (params.minPrice !== undefined && params.maxPrice !== undefined) {
where.price = Between(Number(params.minPrice), Number(params.maxPrice));
} else if (params.minPrice !== undefined) {
where.price = MoreThanOrEqual(Number(params.minPrice));
} else if (params.maxPrice !== undefined) {
where.price = LessThanOrEqual(Number(params.maxPrice));
}
Comment on lines +18 to +27
const queryParams: ProductQueryParams = {
page: page ? Number(page) : undefined,
limit: limit ? Number(limit) : undefined,
search: typeof search === 'string' ? search : undefined,
category: typeof category === 'string' ? category : undefined,
manufacturer: typeof manufacturer === 'string' ? manufacturer : undefined,
minPrice: minPrice ? Number(minPrice) : undefined,
maxPrice: maxPrice ? Number(maxPrice) : undefined,
sortBy: sortBy as ProductQueryParams['sortBy'],
};
Comment on lines +14 to +17
const category = await this.categoryRepo.findOne({
where: { slug },
relations: { products: true },
});
Comment on lines +16 to +26
const userId = req.headers['x-user-id'] as string;
const userEmail = req.headers['x-user-email'] as string;
const userName = req.headers['x-user-name'] as string;

if (userId) {
req.user = {
id: userId,
email: userEmail,
name: userName,
};
}
Comment thread api/src/index.ts
Comment on lines +29 to +32
app.use("/api/v1/core", routes);
app.use("/", routes);

app.use(errorHandler);
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.

2 participants