Implements a new quick entry feature with a dedicated API route and frontend component, allowing users to rapidly log time against projects by selecting a project, date, and predefined hour increments, with automatic creation of timesheets and lines if they don't exist. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 55837015-10e9-4be9-b857-7f5e6be73772 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: c01c2c6b-f846-4f1b-b865-e90687db6de1 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1cc377db-7ea0-49f2-97ce-c3e87e0228cc/55837015-10e9-4be9-b857-7f5e6be73772/cI64U4O Replit-Helium-Checkpoint-Created: true
762 lines
17 KiB
YAML
762 lines
17 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
# Do not change the title, if the title changes, the import paths will be broken
|
|
title: Api
|
|
version: 0.1.0
|
|
description: CRA (Compte Rendu d'Activité) API
|
|
servers:
|
|
- url: /api
|
|
description: Base API path
|
|
tags:
|
|
- name: health
|
|
description: Health operations
|
|
- name: projects
|
|
description: Project management
|
|
- name: timesheets
|
|
description: Timesheet management
|
|
- name: timesheet-lines
|
|
description: Timesheet line management
|
|
- name: time-entries
|
|
description: Time entry management
|
|
- name: dashboard
|
|
description: Dashboard and summary endpoints
|
|
|
|
paths:
|
|
/healthz:
|
|
get:
|
|
operationId: healthCheck
|
|
tags: [health]
|
|
summary: Health check
|
|
description: Returns server health status
|
|
responses:
|
|
"200":
|
|
description: Healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/HealthStatus"
|
|
|
|
/projects:
|
|
get:
|
|
operationId: listProjects
|
|
tags: [projects]
|
|
summary: List all projects
|
|
responses:
|
|
"200":
|
|
description: List of projects
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Project"
|
|
post:
|
|
operationId: createProject
|
|
tags: [projects]
|
|
summary: Create a new project
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateProjectBody"
|
|
responses:
|
|
"201":
|
|
description: Project created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Project"
|
|
|
|
/projects/{id}:
|
|
get:
|
|
operationId: getProject
|
|
tags: [projects]
|
|
summary: Get a project by ID
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Project details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Project"
|
|
"404":
|
|
description: Not found
|
|
patch:
|
|
operationId: updateProject
|
|
tags: [projects]
|
|
summary: Update a project
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpdateProjectBody"
|
|
responses:
|
|
"200":
|
|
description: Project updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Project"
|
|
delete:
|
|
operationId: deleteProject
|
|
tags: [projects]
|
|
summary: Delete a project
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
|
|
/timesheets:
|
|
get:
|
|
operationId: listTimesheets
|
|
tags: [timesheets]
|
|
summary: List timesheets
|
|
parameters:
|
|
- name: year
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: month
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: List of timesheets
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Timesheet"
|
|
post:
|
|
operationId: createTimesheet
|
|
tags: [timesheets]
|
|
summary: Create a new timesheet
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateTimesheetBody"
|
|
responses:
|
|
"201":
|
|
description: Timesheet created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Timesheet"
|
|
|
|
/timesheets/{id}:
|
|
get:
|
|
operationId: getTimesheet
|
|
tags: [timesheets]
|
|
summary: Get timesheet with lines and entries
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Timesheet details with lines
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TimesheetDetail"
|
|
"404":
|
|
description: Not found
|
|
patch:
|
|
operationId: updateTimesheet
|
|
tags: [timesheets]
|
|
summary: Update timesheet status
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpdateTimesheetBody"
|
|
responses:
|
|
"200":
|
|
description: Timesheet updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Timesheet"
|
|
delete:
|
|
operationId: deleteTimesheet
|
|
tags: [timesheets]
|
|
summary: Delete a timesheet
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
|
|
/timesheets/{timesheetId}/lines:
|
|
get:
|
|
operationId: listTimesheetLines
|
|
tags: [timesheet-lines]
|
|
summary: List lines for a timesheet
|
|
parameters:
|
|
- name: timesheetId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Timesheet lines
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TimesheetLine"
|
|
post:
|
|
operationId: createTimesheetLine
|
|
tags: [timesheet-lines]
|
|
summary: Add a line to a timesheet
|
|
parameters:
|
|
- name: timesheetId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateTimesheetLineBody"
|
|
responses:
|
|
"201":
|
|
description: Line created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TimesheetLine"
|
|
|
|
/timesheets/{timesheetId}/lines/{lineId}:
|
|
delete:
|
|
operationId: deleteTimesheetLine
|
|
tags: [timesheet-lines]
|
|
summary: Delete a timesheet line
|
|
parameters:
|
|
- name: timesheetId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
- name: lineId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
|
|
/timesheets/{timesheetId}/entries:
|
|
put:
|
|
operationId: upsertTimeEntries
|
|
tags: [time-entries]
|
|
summary: Create or update time entries for a timesheet (batch)
|
|
parameters:
|
|
- name: timesheetId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UpsertTimeEntriesBody"
|
|
responses:
|
|
"200":
|
|
description: Entries saved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TimeEntry"
|
|
|
|
/quick-entry:
|
|
post:
|
|
operationId: quickAddTime
|
|
tags: [time-entries]
|
|
summary: Quick add time - auto-creates timesheet and line if needed
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/QuickAddTimeBody"
|
|
responses:
|
|
"200":
|
|
description: Time entry saved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/QuickAddTimeResponse"
|
|
|
|
/dashboard/summary:
|
|
get:
|
|
operationId: getDashboardSummary
|
|
tags: [dashboard]
|
|
summary: Get summary stats for the dashboard
|
|
parameters:
|
|
- name: year
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Dashboard summary
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DashboardSummary"
|
|
|
|
/dashboard/monthly-hours:
|
|
get:
|
|
operationId: getMonthlyHours
|
|
tags: [dashboard]
|
|
summary: Get total hours per month for the year
|
|
parameters:
|
|
- name: year
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Monthly hours breakdown
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/MonthlyHours"
|
|
|
|
/dashboard/project-hours:
|
|
get:
|
|
operationId: getProjectHours
|
|
tags: [dashboard]
|
|
summary: Get total hours per project
|
|
parameters:
|
|
- name: year
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: month
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Hours per project
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ProjectHours"
|
|
|
|
components:
|
|
schemas:
|
|
HealthStatus:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
required:
|
|
- status
|
|
|
|
Project:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
code:
|
|
type: string
|
|
name:
|
|
type: string
|
|
parentProjectId:
|
|
type: ["integer", "null"]
|
|
client:
|
|
type: ["string", "null"]
|
|
category:
|
|
type: ["string", "null"]
|
|
isActive:
|
|
type: boolean
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
required:
|
|
- id
|
|
- code
|
|
- name
|
|
- isActive
|
|
- createdAt
|
|
|
|
CreateProjectBody:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
name:
|
|
type: string
|
|
parentProjectId:
|
|
type: ["integer", "null"]
|
|
client:
|
|
type: ["string", "null"]
|
|
category:
|
|
type: ["string", "null"]
|
|
required:
|
|
- code
|
|
- name
|
|
|
|
UpdateProjectBody:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
name:
|
|
type: string
|
|
parentProjectId:
|
|
type: ["integer", "null"]
|
|
client:
|
|
type: ["string", "null"]
|
|
category:
|
|
type: ["string", "null"]
|
|
isActive:
|
|
type: boolean
|
|
|
|
Timesheet:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
year:
|
|
type: integer
|
|
month:
|
|
type: integer
|
|
status:
|
|
type: string
|
|
enum: [draft, submitted, validated]
|
|
collaborator:
|
|
type: string
|
|
totalHours:
|
|
type: number
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
required:
|
|
- id
|
|
- year
|
|
- month
|
|
- status
|
|
- collaborator
|
|
- totalHours
|
|
- createdAt
|
|
- updatedAt
|
|
|
|
CreateTimesheetBody:
|
|
type: object
|
|
properties:
|
|
year:
|
|
type: integer
|
|
month:
|
|
type: integer
|
|
collaborator:
|
|
type: string
|
|
required:
|
|
- year
|
|
- month
|
|
- collaborator
|
|
|
|
UpdateTimesheetBody:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [draft, submitted, validated]
|
|
collaborator:
|
|
type: string
|
|
|
|
TimesheetDetail:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
year:
|
|
type: integer
|
|
month:
|
|
type: integer
|
|
status:
|
|
type: string
|
|
enum: [draft, submitted, validated]
|
|
collaborator:
|
|
type: string
|
|
totalHours:
|
|
type: number
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
lines:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TimesheetLineWithEntries"
|
|
required:
|
|
- id
|
|
- year
|
|
- month
|
|
- status
|
|
- collaborator
|
|
- totalHours
|
|
- createdAt
|
|
- updatedAt
|
|
- lines
|
|
|
|
TimesheetLine:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
timesheetId:
|
|
type: integer
|
|
projectId:
|
|
type: integer
|
|
projectCode:
|
|
type: string
|
|
projectName:
|
|
type: string
|
|
client:
|
|
type: ["string", "null"]
|
|
category:
|
|
type: ["string", "null"]
|
|
totalHours:
|
|
type: number
|
|
required:
|
|
- id
|
|
- timesheetId
|
|
- projectId
|
|
- projectCode
|
|
- projectName
|
|
- totalHours
|
|
|
|
TimesheetLineWithEntries:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
timesheetId:
|
|
type: integer
|
|
projectId:
|
|
type: integer
|
|
projectCode:
|
|
type: string
|
|
projectName:
|
|
type: string
|
|
client:
|
|
type: ["string", "null"]
|
|
category:
|
|
type: ["string", "null"]
|
|
totalHours:
|
|
type: number
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TimeEntry"
|
|
required:
|
|
- id
|
|
- timesheetId
|
|
- projectId
|
|
- projectCode
|
|
- projectName
|
|
- totalHours
|
|
- entries
|
|
|
|
CreateTimesheetLineBody:
|
|
type: object
|
|
properties:
|
|
projectId:
|
|
type: integer
|
|
required:
|
|
- projectId
|
|
|
|
TimeEntry:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
timesheetLineId:
|
|
type: integer
|
|
date:
|
|
type: string
|
|
format: date
|
|
hours:
|
|
type: number
|
|
required:
|
|
- id
|
|
- timesheetLineId
|
|
- date
|
|
- hours
|
|
|
|
UpsertTimeEntriesBody:
|
|
type: object
|
|
properties:
|
|
entries:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
timesheetLineId:
|
|
type: integer
|
|
date:
|
|
type: string
|
|
format: date
|
|
hours:
|
|
type: number
|
|
required:
|
|
- timesheetLineId
|
|
- date
|
|
- hours
|
|
required:
|
|
- entries
|
|
|
|
DashboardSummary:
|
|
type: object
|
|
properties:
|
|
totalHoursThisMonth:
|
|
type: number
|
|
totalHoursThisYear:
|
|
type: number
|
|
activeProjects:
|
|
type: integer
|
|
pendingTimesheets:
|
|
type: integer
|
|
validatedTimesheets:
|
|
type: integer
|
|
required:
|
|
- totalHoursThisMonth
|
|
- totalHoursThisYear
|
|
- activeProjects
|
|
- pendingTimesheets
|
|
- validatedTimesheets
|
|
|
|
MonthlyHours:
|
|
type: object
|
|
properties:
|
|
month:
|
|
type: integer
|
|
totalHours:
|
|
type: number
|
|
label:
|
|
type: string
|
|
required:
|
|
- month
|
|
- totalHours
|
|
- label
|
|
|
|
ProjectHours:
|
|
type: object
|
|
properties:
|
|
projectId:
|
|
type: integer
|
|
projectCode:
|
|
type: string
|
|
projectName:
|
|
type: string
|
|
totalHours:
|
|
type: number
|
|
required:
|
|
- projectId
|
|
- projectCode
|
|
- projectName
|
|
- totalHours
|
|
|
|
QuickAddTimeBody:
|
|
type: object
|
|
properties:
|
|
projectId:
|
|
type: integer
|
|
date:
|
|
type: string
|
|
format: date
|
|
hours:
|
|
type: number
|
|
collaborator:
|
|
type: string
|
|
required:
|
|
- projectId
|
|
- date
|
|
- hours
|
|
- collaborator
|
|
|
|
QuickAddTimeResponse:
|
|
type: object
|
|
properties:
|
|
timesheetId:
|
|
type: integer
|
|
timesheetLineId:
|
|
type: integer
|
|
entryId:
|
|
type: integer
|
|
date:
|
|
type: string
|
|
format: date
|
|
hours:
|
|
type: number
|
|
projectCode:
|
|
type: string
|
|
projectName:
|
|
type: string
|
|
required:
|
|
- timesheetId
|
|
- timesheetLineId
|
|
- entryId
|
|
- date
|
|
- hours
|
|
- projectCode
|
|
- projectName
|