Athena — mahmoud-consultancy/archive/old-docs/API_SPECIFICATION.md

📡 InterimPlaza API Specification

Version: 1.0.0 Base URL: https://api.interimplaza.nl/api Authentication: JWT Bearer Token


🔐 Authentication Endpoints

POST /auth/register

Register a new user account.

Request:

{
  "firstName": "Jan",
  "lastName": "de Vries",
  "email": "jan@example.nl",
  "password": "SecurePass123!",
  "phone": "+31612345678",
  "acceptTerms": true
}

Response: 201 Created

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": 1,
    "firstName": "Jan",
    "lastName": "de Vries",
    "email": "jan@example.nl",
    "role": "USER",
    "emailVerified": false
  }
}

POST /auth/login

Authenticate user and receive tokens.

Request:

{
  "email": "jan@example.nl",
  "password": "SecurePass123!"
}

Response: 200 OK (same structure as register)

POST /auth/refresh

Refresh access token using refresh token.

Request:

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response: 200 OK

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

GET /auth/me

Get current user profile.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
  "id": 1,
  "firstName": "Jan",
  "lastName": "de Vries",
  "email": "jan@example.nl",
  "phone": "+31612345678",
  "role": "USER",
  "emailVerified": true,
  "createdAt": "2025-10-01T10:00:00Z"
}

💼 Job Endpoints

GET /jobs

Get paginated list of active jobs with optional filters.

Query Parameters:

  • page (number): Page number (default: 0)
  • size (number): Items per page (default: 20, max: 100)
  • sort (string): Sort field and direction (e.g., "postedDate,desc")
  • region (string): Filter by region
  • category (string): Filter by category
  • type (string): Filter by job type
  • experienceLevel (string): Filter by experience level
  • salaryMin (number): Minimum salary filter
  • salaryMax (number): Maximum salary filter
  • search (string): Search in title, company, description

Response: 200 OK

{
  "content": [
    {
      "id": 1,
      "title": "Senior Java Developer",
      "company": "ASML",
      "location": "Veldhoven",
      "region": "Noord-Brabant",
      "city": "Veldhoven",
      "description": "We zoeken een ervaren Java Developer...",
      "requirements": "- 5+ jaar Java ervaring\n- Spring Boot",
      "benefits": "- Competitive salary\n- 30 vacation days",
      "salaryMin": 5500,
      "salaryMax": 7500,
      "category": "IT Development",
      "type": "FULL_TIME",
      "experienceLevel": "SENIOR",
      "postedDate": "2025-10-09T10:00:00Z",
      "deadline": "2025-11-09T23:59:59Z",
      "active": true,
      "viewCount": 245,
      "applicationCount": 12
    }
  ],
  "totalElements": 156,
  "totalPages": 8,
  "size": 20,
  "number": 0,
  "first": true,
  "last": false
}

GET /jobs/{id}

Get detailed information about a specific job.

Response: 200 OK

{
  "id": 1,
  "title": "Senior Java Developer",
  "company": "ASML",
  "location": "Veldhoven",
  "region": "Noord-Brabant",
  "city": "Veldhoven",
  "description": "Full job description...",
  "requirements": "Detailed requirements...",
  "benefits": "What we offer...",
  "salaryMin": 5500,
  "salaryMax": 7500,
  "category": "IT Development",
  "type": "FULL_TIME",
  "experienceLevel": "SENIOR",
  "postedDate": "2025-10-09T10:00:00Z",
  "deadline": "2025-11-09T23:59:59Z",
  "sourceUrl": "https://careers.asml.com/job/12345",
  "active": true,
  "viewCount": 246,
  "applicationCount": 12
}

POST /jobs/{id}/view

Increment view count for a job (analytics).

Response: 204 No Content


📝 Application Endpoints

POST /applications

Submit a new job application.

Headers: Authorization: Bearer {token}

Request:

{
  "jobId": 1,
  "coverLetter": "I am very interested in this position...",
  "cvProfileId": 5
}

Response: 201 Created

{
  "id": 42,
  "jobId": 1,
  "userId": 1,
  "jobTitle": "Senior Java Developer",
  "companyName": "ASML",
  "status": "SUBMITTED",
  "coverLetter": "I am very interested...",
  "cvProfileId": 5,
  "appliedDate": "2025-10-11T14:30:00Z",
  "lastUpdated": "2025-10-11T14:30:00Z"
}

GET /applications/my

Get all applications for the current user.

Headers: Authorization: Bearer {token}

Query Parameters:

  • status (string): Filter by status

Response: 200 OK

[
  {
    "id": 42,
    "jobId": 1,
    "userId": 1,
    "jobTitle": "Senior Java Developer",
    "companyName": "ASML",
    "status": "UNDER_REVIEW",
    "coverLetter": "I am very interested...",
    "cvProfileId": 5,
    "appliedDate": "2025-10-11T14:30:00Z",
    "lastUpdated": "2025-10-12T09:15:00Z",
    "notes": "Interview scheduled for next week"
  }
]

GET /applications/{id}

Get details of a specific application.

Headers: Authorization: Bearer {token}

Response: 200 OK (same structure as above)

PUT /applications/{id}/withdraw

Withdraw an application.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
  "id": 42,
  "status": "WITHDRAWN",
  "lastUpdated": "2025-10-13T10:00:00Z"
}

