diff --git a/backend/README.md b/backend/README.md
index b0b729b..f37b14e 100755
--- a/backend/README.md
+++ b/backend/README.md
@@ -75,10 +75,10 @@ O endpoint `/jobs` suporta filtros avançados via query params:
| Método | Endpoint | Roles | Descrição |
|--------|----------|-------|-----------|
-| `GET` | `/api/v1/users` | `superadmin`, `companyAdmin` | Listar usuários |
-| `POST` | `/api/v1/users` | `superadmin`, `companyAdmin` | Criar usuário |
+| `GET` | `/api/v1/users` | `superadmin`, `admin` | Listar usuários |
+| `POST` | `/api/v1/users` | `superadmin`, `admin` | Criar usuário |
| `DELETE` | `/api/v1/users/{id}` | `superadmin` | Deletar usuário |
-| `POST` | `/jobs` | `companyAdmin`, `recruiter` | Criar vaga |
+| `POST` | `/jobs` | `admin`, `recruiter` | Criar vaga |
---
diff --git a/backend/internal/core/domain/entity/user.go b/backend/internal/core/domain/entity/user.go
index 8940bac..2d4e871 100644
--- a/backend/internal/core/domain/entity/user.go
+++ b/backend/internal/core/domain/entity/user.go
@@ -2,6 +2,20 @@ package entity
import "time"
+// Role type alias
+type RoleString string
+
+const (
+ // RoleSuperAdmin is the platform administrator
+ RoleSuperAdmin = "superadmin"
+ // RoleAdmin is the company administrator (formerly admin)
+ RoleAdmin = "admin"
+ // RoleRecruiter is a recruiter within a company
+ RoleRecruiter = "recruiter"
+ // RoleCandidate is a job seeker (formerly candidate)
+ RoleCandidate = "candidate"
+)
+
// User represents a user within a specific Tenant (Company).
type User struct {
ID string `json:"id"`
diff --git a/backend/internal/dto/auth.go b/backend/internal/dto/auth.go
index 9823156..33cfad2 100755
--- a/backend/internal/dto/auth.go
+++ b/backend/internal/dto/auth.go
@@ -31,7 +31,7 @@ type UserInfo struct {
type CompanyInfo struct {
ID int `json:"id"`
Name string `json:"name"`
- Role string `json:"role"` // Role in this company (companyAdmin or recruiter)
+ Role string `json:"role"` // Role in this company (admin or recruiter)
}
// RegisterRequest represents user registration
@@ -44,7 +44,7 @@ type RegisterRequest struct {
LineID *string `json:"lineId,omitempty"`
Instagram *string `json:"instagram,omitempty"`
Language string `json:"language" validate:"required,oneof=pt en es ja"`
- Role string `json:"role" validate:"required,oneof=jobSeeker recruiter companyAdmin"`
+ Role string `json:"role" validate:"required,oneof=candidate recruiter admin"`
}
// User represents a generic user profile
diff --git a/backend/internal/dto/requests.go b/backend/internal/dto/requests.go
index 5bba8f0..53e75b0 100755
--- a/backend/internal/dto/requests.go
+++ b/backend/internal/dto/requests.go
@@ -99,7 +99,7 @@ type UpdateCompanyRequest struct {
type AssignUserToCompanyRequest struct {
UserID string `json:"userId" validate:"required"`
CompanyID string `json:"companyId" validate:"required"`
- Role string `json:"role" validate:"required,oneof=companyAdmin recruiter"`
+ Role string `json:"role" validate:"required,oneof=admin recruiter"`
Permissions map[string]interface{} `json:"permissions,omitempty"`
}
diff --git a/backend/internal/infrastructure/persistence/postgres/user_repository.go b/backend/internal/infrastructure/persistence/postgres/user_repository.go
index 7876f31..f0ad53c 100644
--- a/backend/internal/infrastructure/persistence/postgres/user_repository.go
+++ b/backend/internal/infrastructure/persistence/postgres/user_repository.go
@@ -37,8 +37,8 @@ func (r *UserRepository) Save(ctx context.Context, user *entity.User) (*entity.U
`
var id string
- // Map the first role to the role column, default to 'jobSeeker'
- role := "jobSeeker"
+ // Map the first role to the role column, default to 'candidate'
+ role := "candidate"
if len(user.Roles) > 0 {
role = user.Roles[0].Name
}
diff --git a/backend/internal/middleware/README.md b/backend/internal/middleware/README.md
index f00abfd..28ad909 100644
--- a/backend/internal/middleware/README.md
+++ b/backend/internal/middleware/README.md
@@ -20,7 +20,7 @@ mux.Handle("/admin", AuthMiddleware(RequireRole("superadmin")(handler)))
**Claims extraídas:**
- `UserID` - ID do usuário
-- `Role` - Papel (superadmin, companyAdmin, recruiter, jobSeeker)
+- `Role` - Papel (superadmin, admin, recruiter, candidate)
- `CompanyID` - ID da empresa (se aplicável)
---
diff --git a/backend/internal/models/user.go b/backend/internal/models/user.go
index 01fdbc0..e30e669 100755
--- a/backend/internal/models/user.go
+++ b/backend/internal/models/user.go
@@ -7,7 +7,7 @@ type User struct {
ID string `json:"id" db:"id"`
Identifier string `json:"identifier" db:"identifier"`
PasswordHash string `json:"-" db:"password_hash"` // Never expose password hash in JSON
- Role string `json:"role" db:"role"` // superadmin, companyAdmin, recruiter, jobSeeker
+ Role string `json:"role" db:"role"` // superadmin, admin, recruiter, candidate
// Personal Info
FullName string `json:"fullName" db:"full_name"`
diff --git a/backend/internal/models/user_company.go b/backend/internal/models/user_company.go
index 4ab1e87..2c71aec 100755
--- a/backend/internal/models/user_company.go
+++ b/backend/internal/models/user_company.go
@@ -11,7 +11,7 @@ type UserCompany struct {
ID string `json:"id" db:"id"`
UserID string `json:"userId" db:"user_id"`
CompanyID string `json:"companyId" db:"company_id"`
- Role string `json:"role" db:"role"` // companyAdmin, recruiter
+ Role string `json:"role" db:"role"` // admin, recruiter
Permissions JSONMap `json:"permissions,omitempty" db:"permissions"`
CreatedAt time.Time `json:"createdAt" db:"created_at"`
}
diff --git a/backend/internal/services/admin_service.go b/backend/internal/services/admin_service.go
index 645ed2e..bd31833 100644
--- a/backend/internal/services/admin_service.go
+++ b/backend/internal/services/admin_service.go
@@ -276,7 +276,7 @@ func (s *AdminService) ListCandidates(ctx context.Context) ([]dto.Candidate, dto
query := `
SELECT id, full_name, email, phone, city, state, title, experience, bio, skills, avatar_url, created_at
FROM users
- WHERE role = 'jobSeeker'
+ WHERE role = 'candidate'
ORDER BY created_at DESC
`
diff --git a/backend/migrations/001_create_users_table.sql b/backend/migrations/001_create_users_table.sql
index 9f26a72..81f71ae 100755
--- a/backend/migrations/001_create_users_table.sql
+++ b/backend/migrations/001_create_users_table.sql
@@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
identifier VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
- role VARCHAR(20) NOT NULL CHECK (role IN ('superadmin', 'companyAdmin', 'recruiter', 'jobSeeker')),
+ role VARCHAR(20) NOT NULL CHECK (role IN ('superadmin', 'admin', 'recruiter', 'candidate')),
-- Personal Info
full_name VARCHAR(255),
@@ -32,4 +32,4 @@ CREATE INDEX idx_users_active ON users(active);
-- Comments for documentation
COMMENT ON TABLE users IS 'Stores all system users across all roles';
COMMENT ON COLUMN users.identifier IS 'Username for login (NOT email)';
-COMMENT ON COLUMN users.role IS 'User role: superadmin, companyAdmin, recruiter, or jobSeeker';
+COMMENT ON COLUMN users.role IS 'User role: superadmin, admin, recruiter, or candidate';
diff --git a/backend/migrations/003_create_user_companies_table.sql b/backend/migrations/003_create_user_companies_table.sql
index ddb90d8..d992fd2 100755
--- a/backend/migrations/003_create_user_companies_table.sql
+++ b/backend/migrations/003_create_user_companies_table.sql
@@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS user_companies (
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
user_id UUID NOT NULL,
company_id UUID NOT NULL,
- role VARCHAR(20) NOT NULL CHECK (role IN ('companyAdmin', 'recruiter')),
+ role VARCHAR(20) NOT NULL CHECK (role IN ('admin', 'recruiter')),
permissions JSONB, -- Optional granular permissions
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -25,5 +25,5 @@ CREATE INDEX idx_user_companies_role ON user_companies(role);
-- Comments
COMMENT ON TABLE user_companies IS 'Multi-tenant pivot: links users to companies with specific roles';
-COMMENT ON COLUMN user_companies.role IS 'Role within this company: companyAdmin or recruiter';
+COMMENT ON COLUMN user_companies.role IS 'Role within this company: admin or recruiter';
COMMENT ON COLUMN user_companies.permissions IS 'Optional JSON object for granular permissions per company';
diff --git a/backend/migrations/008_create_password_resets_table.sql b/backend/migrations/008_create_password_resets_table.sql
index 5561c24..d822c8a 100755
--- a/backend/migrations/008_create_password_resets_table.sql
+++ b/backend/migrations/008_create_password_resets_table.sql
@@ -3,7 +3,7 @@
CREATE TABLE IF NOT EXISTS password_resets (
id SERIAL PRIMARY KEY,
- user_id INT NOT NULL,
+ user_id UUID NOT NULL,
token VARCHAR(255) UNIQUE NOT NULL,
expires_at TIMESTAMP NOT NULL,
used BOOLEAN DEFAULT false,
diff --git a/backend/migrations/017_create_tickets_table.sql b/backend/migrations/017_create_tickets_table.sql
index 2f8de9c..cf1ae9a 100644
--- a/backend/migrations/017_create_tickets_table.sql
+++ b/backend/migrations/017_create_tickets_table.sql
@@ -1,6 +1,3 @@
-DROP TABLE IF EXISTS ticket_messages;
-DROP TABLE IF EXISTS tickets;
-
CREATE TABLE tickets (
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
diff --git a/docs/API.md b/docs/API.md
index 23d2e39..ed72a12 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -18,9 +18,9 @@ Complete API reference with routes, permissions, and modules.
| Role | Code | Level | Description |
|------|------|-------|-------------|
| **SuperAdmin** | `superadmin` | 0 | Platform administrator |
-| **CompanyAdmin** | `companyAdmin` | 1 | Company administrator |
+| **Admin** | `admin` | 1 | Company administrator |
| **Recruiter** | `recruiter` | 2 | Job poster |
-| **JobSeeker** | `jobSeeker` | 3 | Candidate |
+| **Candidate** | `candidate` | 3 | Candidate |
| **Guest** | - | - | No authentication |
---
@@ -124,7 +124,7 @@ POST /api/v1/users
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Protected | ✅ | superadmin, companyAdmin | Create new user |
+| Protected | ✅ | superadmin, admin | Create new user |
### Update User
```http
@@ -186,7 +186,7 @@ POST /api/v1/jobs
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public* | ❌ | companyAdmin, recruiter | Create new job posting |
+| Public* | ❌ | admin, recruiter | Create new job posting |
### Update Job
```http
@@ -194,7 +194,7 @@ PUT /api/v1/jobs/{id}
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public* | ❌ | companyAdmin, recruiter | Update job posting |
+| Public* | ❌ | admin, recruiter | Update job posting |
### Delete Job
```http
@@ -202,7 +202,7 @@ DELETE /api/v1/jobs/{id}
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public* | ❌ | companyAdmin, recruiter | Delete job posting |
+| Public* | ❌ | admin, recruiter | Delete job posting |
### List Jobs for Moderation
```http
@@ -258,7 +258,7 @@ GET /api/v1/applications
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public | ❌ | companyAdmin, recruiter | List applications |
+| Public | ❌ | admin, recruiter | List applications |
### Get Application by ID
```http
@@ -266,7 +266,7 @@ GET /api/v1/applications/{id}
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public | ❌ | companyAdmin, recruiter | Get application details |
+| Public | ❌ | admin, recruiter | Get application details |
### Update Application Status
```http
@@ -274,7 +274,7 @@ PUT /api/v1/applications/{id}/status
```
| Field | Auth | Roles | Description |
|-------|------|-------|-------------|
-| Public | ❌ | companyAdmin, recruiter | Update application status |
+| Public | ❌ | admin, recruiter | Update application status |
**Request:**
```json
diff --git a/docs/API_SECURITY.md b/docs/API_SECURITY.md
index 847c7e0..ddcc067 100644
--- a/docs/API_SECURITY.md
+++ b/docs/API_SECURITY.md
@@ -27,8 +27,8 @@ This document details the security layers, authentication methods, and role-base
| Method | Route | Description | Notes |
| :--- | :--- | :--- | :--- |
| `POST` | `/api/v1/auth/login` | User Login | Returns JWT + Cookie |
-| `POST` | `/api/v1/auth/register` | Candidate Register | Creates `jobSeeker` user |
-| `POST` | `/api/v1/companies` | Company Register | Creates company + `companyAdmin` |
+| `POST` | `/api/v1/auth/register` | Candidate Register | Creates `candidate` user |
+| `POST` | `/api/v1/companies` | Company Register | Creates company + `admin` |
| `GET` | `/api/v1/jobs` | List Jobs | Public search/list |
| `GET` | `/api/v1/jobs/{id}` | Get Job | Public details |
| `GET` | `/docs/*` | Swagger UI | API Documentation |
@@ -47,7 +47,7 @@ This document details the security layers, authentication methods, and role-base
| `DELETE` | `/api/v1/storage/files` | Delete S3 File |
### 🟠 Recruiter / CompanyAdmin Routes
-**Requirement**: Role `companyAdmin` OR `recruiter`.
+**Requirement**: Role `admin` OR `recruiter`.
| Method | Route | Description |
| :--- | :--- | :--- |
diff --git a/docs/DATABASE.md b/docs/DATABASE.md
index fff252b..10c3fc5 100644
--- a/docs/DATABASE.md
+++ b/docs/DATABASE.md
@@ -156,7 +156,7 @@ 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'|'companyAdmin'|'recruiter'|'jobSeeker'
+ role VARCHAR(20) NOT NULL, -- 'superadmin'|'admin'|'recruiter'|'candidate'
-- Profile
full_name VARCHAR(255),
@@ -190,9 +190,9 @@ CREATE TABLE users (
**Roles:**
- `superadmin` - Platform administrator
-- `companyAdmin` - Company administrator
+- `admin` - Company administrator
- `recruiter` - Job poster/recruiter
-- `jobSeeker` - Candidate/job seeker
+- `candidate` - Candidate/job seeker
---
@@ -544,7 +544,7 @@ 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', -- 'companyAdmin'|'recruiter'
+ role VARCHAR(30) DEFAULT 'recruiter', -- 'admin'|'recruiter'
permissions JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, company_id)
diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx
index 72392ad..661d258 100644
--- a/frontend/src/app/dashboard/page.tsx
+++ b/frontend/src/app/dashboard/page.tsx
@@ -33,11 +33,11 @@ export default function DashboardPage() {
return
}
- if (user.role === "company" || user.roles?.includes("companyAdmin")) {
+ if (user.role === "company" || user.roles?.includes("admin")) {
return
}
- if (user.role === "candidate" || user.roles?.includes("jobSeeker")) {
+ if (user.role === "candidate" || user.roles?.includes("candidate")) {
return
}
diff --git a/frontend/src/app/dashboard/users/page.tsx b/frontend/src/app/dashboard/users/page.tsx
index 97dab94..d8d2505 100644
--- a/frontend/src/app/dashboard/users/page.tsx
+++ b/frontend/src/app/dashboard/users/page.tsx
@@ -45,7 +45,7 @@ export default function AdminUsersPage() {
name: "",
email: "",
password: "",
- role: "jobSeeker",
+ role: "candidate",
})
const [editFormData, setEditFormData] = useState({
name: "",
@@ -85,7 +85,7 @@ export default function AdminUsersPage() {
await usersApi.create(formData)
toast.success("User created successfully!")
setIsDialogOpen(false)
- setFormData({ name: "", email: "", password: "", role: "jobSeeker" })
+ setFormData({ name: "", email: "", password: "", role: "candidate" })
setPage(1)
loadUsers(1)
} catch (error) {
@@ -158,18 +158,16 @@ export default function AdminUsersPage() {
const getRoleBadge = (role: string) => {
const labels: Record = {
superadmin: "Super Admin",
- companyAdmin: "Company admin",
+ admin: "Company Admin",
recruiter: "Recruiter",
- jobSeeker: "Candidate",
- admin: "Admin",
+ candidate: "Candidate",
company: "Company"
}
const colors: Record = {
superadmin: "destructive",
- companyAdmin: "default",
+ admin: "default",
recruiter: "secondary",
- jobSeeker: "outline",
- admin: "destructive",
+ candidate: "outline",
company: "default"
}
const label = labels[role] || role || "User"
@@ -239,9 +237,9 @@ export default function AdminUsersPage() {
Super Admin
- Company admin
+ Company admin
Recruiter
- Candidate
+ Candidate
@@ -307,7 +305,7 @@ export default function AdminUsersPage() {
Admins (page)
- {users.filter((u) => u.role === "superadmin" || u.role === "companyAdmin").length}
+ {users.filter((u) => u.role === "superadmin" || u.role === "admin" || u.role === "admin").length}
@@ -320,7 +318,7 @@ export default function AdminUsersPage() {
Candidates (page)
- {users.filter((u) => u.role === "jobSeeker").length}
+ {users.filter((u) => u.role === "candidate" || u.role === "candidate").length}
diff --git a/frontend/src/lib/auth.ts b/frontend/src/lib/auth.ts
index 8645e31..5037ff1 100644
--- a/frontend/src/lib/auth.ts
+++ b/frontend/src/lib/auth.ts
@@ -44,9 +44,11 @@ export async function login(
// Note: The backend returns roles as an array of strings. The frontend expects a single 'role' or we need to adapt.
// For now we map the first role or main role to the 'role' field.
let userRole: "candidate" | "admin" | "company" = "candidate";
- if (data.user.roles.includes("superadmin") || data.user.roles.includes("admin") || data.user.roles.includes("ADMIN") || data.user.roles.includes("SUPERADMIN")) {
+ // Check for SuperAdmin (Platform Admin)
+ if (data.user.roles.includes("superadmin") || data.user.roles.includes("SUPERADMIN")) {
userRole = "admin";
- } else if (data.user.roles.includes("companyAdmin") || data.user.roles.includes("recruiter")) {
+ // Check for Company Admin (now called 'admin') or Recruiter
+ } else if (data.user.roles.includes("admin") || data.user.roles.includes("recruiter")) {
userRole = "company";
}
diff --git a/seeder-api/src/index.js b/seeder-api/src/index.js
index d55e037..2bd6208 100644
--- a/seeder-api/src/index.js
+++ b/seeder-api/src/index.js
@@ -14,19 +14,26 @@ async function resetDatabase() {
console.log('🗑️ Resetting database...');
try {
- // Drop all tables in reverse order (respecting foreign keys)
- await pool.query('DROP TABLE IF EXISTS password_resets CASCADE');
- await pool.query('DROP TABLE IF EXISTS favorite_jobs CASCADE');
- await pool.query('DROP TABLE IF EXISTS applications CASCADE');
- await pool.query('DROP TABLE IF EXISTS jobs CASCADE');
- await pool.query('DROP TABLE IF EXISTS user_companies CASCADE');
- await pool.query('DROP TABLE IF EXISTS companies CASCADE');
- await pool.query('DROP TABLE IF EXISTS users CASCADE');
- await pool.query('DROP TABLE IF EXISTS cities CASCADE');
- await pool.query('DROP TABLE IF EXISTS regions CASCADE');
- await pool.query('DROP TABLE IF EXISTS prefectures CASCADE'); // Legacy drop
+ // Dynamic drop: Fetch all tables in public schema and drop them
+ // This avoids "must be owner of schema public" error by operating on tables directly
+ console.log('🔍 Finding tables to drop...');
+ const tablesResult = await pool.query(`
+ SELECT tablename
+ FROM pg_tables
+ WHERE schemaname = 'public'
+ `);
- console.log('✅ All tables dropped successfully');
+ if (tablesResult.rows.length > 0) {
+ const tables = tablesResult.rows.map(row => row.tablename);
+ console.log(`🔥 Dropping ${tables.length} tables: ${tables.join(', ')}`);
+
+ // Construct a single DROP statement for all tables (CASCADE handles dependencies)
+ const tableList = tables.map(t => `"${t}"`).join(', ');
+ await pool.query(`DROP TABLE IF EXISTS ${tableList} CASCADE`);
+ console.log('✅ All public tables dropped successfully.');
+ } else {
+ console.log('ℹ️ No tables found to drop IN public schema.');
+ }
} catch (error) {
console.error('❌ Error resetting database:', error.message);
throw error;
diff --git a/seeder-api/src/seeders/jobs.js b/seeder-api/src/seeders/jobs.js
index 3b226b8..98f64a3 100644
--- a/seeder-api/src/seeders/jobs.js
+++ b/seeder-api/src/seeders/jobs.js
@@ -80,7 +80,12 @@ export async function seedJobs() {
let totalJobs = 0;
try {
+ // Process companies in chunks to avoid overwhelming the DB
for (const company of companies) {
+ const jobValues = [];
+ const jobParams = [];
+ let paramCounter = 1;
+
// Generate 25 jobs per company
for (let i = 0; i < 25; i++) {
const template = jobTemplates[i % jobTemplates.length];
@@ -98,13 +103,8 @@ export async function seedJobs() {
const currency = currencies[i % currencies.length];
const salaryType = salaryTypes[i % salaryTypes.length];
- // jobs.id is SERIAL - let DB auto-generate
- await pool.query(`
- 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)
- `, [
+ // Prepare params for bulk insert
+ jobParams.push(
company.id,
seedUserId,
title,
@@ -122,11 +122,28 @@ export async function seedJobs() {
'beginner',
'open',
workMode
- ]);
+ );
+ // ($1, $2, $3, ...), ($18, $19, ...)
+ const placeHolders = [];
+ for (let k = 0; k < 17; k++) {
+ placeHolders.push(`$${paramCounter++}`);
+ }
+ jobValues.push(`(${placeHolders.join(',')})`);
totalJobs++;
}
+
+ // Bulk Insert for this company
+ if (jobValues.length > 0) {
+ const query = `
+ 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 ${jobValues.join(',')}
+ `;
+ await pool.query(query, jobParams);
+ }
}
console.log(` ✓ ${totalJobs} jobs seeded across ${companies.length} companies`);
diff --git a/seeder-api/src/seeders/notifications.js b/seeder-api/src/seeders/notifications.js
index 11de134..301e955 100644
--- a/seeder-api/src/seeders/notifications.js
+++ b/seeder-api/src/seeders/notifications.js
@@ -108,7 +108,7 @@ export async function seedNotifications() {
createdAt.setHours(createdAt.getHours() - hoursAgo);
await pool.query(`
- INSERT INTO notifications (id, user_id, title, message, type, is_read, created_at, updated_at)
+ INSERT INTO notifications (id, user_id, title, message, type, read_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (id) DO NOTHING
`, [
@@ -117,7 +117,7 @@ export async function seedNotifications() {
template.title,
template.message,
template.type,
- template.is_read,
+ template.is_read ? new Date() : null,
createdAt,
createdAt
]);
diff --git a/seeder-api/src/seeders/users.js b/seeder-api/src/seeders/users.js
index 21f8268..3eb7f69 100644
--- a/seeder-api/src/seeders/users.js
+++ b/seeder-api/src/seeders/users.js
@@ -40,13 +40,13 @@ export async function seedUsers() {
console.log(' ✓ SuperAdmin created (superadmin)');
// 2. Create Company Admins
- const companyAdmins = [
- { identifier: 'takeshi_yamamoto', fullName: 'Takeshi Yamamoto', company: 'TechCorp', email: 'takeshi@techcorp.com', pass: 'Takeshi@2025', roles: ['companyAdmin'] },
- { identifier: 'kenji', fullName: 'Kenji Tanaka', company: 'AppMakers', email: 'kenji@appmakers.mobile', pass: 'Takeshi@2025', roles: ['companyAdmin'] },
+ const admins = [
+ { identifier: 'takeshi_yamamoto', fullName: 'Takeshi Yamamoto', company: 'TechCorp', email: 'takeshi@techcorp.com', pass: 'Takeshi@2025', roles: ['admin'] },
+ { identifier: 'kenji', fullName: 'Kenji Tanaka', company: 'AppMakers', email: 'kenji@appmakers.mobile', pass: 'Takeshi@2025', roles: ['admin'] },
{ identifier: 'maria_santos', fullName: 'Maria Santos', company: 'DesignHub', email: 'maria@designhub.com', pass: 'User@2025', roles: ['recruiter'] }
];
- for (const admin of companyAdmins) {
+ for (const admin of admins) {
const hash = await bcrypt.hash(admin.pass + PASSWORD_PEPPER, 10);
const tenantId = companyMap[admin.company];
@@ -86,7 +86,7 @@ export async function seedUsers() {
const result = await pool.query(`
INSERT INTO users (identifier, password_hash, role, full_name, email, name, status)
- VALUES ($1, $2, 'jobSeeker', $3, $4, $5, 'active')
+ VALUES ($1, $2, 'candidate', $3, $4, $5, 'active')
ON CONFLICT (identifier) DO UPDATE SET password_hash = EXCLUDED.password_hash
RETURNING id
`, [cand.identifier, hash, cand.fullName, cand.email, cand.fullName]);
@@ -178,7 +178,7 @@ export async function seedUsers() {
INSERT INTO users (
identifier, password_hash, role, full_name, email, name, phone,
city, state, title, experience, skills, objective, bio, status
- ) VALUES ($1, $2, 'jobSeeker', $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, 'active')
+ ) VALUES ($1, $2, 'candidate', $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, 'active')
ON CONFLICT (identifier) DO UPDATE SET
full_name = EXCLUDED.full_name,
email = EXCLUDED.email,