751 lines
19 KiB
Markdown
751 lines
19 KiB
Markdown
# 🗄️ Database Schema Documentation
|
||
|
||
Complete database documentation for the GoHorseJobs platform.
|
||
|
||
> **Last Updated:** 2026-01-03
|
||
> **Database:** PostgreSQL 16+ (Local `postgres-main` container)
|
||
> **Connection:** Internal `gohorsejobs_dev` database via `web_proxy` network
|
||
> **ID Strategy:** UUID v7 for core tables, SERIAL for reference tables
|
||
> **Migrations:** 30 SQL files in `backend/migrations/`
|
||
|
||
---
|
||
|
||
## <20>️ Development Environment Structure
|
||
|
||
The development environment (`apolo` server) uses a **Local Containerized Strategy** to ensure isolation and speed.
|
||
|
||
### 🏗️ Topology
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph VPS ["Apolo Server (VPS)"]
|
||
subgraph Net ["Docker Network: web_proxy"]
|
||
PG[("postgres-main")]
|
||
BE["Backend API"]
|
||
BO["Backoffice"]
|
||
SE["Seeder API"]
|
||
end
|
||
Traefik["Traefik Proxy"]
|
||
end
|
||
|
||
Traefik --> BE
|
||
Traefik --> BO
|
||
Traefik --> SE
|
||
|
||
BE -- "internal:5432" --> PG
|
||
BO -- "internal:5432" --> PG
|
||
SE -- "internal:5432" --> PG
|
||
|
||
style PG fill:#336791,stroke:#fff,stroke-width:2px,color:#fff
|
||
```
|
||
|
||
### 🔌 Connection Details
|
||
|
||
All services connect to the database via the internal Docker network.
|
||
|
||
| Parameter | Value | Notes |
|
||
|-----------|-------|-------|
|
||
| **Host** | `postgres-main` | Internal Container Hostname |
|
||
| **Port** | `5432` | Internal Port |
|
||
| **Database** | `gohorsejobs_dev` | Dedicated Dev DB (Isolated from `main_db`) |
|
||
| **User** | `yuki` | Owner of public schema |
|
||
| **Network** | `web_proxy` | Shared Bridge Network |
|
||
| **SSL Mode** | `disable` | Internal traffic is unencrypted |
|
||
|
||
### 🚀 Access & Management
|
||
|
||
Since the database runs inside a container and is not exposed to the public internet, use the following methods for access:
|
||
|
||
**1. CLI Access (via SSH)**
|
||
```bash
|
||
# Connect to PostgreSQL shell
|
||
ssh root@apolo 'podman exec -it postgres-main psql -U yuki -d gohorsejobs_dev'
|
||
```
|
||
|
||
**2. Run Migrations**
|
||
Migrations are applied using the Backend service or manually piped:
|
||
```bash
|
||
# Manual Pipe (from local machine)
|
||
cat backend/migrations/*.sql | ssh root@apolo 'podman exec -i postgres-main psql -U yuki -d gohorsejobs_dev'
|
||
```
|
||
|
||
**3. Seeding Data**
|
||
Trigger the Seeder API (running locally) to populate data:
|
||
```bash
|
||
curl -X POST https://seeder.gohorsejobs.com/seed
|
||
```
|
||
|
||
|
||
## <20>📊 Entity Relationship Diagram
|
||
|
||
```mermaid
|
||
erDiagram
|
||
%% Core Entities
|
||
users ||--o{ user_companies : "belongs to"
|
||
users ||--o{ user_roles : "has roles"
|
||
users ||--o{ applications : "submits"
|
||
users ||--o{ favorite_jobs : "saves"
|
||
users ||--o{ notifications : "receives"
|
||
users ||--o{ tickets : "opens"
|
||
users ||--o{ ticket_messages : "sends"
|
||
users ||--o{ login_audits : "generates"
|
||
users ||--o{ activity_logs : "generates"
|
||
|
||
companies ||--o{ user_companies : "has members"
|
||
companies ||--o{ jobs : "posts"
|
||
|
||
jobs ||--o{ applications : "receives"
|
||
jobs ||--o{ favorite_jobs : "saved by"
|
||
jobs ||--o{ job_payments : "has payments"
|
||
|
||
regions ||--o{ cities : "contains"
|
||
regions ||--o{ companies : "located in"
|
||
regions ||--o{ jobs : "located in"
|
||
|
||
tickets ||--o{ ticket_messages : "contains"
|
||
|
||
%% Entities
|
||
users {
|
||
int id PK "SERIAL"
|
||
varchar identifier UK "login"
|
||
varchar password_hash
|
||
varchar role "enum"
|
||
varchar full_name
|
||
varchar email
|
||
varchar name
|
||
int tenant_id FK "nullable"
|
||
varchar status
|
||
}
|
||
|
||
user_roles {
|
||
int user_id PK,FK
|
||
varchar role PK "composite key"
|
||
}
|
||
|
||
companies {
|
||
int id PK "SERIAL"
|
||
varchar name
|
||
varchar slug UK
|
||
varchar type
|
||
varchar document
|
||
text address
|
||
int region_id FK
|
||
varchar email
|
||
varchar website
|
||
boolean verified
|
||
boolean active
|
||
}
|
||
|
||
jobs {
|
||
int id PK "SERIAL"
|
||
int company_id FK
|
||
int created_by FK
|
||
varchar title
|
||
text description
|
||
decimal salary_min
|
||
decimal salary_max
|
||
varchar salary_type
|
||
varchar currency
|
||
varchar employment_type
|
||
varchar work_mode
|
||
varchar status
|
||
boolean is_featured
|
||
}
|
||
|
||
applications {
|
||
int id PK "SERIAL"
|
||
int job_id FK
|
||
int user_id FK "nullable"
|
||
varchar status
|
||
text message
|
||
varchar resume_url
|
||
}
|
||
|
||
regions {
|
||
int id PK "SERIAL"
|
||
varchar name
|
||
varchar country_code
|
||
varchar code
|
||
}
|
||
|
||
cities {
|
||
int id PK "SERIAL"
|
||
int region_id FK
|
||
varchar name
|
||
}
|
||
|
||
notifications {
|
||
uuid id PK
|
||
int user_id FK
|
||
varchar type
|
||
varchar title
|
||
text message
|
||
boolean read
|
||
}
|
||
|
||
job_payments {
|
||
uuid id PK
|
||
int job_id FK
|
||
int user_id FK
|
||
decimal amount
|
||
varchar status
|
||
varchar stripe_session_id
|
||
}
|
||
|
||
tickets {
|
||
uuid id PK
|
||
int user_id FK
|
||
varchar subject
|
||
varchar status
|
||
varchar priority
|
||
}
|
||
|
||
ticket_messages {
|
||
uuid id PK
|
||
uuid ticket_id FK
|
||
int user_id FK
|
||
text message
|
||
boolean is_staff
|
||
}
|
||
|
||
job_posting_prices {
|
||
int id PK
|
||
varchar name
|
||
decimal price
|
||
int duration_days
|
||
}
|
||
|
||
login_audits {
|
||
int id PK
|
||
int user_id FK
|
||
varchar identifier
|
||
boolean success
|
||
varchar ip_address
|
||
}
|
||
|
||
activity_logs {
|
||
int id PK
|
||
int user_id FK
|
||
varchar entity_type
|
||
varchar action
|
||
jsonb details
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🏗️ Table Overview
|
||
|
||
| Table | ID Type | Description | Migration |
|
||
|-------|---------|-------------|-----------|
|
||
| `users` | UUID v7 | System users (candidates, recruiters, admins) | 001/021 |
|
||
| `user_roles` | Composite | Additional roles per user | 020 |
|
||
| `companies` | UUID v7 | Employer organizations | 002/021 |
|
||
| `user_companies` | UUID v7 | User ↔ Company mapping | 003/021 |
|
||
| `regions` | SERIAL | States/Provinces/Prefectures | 004 |
|
||
| `cities` | SERIAL | Cities within regions | 004 |
|
||
| `jobs` | UUID v7 | Job postings | 005/021 |
|
||
| `applications` | UUID v7 | Job applications | 006/021 |
|
||
| `favorite_jobs` | SERIAL | Saved jobs by users | 007 |
|
||
| `password_resets` | SERIAL | Password reset tokens | 008 |
|
||
| `notifications` | UUID v7 | User notifications | 016 |
|
||
| `tickets` | UUID v7 | Support tickets | 017 |
|
||
| `ticket_messages` | UUID v7 | Ticket messages | 017 |
|
||
| `job_payments` | UUID v7 | Payment records | 019 |
|
||
| `job_posting_prices` | SERIAL | Pricing configuration | 019 |
|
||
| `login_audits` | SERIAL | Login audit trail | 013 |
|
||
| `activity_logs` | SERIAL | Activity logging | 013 |
|
||
|
||
---
|
||
|
||
## 📋 Core Tables
|
||
|
||
### `users`
|
||
|
||
System users including Candidates, Recruiters, and Admins.
|
||
|
||
```sql
|
||
CREATE TABLE users (
|
||
id SERIAL PRIMARY KEY,
|
||
identifier VARCHAR(100) UNIQUE NOT NULL, -- Login (username/email)
|
||
password_hash VARCHAR(255) NOT NULL,
|
||
role VARCHAR(20) NOT NULL, -- 'superadmin'|'admin'|'recruiter'|'candidate'
|
||
|
||
-- Profile
|
||
full_name VARCHAR(255),
|
||
email VARCHAR(255),
|
||
name VARCHAR(255),
|
||
phone VARCHAR(30),
|
||
|
||
-- Candidate Profile Fields (015)
|
||
city VARCHAR(100),
|
||
state VARCHAR(50),
|
||
title VARCHAR(100),
|
||
experience VARCHAR(100),
|
||
skills TEXT[],
|
||
bio TEXT,
|
||
objective TEXT,
|
||
|
||
-- Multi-tenancy (020)
|
||
tenant_id INT REFERENCES companies(id),
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
|
||
-- Settings
|
||
language VARCHAR(5) DEFAULT 'en',
|
||
active BOOLEAN DEFAULT true,
|
||
|
||
-- Timestamps
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
last_login_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
**Roles:**
|
||
- `superadmin` - Platform administrator
|
||
- `admin` - Company administrator
|
||
- `recruiter` - Job poster/recruiter
|
||
- `candidate` - Candidate/job seeker
|
||
|
||
---
|
||
|
||
### `user_roles`
|
||
|
||
Additional roles per user (for multi-role support).
|
||
|
||
```sql
|
||
CREATE TABLE user_roles (
|
||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
role VARCHAR(50) NOT NULL,
|
||
PRIMARY KEY (user_id, role)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
### `companies`
|
||
|
||
Employer organizations that post jobs.
|
||
|
||
```sql
|
||
CREATE TABLE companies (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(255) NOT NULL,
|
||
slug VARCHAR(255) UNIQUE NOT NULL, -- URL-friendly name
|
||
type VARCHAR(50) DEFAULT 'company', -- 'company'|'agency'|'system'
|
||
document VARCHAR(100), -- CNPJ/Tax ID
|
||
|
||
-- Location
|
||
address TEXT,
|
||
region_id INT REFERENCES regions(id),
|
||
city_id INT REFERENCES cities(id),
|
||
|
||
-- Contact
|
||
phone VARCHAR(30),
|
||
email VARCHAR(255),
|
||
website VARCHAR(255),
|
||
|
||
-- Branding
|
||
logo_url TEXT,
|
||
description TEXT, -- JSON or plain text
|
||
|
||
-- Status
|
||
active BOOLEAN DEFAULT true,
|
||
verified BOOLEAN DEFAULT false,
|
||
|
||
-- Timestamps
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
### `jobs`
|
||
|
||
Job postings created by companies.
|
||
|
||
```sql
|
||
CREATE TABLE jobs (
|
||
id SERIAL PRIMARY KEY,
|
||
company_id INT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||
created_by INT NOT NULL REFERENCES users(id),
|
||
|
||
-- Job Details
|
||
title VARCHAR(255) NOT NULL,
|
||
description TEXT NOT NULL,
|
||
|
||
-- Salary
|
||
salary_min DECIMAL(12,2),
|
||
salary_max DECIMAL(12,2),
|
||
salary_type VARCHAR(20), -- 'hourly'|'daily'|'weekly'|'monthly'|'yearly'
|
||
currency VARCHAR(3), -- 'BRL'|'USD'|'EUR'|'GBP'|'JPY'
|
||
|
||
-- Employment
|
||
employment_type VARCHAR(30), -- 'full-time'|'part-time'|'contract'|'dispatch'|...
|
||
work_mode VARCHAR(10), -- 'onsite'|'hybrid'|'remote'
|
||
working_hours VARCHAR(100),
|
||
|
||
-- Location
|
||
location VARCHAR(255),
|
||
region_id INT REFERENCES regions(id),
|
||
city_id INT REFERENCES cities(id),
|
||
|
||
-- Requirements & Benefits
|
||
requirements JSONB, -- Array of skills/requirements
|
||
benefits JSONB, -- Array of benefits
|
||
|
||
-- Visa & Language
|
||
visa_support BOOLEAN DEFAULT false,
|
||
language_level VARCHAR(20), -- 'N5'|'N4'|'N3'|'N2'|'N1'|'beginner'|'none'
|
||
|
||
-- Status
|
||
status VARCHAR(20) DEFAULT 'open', -- 'draft'|'open'|'closed'|'published'|...
|
||
is_featured BOOLEAN DEFAULT false,
|
||
|
||
-- Timestamps
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
**Status Values:**
|
||
- `draft` - Not published yet
|
||
- `open` - Accepting applications
|
||
- `published` - Live and visible
|
||
- `paused` - Temporarily hidden
|
||
- `closed` - No longer accepting
|
||
- `expired` - Past expiration date
|
||
- `archived` - Archived by employer
|
||
- `reported` - Flagged for review
|
||
- `review` - Under admin review
|
||
|
||
---
|
||
|
||
### `applications`
|
||
|
||
Job applications from candidates.
|
||
|
||
```sql
|
||
CREATE TABLE applications (
|
||
id SERIAL PRIMARY KEY,
|
||
job_id INT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
||
user_id INT REFERENCES users(id), -- Nullable for guest applications
|
||
|
||
-- Applicant Info
|
||
name VARCHAR(255) NOT NULL,
|
||
email VARCHAR(255) NOT NULL,
|
||
phone VARCHAR(30),
|
||
line_id VARCHAR(100),
|
||
whatsapp VARCHAR(30),
|
||
|
||
-- Application Content
|
||
message TEXT,
|
||
resume_url VARCHAR(500),
|
||
documents JSONB,
|
||
|
||
-- Status
|
||
status VARCHAR(20) DEFAULT 'pending', -- 'pending'|'reviewed'|'shortlisted'|'rejected'|'hired'
|
||
notes TEXT, -- Recruiter notes
|
||
|
||
-- Timestamps
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🌍 Geographic Tables
|
||
|
||
### `regions`
|
||
|
||
States, provinces, or prefectures.
|
||
|
||
```sql
|
||
CREATE TABLE regions (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(100) NOT NULL,
|
||
country_code VARCHAR(2) NOT NULL, -- 'BR'|'US'|'JP'
|
||
code VARCHAR(10) NOT NULL -- 'SP'|'CA'|'13'
|
||
);
|
||
```
|
||
|
||
**Seeded Regions:**
|
||
- 🇧🇷 Brazil: São Paulo (SP), Rio de Janeiro (RJ), Minas Gerais (MG)
|
||
- 🇺🇸 USA: California (CA), New York (NY), Texas (TX)
|
||
- 🇯🇵 Japan: Tokyo (13), Osaka (27)
|
||
|
||
---
|
||
|
||
### `cities`
|
||
|
||
Cities within regions.
|
||
|
||
```sql
|
||
CREATE TABLE cities (
|
||
id SERIAL PRIMARY KEY,
|
||
region_id INT NOT NULL REFERENCES regions(id),
|
||
name VARCHAR(100) NOT NULL
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 💰 Payment Tables
|
||
|
||
### `job_payments` (UUID)
|
||
|
||
Payment records for job postings.
|
||
|
||
```sql
|
||
CREATE TABLE job_payments (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
job_id INT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
||
user_id INT REFERENCES users(id) ON DELETE SET NULL,
|
||
|
||
-- Stripe
|
||
stripe_session_id VARCHAR(255),
|
||
stripe_payment_intent VARCHAR(255),
|
||
stripe_customer_id VARCHAR(255),
|
||
|
||
-- Amount
|
||
amount DECIMAL(12,2) NOT NULL,
|
||
currency VARCHAR(3) DEFAULT 'USD',
|
||
|
||
-- Status
|
||
status VARCHAR(20) DEFAULT 'pending', -- 'pending'|'completed'|'failed'|'refunded'|'expired'
|
||
|
||
-- Billing
|
||
billing_type VARCHAR(20), -- 'company'|'individual'
|
||
billing_name VARCHAR(255),
|
||
billing_email VARCHAR(255),
|
||
|
||
-- Job Details
|
||
duration_days INT DEFAULT 30,
|
||
is_featured BOOLEAN DEFAULT false,
|
||
|
||
-- Timestamps
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
paid_at TIMESTAMP,
|
||
expires_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
### `job_posting_prices`
|
||
|
||
Pricing configuration for job postings.
|
||
|
||
```sql
|
||
CREATE TABLE job_posting_prices (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(100) NOT NULL,
|
||
description TEXT,
|
||
price DECIMAL(12,2) NOT NULL,
|
||
currency VARCHAR(3) DEFAULT 'USD',
|
||
duration_days INT DEFAULT 30,
|
||
is_featured BOOLEAN DEFAULT false,
|
||
stripe_price_id VARCHAR(255),
|
||
active BOOLEAN DEFAULT true,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔔 Notification Tables
|
||
|
||
### `notifications` (UUID)
|
||
|
||
User notifications.
|
||
|
||
```sql
|
||
CREATE TABLE notifications (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
type VARCHAR(50),
|
||
title VARCHAR(255),
|
||
message TEXT,
|
||
read BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🎫 Support Tables
|
||
|
||
### `tickets` (UUID)
|
||
|
||
Support tickets.
|
||
|
||
```sql
|
||
CREATE TABLE tickets (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
user_id INT NOT NULL,
|
||
subject VARCHAR(255) NOT NULL,
|
||
status VARCHAR(20) DEFAULT 'open', -- 'open'|'in_progress'|'resolved'|'closed'
|
||
priority VARCHAR(10) DEFAULT 'medium', -- 'low'|'medium'|'high'|'urgent'
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
### `ticket_messages` (UUID)
|
||
|
||
Messages within tickets.
|
||
|
||
```sql
|
||
CREATE TABLE ticket_messages (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
ticket_id UUID NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
|
||
user_id INT NOT NULL,
|
||
message TEXT NOT NULL,
|
||
is_staff BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 Audit Tables
|
||
|
||
### `login_audits`
|
||
|
||
Login attempt tracking.
|
||
|
||
```sql
|
||
CREATE TABLE login_audits (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INT,
|
||
identifier VARCHAR(100),
|
||
success BOOLEAN,
|
||
ip_address VARCHAR(45),
|
||
user_agent TEXT,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
### `activity_logs`
|
||
|
||
General activity logging.
|
||
|
||
```sql
|
||
CREATE TABLE activity_logs (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INT,
|
||
entity_type VARCHAR(50),
|
||
entity_id INT,
|
||
action VARCHAR(50),
|
||
details JSONB,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 Junction Tables
|
||
|
||
### `user_companies`
|
||
|
||
Maps users to companies (N:M relationship).
|
||
|
||
```sql
|
||
CREATE TABLE user_companies (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
company_id INT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||
role VARCHAR(30) DEFAULT 'recruiter', -- 'admin'|'recruiter'
|
||
permissions JSONB,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
UNIQUE(user_id, company_id)
|
||
);
|
||
```
|
||
|
||
### `favorite_jobs`
|
||
|
||
Saved jobs by users.
|
||
|
||
```sql
|
||
CREATE TABLE favorite_jobs (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
job_id INT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
UNIQUE(user_id, job_id)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Migrations History
|
||
|
||
| # | File | Description |
|
||
|---|------|-------------|
|
||
| 001 | `001_create_users_table.sql` | Core users table |
|
||
| 002 | `002_create_companies_table.sql` | Companies/employers |
|
||
| 003 | `003_create_user_companies_table.sql` | User ↔ Company mapping |
|
||
| 004 | `004_create_prefectures_cities_tables.sql` | Geographic data |
|
||
| 005 | `005_create_jobs_table.sql` | Job postings |
|
||
| 006 | `006_create_applications_table.sql` | Job applications |
|
||
| 007 | `007_create_favorite_jobs_table.sql` | Saved jobs |
|
||
| 008 | `008_create_password_resets_table.sql` | Password reset tokens |
|
||
| 010 | `010_seed_super_admin.sql` | Default superadmin |
|
||
| 011 | `011_add_is_featured_to_jobs.sql` | Featured jobs flag |
|
||
| 012 | `012_add_work_mode.sql` | Work mode column |
|
||
| 013 | `013_create_backoffice_tables.sql` | Audit tables |
|
||
| 014 | `014_update_job_status_constraint.sql` | Status enum update |
|
||
| 015 | `015_add_candidate_profile_fields.sql` | Candidate profile |
|
||
| 016 | `016_create_notifications_table.sql` | Notifications |
|
||
| 017 | `017_create_tickets_table.sql` | Support tickets |
|
||
| 018 | `018_add_currency_to_jobs.sql` | Currency support |
|
||
| 019 | `019_create_job_payments_table.sql` | Payment tracking |
|
||
| 020 | `020_unify_schema.sql` | Schema unification |
|
||
| 999 | `999_fix_gohorse_schema.sql` | Schema fixes |
|
||
|
||
---
|
||
|
||
## ⚠️ ID Strategy Notes
|
||
|
||
The database uses a **hybrid ID strategy**:
|
||
|
||
| Strategy | Tables | Rationale |
|
||
|----------|--------|-----------|
|
||
| **UUID v7** | users, companies, jobs, applications, notifications, tickets, job_payments | Time-ordered, distributed-friendly, sortable, scalable |
|
||
| **SERIAL (INT)** | regions, cities, job_posting_prices, job_tags | Reference/Static data, low volume |
|
||
|
||
### UUID v7 (RFC 9562)
|
||
|
||
Starting from migration `021_create_uuid_v7_function.sql`, the database uses **UUID v7** instead of UUID v4:
|
||
|
||
```sql
|
||
-- UUID v7 is generated by uuid_generate_v7() function
|
||
SELECT uuid_generate_v7();
|
||
-- Returns: 019438a1-2b3c-7abc-8123-4567890abcdef
|
||
-- ^^^^^^^^ time component (sortable)
|
||
```
|
||
|
||
**Benefits of UUID v7:**
|
||
- ⏱️ Time-ordered (sortable by creation time)
|
||
- 🌐 Distributed-friendly (no coordination needed)
|
||
- 📊 Better index performance than UUID v4
|
||
- 🔒 Contains embedded timestamp
|
||
|
||
---
|
||
|
||
## 🔒 Security Notes
|
||
|
||
1. **Password Hashing:** BCrypt with optional `PASSWORD_PEPPER` environment variable
|
||
2. **Soft Deletes:** Not implemented (uses `CASCADE` for referential integrity)
|
||
3. **Row-Level Security:** Not implemented (uses application-level checks)
|
||
4. **Audit Trail:** `login_audits` and `activity_logs` for compliance
|
||
|
||
---
|
||
|
||
## 📚 Related Documentation
|
||
|
||
- [Backend README](../backend/README.md) - API documentation
|
||
- [Seeder README](../seeder-api/README.md) - Database seeding
|
||
- [Backoffice README](../backoffice/README.md) - Admin panel
|