DELETE /applications/{id}

Delete a draft application.

Headers: Authorization: Bearer {token}

Response: 204 No Content

GET /applications/job/{jobId}/applied

Check if user has already applied to a job.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
  "hasApplied": true
}

📁 CV/Document Endpoints

POST /cv/upload

Upload a CV document.

Headers:

  • Authorization: Bearer {token}
  • Content-Type: multipart/form-data

Request: FormData with file

Response: 201 Created

{
  "id": 5,
  "fileName": "jan_de_vries_cv.pdf",
  "fileSize": 245678,
  "mimeType": "application/pdf",
  "uploadedAt": "2025-10-11T14:25:00Z",
  "url": "https://storage.interimplaza.nl/cvs/5.pdf"
}

GET /cv/{id}

Download a CV document.

Headers: Authorization: Bearer {token}

Response: 200 OK with file stream

DELETE /cv/{id}

Delete a CV document.

Headers: Authorization: Bearer {token}

Response: 204 No Content


👤 User Profile Endpoints

PUT /users/profile

Update user profile.

Headers: Authorization: Bearer {token}

Request:

{
  "firstName": "Jan",
  "lastName": "de Vries",
  "phone": "+31612345678"
}

Response: 200 OK (returns updated user object)

PUT /users/password

Change password.

Headers: Authorization: Bearer {token}

Request:

{
  "currentPassword": "OldPass123!",
  "newPassword": "NewPass456!"
}

Response: 204 No Content


👑 Admin Endpoints

GET /admin/users

Get all users (admin only).

Headers: Authorization: Bearer {token} Required Role: ADMIN or RECRUITER

Query Parameters:

  • page, size, sort
  • search (string): Search by name or email
  • role (string): Filter by role

Response: 200 OK

{
  "content": [
    {
      "id": 1,
      "firstName": "Jan",
      "lastName": "de Vries",
      "email": "jan@example.nl",
      "role": "USER",
      "emailVerified": true,
      "active": true,
      "createdAt": "2025-10-01T10:00:00Z",
      "lastLogin": "2025-10-11T14:30:00Z",
      "applicationCount": 5
    }
  ],
  "totalElements": 245,
  "totalPages": 13,
  "number": 0
}

PUT /admin/users/{id}

Update user (admin only).

Headers: Authorization: Bearer {token} Required Role: ADMIN

Request:

{
  "role": "RECRUITER",
  "active": true
}

Response: 200 OK (returns updated user)

GET /admin/applications

Get all applications (admin/recruiter only).

Headers: Authorization: Bearer {token} Required Role: ADMIN or RECRUITER

Query Parameters:

  • page, size, sort
  • status (string): Filter by status
  • jobId (number): Filter by job
  • search (string): Search by candidate name

Response: 200 OK (paginated applications)

PUT /admin/applications/{id}/status

Update application status (recruiter only).

Headers: Authorization: Bearer {token} Required Role: ADMIN or RECRUITER

Request:

{
  "status": "INTERVIEW",
  "notes": "Interview scheduled for Oct 20"
}

Response: 200 OK (returns updated application)

GET /admin/statistics

Get dashboard statistics.

Headers: Authorization: Bearer {token} Required Role: ADMIN or RECRUITER

Response: 200 OK

{
  "totalJobs": 156,
  "activeJobs": 142,
  "totalApplications": 1234,
  "pendingApplications": 234,
  "totalUsers": 567,
  "newUsersThisMonth": 45,
  "applicationsPerMonth": [
    { "month": "2025-06", "count": 89 },
    { "month": "2025-07", "count": 103 }
  ],
  "applicationsByStatus": {
    "SUBMITTED": 120,
    "UNDER_REVIEW": 78,
    "INTERVIEW": 23,
    "OFFERED": 8,
    "REJECTED": 45
  }
}

🔧 Utility Endpoints

GET /jobs/categories

Get list of all job categories.

Response: 200 OK

[
  "IT Development",
  "IT Infrastructure",
  "Finance",
  "Marketing",
  "Human Resources",
  "Engineering",
  "Sales"
]

GET /jobs/regions

Get list of all Dutch regions.

Response: 200 OK

[
  "Noord-Holland",
  "Zuid-Holland",
  "Utrecht",
  "Noord-Brabant",
  "Gelderland",
  ...
]

📋 Status Codes

  • 200 OK - Success
  • 201 Created - Resource created
  • 204 No Content - Success with no response body
  • 400 Bad Request - Validation error
  • 401 Unauthorized - Missing or invalid token
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found
  • 409 Conflict - Duplicate application
  • 422 Unprocessable Entity - Business logic error
  • 500 Internal Server Error - Server error

🔒 Security

Authentication

  • JWT tokens with 1-hour expiration
  • Refresh tokens with 7-day expiration
  • HTTPS required for all requests
  • Rate limiting: 100 requests/minute per IP

Authorization

  • Role-based access control (USER, RECRUITER, ADMIN)
  • Users can only access their own resources
  • Recruiters can view applications for their jobs
  • Admins have full access

Data Protection

  • Passwords hashed with BCrypt (cost factor 12)
  • CV files stored encrypted in MinIO
  • Personal data GDPR compliant
  • Audit logging for sensitive operations

Implementation Status: Backend 60% complete, Frontend 95% complete

Reacties

Nog geen reacties