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 description: type: string nullable: true 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