Add Time Tracking backend API

Implementovaný kompletný backend pre time tracking:
- Nová tabuľka time_entries s foreign keys na users, projects, todos, companies
- Service layer s business logikou pre CRUD operácie
- Controller pre všetky endpointy
- Validačné schémy pomocou Zod
- Routes s autentifikáciou a validáciou
- Endpointy:
  * POST /api/time-tracking/start - Spustenie timeru
  * POST /api/time-tracking/:id/stop - Zastavenie timeru
  * GET /api/time-tracking/running - Získanie bežiaceho záznamu
  * GET /api/time-tracking/month/:year/:month - Mesačné záznamy
  * GET /api/time-tracking/stats/monthly/:year/:month - Mesačné štatistiky
  * PATCH /api/time-tracking/:id - Aktualizácia záznamu
  * DELETE /api/time-tracking/:id - Zmazanie záznamu
- Podpora pre isEdited flag pri editácii
- Kalkulácia duration v minútach

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
richardtekula
2025-11-24 06:41:39 +01:00
parent ca93b6f2d2
commit 540c1719d3
7 changed files with 843 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import express from 'express';
import * as timeTrackingController from '../controllers/time-tracking.controller.js';
import { authenticate } from '../middlewares/auth/authMiddleware.js';
import { validateBody, validateParams } from '../middlewares/security/validateInput.js';
import {
startTimeEntrySchema,
stopTimeEntrySchema,
updateTimeEntrySchema,
} from '../validators/crm.validators.js';
import { z } from 'zod';
const router = express.Router();
// All time tracking routes require authentication
router.use(authenticate);
/**
* Time Tracking management
*/
// Start new time entry
router.post('/start', validateBody(startTimeEntrySchema), timeTrackingController.startTimeEntry);
// Stop running time entry
router.post(
'/:entryId/stop',
validateParams(z.object({ entryId: z.string().uuid() })),
validateBody(stopTimeEntrySchema),
timeTrackingController.stopTimeEntry
);
// Get running time entry
router.get('/running', timeTrackingController.getRunningTimeEntry);
// Get all time entries with filters
router.get('/', timeTrackingController.getAllTimeEntries);
// Get monthly time entries
router.get(
'/month/:year/:month',
validateParams(
z.object({
year: z.string().regex(/^\d{4}$/, 'Rok musí byť 4-ciferné číslo'),
month: z.string().regex(/^(0?[1-9]|1[0-2])$/, 'Mesiac musí byť číslo 1-12'),
})
),
timeTrackingController.getMonthlyTimeEntries
);
// Get monthly statistics
router.get(
'/stats/monthly/:year/:month',
validateParams(
z.object({
year: z.string().regex(/^\d{4}$/, 'Rok musí byť 4-ciferné číslo'),
month: z.string().regex(/^(0?[1-9]|1[0-2])$/, 'Mesiac musí byť číslo 1-12'),
})
),
timeTrackingController.getMonthlyStats
);
// Get time entry by ID
router.get(
'/:entryId',
validateParams(z.object({ entryId: z.string().uuid() })),
timeTrackingController.getTimeEntryById
);
// Get time entry with relations
router.get(
'/:entryId/details',
validateParams(z.object({ entryId: z.string().uuid() })),
timeTrackingController.getTimeEntryWithRelations
);
// Update time entry
router.patch(
'/:entryId',
validateParams(z.object({ entryId: z.string().uuid() })),
validateBody(updateTimeEntrySchema),
timeTrackingController.updateTimeEntry
);
// Delete time entry
router.delete(
'/:entryId',
validateParams(z.object({ entryId: z.string().uuid() })),
timeTrackingController.deleteTimeEntry
);
export default router;