From 7f30a214f7ee8ffdf145d858b1a4f4f10b017825 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Wed, 24 Dec 2025 11:25:55 -0300 Subject: [PATCH] docs: add API documentation with routes and permissions - Create docs/API.md with complete API reference - 40+ routes documented - Permission matrix by role - Module breakdown (Auth, Users, Jobs, Applications, etc.) - Error response examples - ID format documentation - Fix seeders to use SERIAL (not UUID) for jobs.id - jobs.js: let DB auto-generate id - acme.js, fictional-companies.js, epic-companies.js: same fix - Update README.md with API documentation link --- README.md | 1 + docs/API.md | 480 ++++++++++++++++++ seeder-api/src/seeders/acme.js | 6 +- seeder-api/src/seeders/epic-companies.js | 6 +- seeder-api/src/seeders/fictional-companies.js | 18 +- seeder-api/src/seeders/jobs.js | 7 +- 6 files changed, 499 insertions(+), 19 deletions(-) create mode 100644 docs/API.md diff --git a/README.md b/README.md index b9113dd..5fac102 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ Veja a documentaΓ§Γ£o completa do banco de dados em: [docs/DATABASE.md](docs/DAT ### Roadmap & Tarefas - πŸ—ΊοΈ **Roadmap:** [docs/ROADMAP.md](docs/ROADMAP.md) - Status e progresso do projeto - πŸ“‹ **Tarefas:** [docs/TASKS.md](docs/TASKS.md) - Lista detalhada para evitar retrabalho +- πŸ“‘ **API:** [docs/API.md](docs/API.md) - DocumentaΓ§Γ£o completa com rotas e permissΓ΅es ### DocumentaΓ§Γ£o por Componente | Componente | DocumentaΓ§Γ£o | diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..23d2e39 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,480 @@ +# πŸ“‘ GoHorse Jobs - API Documentation + +Complete API reference with routes, permissions, and modules. + +> **Last Updated:** 2024-12-24 +> **Base URL:** `http://localhost:8521/api/v1` +> **Auth:** JWT Bearer Token or HttpOnly Cookie + +--- + +## πŸ” Authentication + +### Methods +1. **Authorization Header:** `Authorization: Bearer ` +2. **Cookie:** `jwt=` (HttpOnly, Secure) + +### Roles +| Role | Code | Level | Description | +|------|------|-------|-------------| +| **SuperAdmin** | `superadmin` | 0 | Platform administrator | +| **CompanyAdmin** | `companyAdmin` | 1 | Company administrator | +| **Recruiter** | `recruiter` | 2 | Job poster | +| **JobSeeker** | `jobSeeker` | 3 | Candidate | +| **Guest** | - | - | No authentication | + +--- + +## πŸ“‹ Module: Authentication + +### Login +```http +POST /api/v1/auth/login +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Authenticate user | + +**Request:** +```json +{ + "identifier": "superadmin", + "password": "Admin@2025!" +} +``` + +**Response (200):** +```json +{ + "token": "eyJhbGciOiJI...", + "user": { "id": 1, "role": "superadmin", "name": "Super Administrator" } +} +``` + +--- + +### Register Candidate +```http +POST /api/v1/auth/register +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Register new job seeker | + +**Request:** +```json +{ + "name": "John Doe", + "email": "john@example.com", + "password": "SecurePass123!" +} +``` + +--- + +## 🏒 Module: Companies + +### Create Company +```http +POST /api/v1/companies +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Register new company | + +### List Companies +```http +GET /api/v1/companies +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Smart | βšͺ Optional | Guest/Admin | Public list or admin full list | + +### Update Company Status +```http +PATCH /api/v1/companies/{id}/status +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Activate/deactivate company | + +--- + +## πŸ‘₯ Module: Users + +### Get Current User +```http +GET /api/v1/users/me +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Get current user profile | + +### List Users +```http +GET /api/v1/users +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | List all users | + +### Create User +```http +POST /api/v1/users +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, companyAdmin | Create new user | + +### Update User +```http +PATCH /api/v1/users/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Update user profile | + +### Delete User +```http +DELETE /api/v1/users/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin | Delete user | + +### List User Roles +```http +GET /api/v1/users/roles +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | List available roles | + +--- + +## πŸ’Ό Module: Jobs + +### List Jobs (Public) +```http +GET /api/v1/jobs +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Search and filter jobs | + +**Query Parameters:** +| Param | Type | Description | +|-------|------|-------------| +| `q` | string | Search query (title, description) | +| `location` | string | Filter by location | +| `type` | string | Employment type filter | +| `workMode` | string | `onsite`, `hybrid`, `remote` | +| `page` | int | Page number (default: 1) | +| `limit` | int | Items per page (default: 20) | + +### Get Job by ID +```http +GET /api/v1/jobs/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Get job details | + +### Create Job +```http +POST /api/v1/jobs +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public* | ❌ | companyAdmin, recruiter | Create new job posting | + +### Update Job +```http +PUT /api/v1/jobs/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public* | ❌ | companyAdmin, recruiter | Update job posting | + +### Delete Job +```http +DELETE /api/v1/jobs/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public* | ❌ | companyAdmin, recruiter | Delete job posting | + +### List Jobs for Moderation +```http +GET /api/v1/jobs/moderation +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | List all jobs for moderation | + +### Update Job Status +```http +PATCH /api/v1/jobs/{id}/status +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Approve/reject/close job | + +### Duplicate Job +```http +POST /api/v1/jobs/{id}/duplicate +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Duplicate job posting | + +--- + +## πŸ“ Module: Applications + +### Create Application +```http +POST /api/v1/applications +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest/JobSeeker | Apply to a job | + +**Request:** +```json +{ + "job_id": 123, + "name": "John Doe", + "email": "john@example.com", + "phone": "+55 11 99999-9999", + "message": "I am interested in this position...", + "resume_url": "https://..." +} +``` + +### List Applications +```http +GET /api/v1/applications +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | companyAdmin, recruiter | List applications | + +### Get Application by ID +```http +GET /api/v1/applications/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | companyAdmin, recruiter | Get application details | + +### Update Application Status +```http +PUT /api/v1/applications/{id}/status +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | companyAdmin, recruiter | Update application status | + +**Request:** +```json +{ + "status": "hired", + "notes": "Approved after final interview" +} +``` + +**Status Values:** +- `pending` - Awaiting review +- `reviewed` - Seen by recruiter +- `shortlisted` - Selected for interview +- `rejected` - Not selected +- `hired` - Offer accepted + +--- + +## πŸ”” Module: Notifications + +### List Notifications +```http +GET /api/v1/notifications +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Get user notifications | + +--- + +## 🏷️ Module: Tags + +### List Tags +```http +GET /api/v1/tags +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | List all tags | + +### Create Tag +```http +POST /api/v1/tags +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Create new tag | + +### Update Tag +```http +PATCH /api/v1/tags/{id} +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Update tag | + +--- + +## πŸ‘€ Module: Candidates + +### List Candidates +```http +GET /api/v1/candidates +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | List all candidates | + +--- + +## πŸ“Š Module: Audit + +### List Login Audits +```http +GET /api/v1/audit/logins +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | superadmin, admin | Login audit trail | + +--- + +## πŸ“¦ Module: Storage + +### Generate Upload URL +```http +POST /api/v1/storage/upload-url +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Get S3 presigned upload URL | + +### Generate Download URL +```http +POST /api/v1/storage/download-url +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Get S3 presigned download URL | + +### Delete File +```http +DELETE /api/v1/storage/files +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Protected | βœ… | Any authenticated | Delete file from S3 | + +--- + +## πŸ“š Module: Documentation + +### Swagger UI +```http +GET /docs/ +``` +| Field | Auth | Roles | Description | +|-------|------|-------|-------------| +| Public | ❌ | Guest | Interactive API documentation | + +--- + +## πŸ”‘ Permission Matrix + +| Route | Guest | JobSeeker | Recruiter | CompanyAdmin | Admin | SuperAdmin | +|-------|-------|-----------|-----------|--------------|-------|------------| +| `POST /auth/login` | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… | +| `POST /auth/register` | βœ… | ❌ | ❌ | ❌ | ❌ | ❌ | +| `GET /jobs` | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… | +| `GET /jobs/{id}` | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… | +| `POST /jobs` | ❌ | ❌ | βœ… | βœ… | βœ… | βœ… | +| `POST /applications` | βœ… | βœ… | ❌ | ❌ | ❌ | ❌ | +| `GET /users/me` | ❌ | βœ… | βœ… | βœ… | βœ… | βœ… | +| `GET /users` | ❌ | ❌ | ❌ | ❌ | βœ… | βœ… | +| `DELETE /users/{id}` | ❌ | ❌ | ❌ | ❌ | ❌ | βœ… | +| `GET /notifications` | ❌ | βœ… | βœ… | βœ… | βœ… | βœ… | +| `GET /audit/logins` | ❌ | ❌ | ❌ | ❌ | βœ… | βœ… | +| `GET /jobs/moderation` | ❌ | ❌ | ❌ | ❌ | βœ… | βœ… | + +--- + +## πŸ†” ID Formats + +| Entity | ID Type | Example | +|--------|---------|---------| +| Users | INT (SERIAL) | `1`, `42`, `1337` | +| Companies | INT (SERIAL) | `1`, `15`, `100` | +| Jobs | INT (SERIAL) | `1`, `500`, `2500` | +| Notifications | UUID v7 | `019438a1-2b3c-7abc-8123-4567890abcdef` | +| Tickets | UUID v7 | `019438a2-3c4d-7xyz-9abc-def0123456789` | +| Payments | UUID v7 | `019438a3-4e5f-7mno-pqrs-tuvwxyz012345` | + +--- + +## πŸ“ Error Responses + +### 400 Bad Request +```json +{ + "error": "Invalid request body", + "details": "Field 'email' is required" +} +``` + +### 401 Unauthorized +```json +{ + "error": "Unauthorized", + "message": "Invalid or expired token" +} +``` + +### 403 Forbidden +```json +{ + "error": "Forbidden", + "message": "Insufficient permissions" +} +``` + +### 404 Not Found +```json +{ + "error": "Not Found", + "message": "Resource not found" +} +``` + +### 500 Internal Server Error +```json +{ + "error": "Internal Server Error", + "message": "An unexpected error occurred" +} +``` + +--- + +## πŸ“š Related Documentation + +- [Database Schema](DATABASE.md) +- [Roadmap](ROADMAP.md) +- [Tasks](TASKS.md) diff --git a/seeder-api/src/seeders/acme.js b/seeder-api/src/seeders/acme.js index cf511db..58e181e 100644 --- a/seeder-api/src/seeders/acme.js +++ b/seeder-api/src/seeders/acme.js @@ -192,15 +192,15 @@ export async function seedAcmeCorp() { for (let b = 0; b < 4; b++) { selectedBenefits.push(benefits[(i + b) % benefits.length]); } - const jobId = crypto.randomUUID(); + await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs ( company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, + acmeCompanyId, seedUserId, title, diff --git a/seeder-api/src/seeders/epic-companies.js b/seeder-api/src/seeders/epic-companies.js index a0739ed..caed7cf 100644 --- a/seeder-api/src/seeders/epic-companies.js +++ b/seeder-api/src/seeders/epic-companies.js @@ -294,14 +294,14 @@ async function createCompanyAndJobs(companyData, jobs) { for (let i = 0; i < jobs.length; i++) { const job = jobs[i]; - const jobId = crypto.randomUUID(); + await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs ( company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, + companyId, seedUserId, job.title, diff --git a/seeder-api/src/seeders/fictional-companies.js b/seeder-api/src/seeders/fictional-companies.js index 7bded85..e342d31 100644 --- a/seeder-api/src/seeders/fictional-companies.js +++ b/seeder-api/src/seeders/fictional-companies.js @@ -190,14 +190,14 @@ export async function seedStarkIndustries() { for (let i = 0; i < starkJobs.length; i++) { const job = starkJobs[i]; - const jobId = crypto.randomUUID(); + await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs ( company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, + companyId, seedUserId, job.title, @@ -275,14 +275,14 @@ export async function seedLosPollosHermanos() { for (let i = 0; i < losPollosJobs.length; i++) { const job = losPollosJobs[i]; - const jobId = crypto.randomUUID(); + await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs ( company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, + companyId, seedUserId, job.title, @@ -362,14 +362,14 @@ export async function seedSpringfieldNuclear() { for (let i = 0; i < springfieldJobs.length; i++) { const job = springfieldJobs[i]; - const jobId = crypto.randomUUID(); + await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs ( company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, + companyId, seedUserId, job.title, diff --git a/seeder-api/src/seeders/jobs.js b/seeder-api/src/seeders/jobs.js index c3a83e9..3b226b8 100644 --- a/seeder-api/src/seeders/jobs.js +++ b/seeder-api/src/seeders/jobs.js @@ -97,15 +97,14 @@ export async function seedJobs() { const employmentType = employmentTypes[i % employmentTypes.length]; const currency = currencies[i % currencies.length]; const salaryType = salaryTypes[i % salaryTypes.length]; - const jobId = crypto.randomUUID(); + // jobs.id is SERIAL - let DB auto-generate await pool.query(` - INSERT INTO jobs (id, company_id, created_by, title, description, + INSERT INTO jobs (company_id, created_by, title, description, salary_min, salary_max, salary_type, currency, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ - jobId, company.id, seedUserId, title,