Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions src/routes/exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const express = require('express');
const router = express.Router();
const { handleExport } = require('../services/exporter');
const { childLogger } = require('../config/logger');
const { validate } = require('../middleware/validate');
const { readingsQuerySchema, analyticsExportSchema, createReadingSchema, bulkReadingsSchema } = require('../schemas/metering.schema');

const log = childLogger('routes:exports');

Expand Down
8 changes: 4 additions & 4 deletions src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ const { services } = require('../services');

// Import route modules here as they are created
// const authRoutes = require('./auth');
// const adminRoutes = require('./admin');
// const analyticsRoutes = require('./analytics');
const adminRoutes = require('./admin');
const analyticsRoutes = require('./analytics');
const exportRoutes = require('./exports');

// Mount routes under their respective prefixes
// router.use('/api/auth', authRoutes);
// router.use('/api/admin', adminRoutes);
// router.use('/api/analytics', analyticsRoutes);
router.use('/api/admin', adminRoutes);
router.use('/api/analytics', analyticsRoutes);
router.use('/api/exports', exportRoutes);

// Health check route
Expand Down
53 changes: 53 additions & 0 deletions src/schemas/metering.schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// src/schemas/metering.schema.js
//
// Zod validation schemas for metering/export endpoints (issue #8).
// Covers the export routes that were missing validation in src/routes/exports.js.

const { z } = require('zod');
const { isoDateString, paginationQuerySchema } = require('./common.schema');

/**
* Query params for listing meter readings via export endpoints.
*/
const readingsQuerySchema = paginationQuerySchema.extend({
meterId: z.string().min(1).optional(),
status: z.enum(['verified', 'pending', 'rejected']).optional(),
unit: z.enum(['kWh', 'kW', 'V', 'A', 'VAR', 'VA']).optional(),
startDate: isoDateString.optional(),
endDate: isoDateString.optional(),
});

/**
* Query params for analytics export endpoints.
*/
const analyticsExportSchema = z.object({
startDate: isoDateString.optional(),
endDate: isoDateString.optional(),
granularity: z.enum(['hour', 'day', 'week', 'month']).default('day'),
format: z.enum(['json', 'csv']).default('json'),
});

/**
* Body schema for creating a meter reading submission.
*/
const createReadingSchema = z.object({
meterId: z.string().min(1),
timestamp: isoDateString,
value: z.number().finite(),
unit: z.enum(['kWh', 'kW', 'V', 'A', 'VAR', 'VA']),
status: z.enum(['verified', 'pending', 'rejected']).default('pending'),
}).strict();

/**
* Body schema for bulk reading import.
*/
const bulkReadingsSchema = z.object({
readings: z.array(createReadingSchema).min(1).max(1000),
}).strict();

module.exports = {
readingsQuerySchema,
analyticsExportSchema,
createReadingSchema,
bulkReadingsSchema,
};