chore: heygermany customer project
Some checks failed
Main / Setup and Test (push) Has been cancelled
Main / Build Website (push) Has been cancelled

This commit is contained in:
e2e
2026-07-11 11:13:08 +02:00
commit 2c4174b44b
370 changed files with 35601 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
CREATE SCHEMA IF NOT EXISTS institutions;
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
CREATE OR REPLACE FUNCTION institutions.update_lastupdated_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE institutions.country (
country_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
iso_code VARCHAR NOT NULL,
name_english VARCHAR NOT NULL,
name_official VARCHAR,
name_short VARCHAR,
publicated BOOLEAN NOT NULL,
hidden BOOLEAN,
country_group VARCHAR NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.location (
location_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
country_id UUID NOT NULL REFERENCES institutions.country(country_id),
origin_name VARCHAR NOT NULL,
name_short VARCHAR,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.institution_type (
institution_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name_short VARCHAR,
status VARCHAR CHECK (status IN ('H +', 'H -', 'H +/-')),
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.institution (
institution_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
country_id UUID NOT NULL REFERENCES institutions.country(country_id),
location_id UUID REFERENCES institutions.location(location_id),
institution_type_id UUID NOT NULL REFERENCES institutions.institution_type(institution_type_id),
name_short VARCHAR,
abbreviation VARCHAR,
homepage VARCHAR,
name_german VARCHAR,
address_street VARCHAR,
address_zip VARCHAR,
address_city VARCHAR,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree_type (
degree_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
country_id UUID NOT NULL REFERENCES institutions.country(country_id),
name_short VARCHAR,
name_german VARCHAR,
name_female VARCHAR,
name_female_german VARCHAR,
comment TEXT,
hide_requirement BOOLEAN,
requirement TEXT,
additional_requirement TEXT,
hide_studies BOOLEAN,
studies_min_length FLOAT,
studies_max_length FLOAT,
explanation_studies_length TEXT,
studies_description TEXT,
abbreviation VARCHAR,
abbreviation_female VARCHAR,
degree_class VARCHAR CHECK (degree_class IN ('A1', 'A2', 'A3', 'A4', 'A5', 'PGS', 'NZ', 'D1', 'D2', 'HC')),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree_type_equivalence (
degree_type_equivalence_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
degree_type_id UUID NOT NULL REFERENCES institutions.degree_type(degree_type_id),
hidden BOOLEAN,
equivalence_class VARCHAR NOT NULL,
comment TEXT,
admin_comment TEXT,
internal_comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree_field_of_study (
degree_field_of_study_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
country_id UUID NOT NULL REFERENCES institutions.country(country_id),
name_short VARCHAR,
name_german VARCHAR,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree (
degree_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_original VARCHAR NOT NULL,
country_id UUID NOT NULL REFERENCES institutions.country(country_id),
degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id),
field_of_study_id UUID REFERENCES institutions.degree_field_of_study(degree_field_of_study_id),
degree_short VARCHAR,
name_short VARCHAR,
name_german VARCHAR,
name_female VARCHAR,
name_female_german VARCHAR,
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.alias_name (
alias_name_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
type VARCHAR NOT NULL CHECK (type IN ('alias', 'alternative', 'outdated')),
id_original VARCHAR NOT NULL,
name_short VARCHAR,
name_german VARCHAR,
comment TEXT,
hidden BOOLEAN,
deleted BOOLEAN,
language_id VARCHAR,
name_translated VARCHAR,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.entity_name_link (
entity_type VARCHAR NOT NULL CHECK (entity_type IN ('degree', 'institution', 'location', 'degree_type')),
entity_id UUID NOT NULL,
name_id UUID NOT NULL REFERENCES institutions.alias_name(alias_name_id),
name_type VARCHAR NOT NULL CHECK (name_type IN ('alias', 'alternative', 'outdated')),
PRIMARY KEY (entity_type, entity_id, name_id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.institution_degree (
institution_id UUID REFERENCES institutions.institution(institution_id),
degree_id UUID REFERENCES institutions.degree(degree_id),
PRIMARY KEY (institution_id, degree_id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree_equivalence (
degree_id UUID REFERENCES institutions.degree(degree_id),
equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id),
PRIMARY KEY (degree_id, equivalence_id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE institutions.degree_type_equivalence_link (
degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id),
equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id),
PRIMARY KEY (degree_type_id, equivalence_id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
DO $$
DECLARE
tbl TEXT;
BEGIN
FOR tbl IN
SELECT table_name FROM information_schema.columns
WHERE column_name = 'last_updated_at'
AND table_schema = 'app'
LOOP
EXECUTE format('
DROP TRIGGER IF EXISTS trg_update_last_updated_at ON institutions.%I;
CREATE TRIGGER trg_update_last_updated_at
BEFORE UPDATE ON institutions.%I
FOR EACH ROW
EXECUTE FUNCTION institutions.update_lastupdated_timestamp();',
tbl, tbl
);
END LOOP;
END $$;
-- Drop and recreate institution_search
CREATE OR REPLACE VIEW institutions.institution_search AS
SELECT
i.institution_id,
i.name_short AS main_name_short,
i.name_german AS main_name_german,
a.name_short AS alias_name_short,
a.name_german AS alias_name_german,
a.type AS alias_type,
it.status AS institution_status,
GREATEST(
similarity(i.name_short, ''),
similarity(i.name_german, ''),
similarity(a.name_short, ''),
similarity(a.name_german, '')
) AS match_score
FROM institutions.institution i
LEFT JOIN institutions.entity_name_link enl ON enl.entity_type = 'institution' AND enl.entity_id = i.institution_id
LEFT JOIN institutions.alias_name a ON enl.name_id = a.alias_name_id
LEFT JOIN institutions.institution_type it ON i.institution_type_id = it.institution_type_id;
-- Drop and recreate degree_search
CREATE OR REPLACE VIEW institutions.degree_search AS
SELECT
d.degree_id,
d.name_short AS main_name_short,
d.name_german AS main_name_german,
a.name_short AS alias_name_short,
a.name_german AS alias_name_german,
a.type AS alias_type,
GREATEST(
similarity(d.name_short, ''),
similarity(d.name_german, ''),
similarity(a.name_short, ''),
similarity(a.name_german, '')
) AS match_score
FROM institutions.degree d
LEFT JOIN institutions.entity_name_link enl
ON enl.entity_type = 'degree' AND enl.entity_id = d.degree_id
LEFT JOIN institutions.alias_name a
ON enl.name_id = a.alias_name_id;
CREATE INDEX idx_inst_name_short_trgm ON institutions.institution USING gin (name_short gin_trgm_ops);
CREATE INDEX idx_inst_name_german_trgm ON institutions.institution USING gin (name_german gin_trgm_ops);
CREATE INDEX idx_alias_name_short_trgm ON institutions.alias_name USING gin (name_short gin_trgm_ops);
CREATE INDEX idx_alias_name_german_trgm ON institutions.alias_name USING gin (name_german gin_trgm_ops);

26
db/postgres/0002-user.sql Normal file
View File

@@ -0,0 +1,26 @@
CREATE SCHEMA IF NOT EXISTS app;
CREATE OR REPLACE FUNCTION app.update_lastupdated_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE app.user (
user_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR NOT NULL,
name VARCHAR NOT NULL,
email_verified_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE app.user_auth (
user_id UUID PRIMARY KEY REFERENCES app.user(user_id),
access_token VARCHAR NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -0,0 +1,99 @@
-- Create enums for states (using German names), countries (using ISO codes for i18n), and language levels
CREATE TYPE app.german_state AS ENUM (
'Baden-Württemberg',
'Bayern',
'Berlin',
'Brandenburg',
'Bremen',
'Hamburg',
'Hessen',
'Mecklenburg-Vorpommern',
'Niedersachsen',
'Nordrhein-Westfalen',
'Rheinland-Pfalz',
'Saarland',
'Sachsen',
'Sachsen-Anhalt',
'Schleswig-Holstein',
'Thüringen'
);
CREATE TYPE app.education_country AS ENUM (
'AL', -- Albania
'BA', -- Bosnia and Herzegovina
'IN', -- India
'MX', -- Mexico
'PH', -- Philippines
'SY', -- Syria
'TN', -- Tunisia
'TR', -- Turkey
'UA', -- Ukraine
'VN' -- Vietnam
);
CREATE TYPE app.language_level AS ENUM (
'A_ONE',
'A_TWO',
'B_ONE',
'B_TWO',
'C_ONE',
'C_TWO'
);
CREATE TYPE app.candidate_document_type AS ENUM (
'education',
'transcript',
'license',
'language',
'work_experience'
);
CREATE TABLE app.candidate (
candidate_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR NOT NULL,
name VARCHAR NOT NULL,
-- Basic info
state_work_preference app.german_state[],
open_to_work BOOLEAN,
living_in_germany BOOLEAN,
eu_passport BOOLEAN,
country_education app.education_country,
-- License info
license_provided BOOLEAN,
-- Language info
language_certificate_provided BOOLEAN,
language_self_assessment_level app.language_level,
submitted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE app.candidate_document (
document_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate,
category app.candidate_document_type NOT NULL,
title VARCHAR,
note VARCHAR,
file_path VARCHAR NOT NULL,
file_name VARCHAR NOT NULL,
file_size INTEGER,
mime_type VARCHAR,
uploaded BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- Add triggers for timestamp updates
CREATE TRIGGER update_candidate_timestamp
BEFORE UPDATE ON app.candidate
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();
CREATE TRIGGER update_candidate_document_timestamp
BEFORE UPDATE ON app.candidate_document
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();

View File

@@ -0,0 +1,323 @@
-- Create enums for OCR models, AI models, and user roles
CREATE TYPE app.ocr_model AS ENUM (
'tesseract',
'azure_cognitive',
'aws_textract',
'google_vision',
'manual_entry'
);
CREATE TYPE app.ai_model AS ENUM (
'gpt-five',
'claude-three-opus',
'claude-three-sonnet',
'claude-three-haiku',
'gemini-pro'
);
CREATE TYPE app.user_role AS ENUM (
'admin',
'recruiter',
'candidate'
);
CREATE TYPE app.nurse_recognition AS ENUM (
'nurse',
'assistant_nurse',
'nursing_helper'
);
-- Update User Table
ALTER TABLE app.user
ADD COLUMN role app.user_role DEFAULT 'candidate';
-- Update Candidate Document Table
ALTER TABLE app.candidate_document
ADD COLUMN ocr_text TEXT,
ADD COLUMN ocr_model app.ocr_model,
ADD COLUMN ocr_started_at TIMESTAMPTZ,
ADD COLUMN ocr_ended_at TIMESTAMPTZ;
-- Update Candidate Table (user-provided data only)
ALTER TABLE app.candidate
ADD COLUMN phone VARCHAR,
ADD COLUMN date_of_birth DATE,
ADD COLUMN current_residence VARCHAR,
ADD COLUMN recognition_status app.nurse_recognition;
-- Create Education Table
CREATE TABLE app.candidate_education (
education_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate(candidate_id),
source_document_id UUID REFERENCES app.candidate_document(document_id),
-- Admin-confirmed data
institution VARCHAR,
country VARCHAR,
program VARCHAR,
duration_years INTEGER,
completion_date DATE,
is_accredited BOOLEAN,
-- AI-extracted data
ai_institution VARCHAR,
ai_country VARCHAR,
ai_program VARCHAR,
ai_duration_years INTEGER,
ai_completion_date DATE,
ai_is_accredited BOOLEAN,
-- Metadata
ai_extracted_by app.ai_model,
ai_extraction_date TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
-- Constraint: AI data requires source document
CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_institution IS NULL AND
ai_country IS NULL AND
ai_program IS NULL AND
ai_duration_years IS NULL AND
ai_completion_date IS NULL AND
ai_is_accredited IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
)
);
-- Create Transcript Table
CREATE TABLE app.candidate_transcript (
transcript_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate(candidate_id),
source_document_id UUID REFERENCES app.candidate_document(document_id),
education_id UUID REFERENCES app.candidate_education(education_id),
-- Admin-confirmed data
total_theory_hours INTEGER,
total_practical_hours INTEGER,
-- AI-extracted data
ai_total_theory_hours INTEGER,
ai_total_practical_hours INTEGER,
-- Metadata
ai_extracted_by app.ai_model,
ai_extraction_date TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
-- Constraint
CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_total_theory_hours IS NULL AND
ai_total_practical_hours IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
)
);
-- Create Transcript Course Table
CREATE TABLE app.candidate_transcript_course (
course_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
transcript_id UUID NOT NULL REFERENCES app.candidate_transcript(transcript_id),
-- Admin-confirmed data
course_name VARCHAR,
hours INTEGER,
grade VARCHAR,
-- AI-extracted data
ai_course_name VARCHAR,
ai_hours INTEGER,
ai_grade VARCHAR,
-- Metadata
ai_extracted_by app.ai_model
);
-- Create Clinical Placement Table
CREATE TABLE app.candidate_clinical_placement (
placement_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
transcript_id UUID NOT NULL REFERENCES app.candidate_transcript(transcript_id),
-- Admin-confirmed data
institution VARCHAR,
department VARCHAR,
duration_hours INTEGER,
duration_weeks INTEGER,
-- AI-extracted data
ai_institution VARCHAR,
ai_department VARCHAR,
ai_duration_hours INTEGER,
ai_duration_weeks INTEGER,
-- Metadata
ai_extracted_by app.ai_model
);
-- Create License Table
CREATE TABLE app.candidate_license (
license_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate(candidate_id),
source_document_id UUID REFERENCES app.candidate_document(document_id),
-- Admin-confirmed data
license_number VARCHAR,
issuing_authority VARCHAR,
issue_date DATE,
expiry_date DATE,
status VARCHAR,
license_type VARCHAR,
-- AI-extracted data
ai_license_number VARCHAR,
ai_issuing_authority VARCHAR,
ai_issue_date DATE,
ai_expiry_date DATE,
ai_status VARCHAR,
ai_license_type VARCHAR,
-- Metadata
ai_extracted_by app.ai_model,
ai_extraction_date TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
-- Constraint
CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_license_number IS NULL AND
ai_issuing_authority IS NULL AND
ai_issue_date IS NULL AND
ai_expiry_date IS NULL AND
ai_status IS NULL AND
ai_license_type IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
)
);
-- Create Language Certificate Table
CREATE TABLE app.candidate_language (
language_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate(candidate_id),
source_document_id UUID REFERENCES app.candidate_document(document_id),
-- Admin-confirmed data
language VARCHAR DEFAULT 'German',
level app.language_level,
issuing_body VARCHAR,
issue_date DATE,
certified_skills TEXT[],
-- AI-extracted data
ai_language VARCHAR DEFAULT 'German',
ai_level app.language_level,
ai_issuing_body VARCHAR,
ai_issue_date DATE,
ai_certified_skills TEXT[],
-- Metadata
ai_extracted_by app.ai_model,
ai_extraction_date TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
-- Constraint
CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_language IS NULL AND
ai_level IS NULL AND
ai_issuing_body IS NULL AND
ai_issue_date IS NULL AND
ai_certified_skills IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
)
);
-- Create Work Experience Table
CREATE TABLE app.candidate_experience (
experience_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID NOT NULL REFERENCES app.candidate(candidate_id),
source_document_id UUID REFERENCES app.candidate_document(document_id),
-- Admin-confirmed data
employer VARCHAR,
position VARCHAR,
department VARCHAR,
start_date DATE,
end_date DATE,
duration_months INTEGER,
is_full_time BOOLEAN,
duties TEXT[],
-- AI-extracted data
ai_employer VARCHAR,
ai_position VARCHAR,
ai_department VARCHAR,
ai_start_date DATE,
ai_end_date DATE,
ai_duration_months INTEGER,
ai_is_full_time BOOLEAN,
ai_duties TEXT[],
-- Metadata
ai_extracted_by app.ai_model,
ai_extraction_date TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
-- Constraint
CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_employer IS NULL AND
ai_position IS NULL AND
ai_department IS NULL AND
ai_start_date IS NULL AND
ai_end_date IS NULL AND
ai_duration_months IS NULL AND
ai_is_full_time IS NULL AND
ai_duties IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
)
);
-- Add Indexes
CREATE INDEX idx_education_candidate ON app.candidate_education(candidate_id);
CREATE INDEX idx_transcript_candidate ON app.candidate_transcript(candidate_id);
CREATE INDEX idx_license_candidate ON app.candidate_license(candidate_id);
CREATE INDEX idx_language_candidate ON app.candidate_language(candidate_id);
CREATE INDEX idx_experience_candidate ON app.candidate_experience(candidate_id);
CREATE INDEX idx_user_role ON app.user(role);
CREATE INDEX idx_document_ocr_status ON app.candidate_document(ocr_started_at, ocr_ended_at);
-- Add Update Triggers
CREATE TRIGGER update_candidate_education_timestamp
BEFORE UPDATE ON app.candidate_education
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();
CREATE TRIGGER update_candidate_transcript_timestamp
BEFORE UPDATE ON app.candidate_transcript
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();
CREATE TRIGGER update_candidate_license_timestamp
BEFORE UPDATE ON app.candidate_license
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();
CREATE TRIGGER update_candidate_language_timestamp
BEFORE UPDATE ON app.candidate_language
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();
CREATE TRIGGER update_candidate_experience_timestamp
BEFORE UPDATE ON app.candidate_experience
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();

View File

@@ -0,0 +1,22 @@
CREATE TYPE app.user_type AS ENUM (
'company',
'backoffice',
'candidate'
);
ALTER TABLE app.user
DROP COLUMN role;
BEGIN;
-- Create a new enum with the desired values
ALTER TYPE app.user_role RENAME TO user_role_old;
CREATE TYPE app.user_role AS ENUM (
'admin',
'owner'
);
DROP TYPE app.user_role_old;
COMMIT;
ALTER TABLE app.user
ADD COLUMN role app.user_role NOT NULL,
ADD COLUMN type app.user_type NOT NULL;

View File

@@ -0,0 +1,62 @@
-- Add manual verification fields for candidates
-- Add nursing-related boolean fields to candidate_education table
ALTER TABLE app.candidate_education
ADD COLUMN nursing_related_degree BOOLEAN,
ADD COLUMN accredited_university BOOLEAN,
ADD COLUMN accredited_study_program BOOLEAN;
-- Add corresponding AI-extracted fields to maintain the pattern
ALTER TABLE app.candidate_education
ADD COLUMN ai_nursing_related_degree BOOLEAN,
ADD COLUMN ai_accredited_university BOOLEAN,
ADD COLUMN ai_accredited_study_program BOOLEAN;
-- Update the existing constraint to include the new AI fields
ALTER TABLE app.candidate_education
DROP CONSTRAINT ai_data_requires_document;
ALTER TABLE app.candidate_education
ADD CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_institution IS NULL AND
ai_country IS NULL AND
ai_program IS NULL AND
ai_duration_years IS NULL AND
ai_completion_date IS NULL AND
ai_nursing_related_degree IS NULL AND
ai_accredited_university IS NULL AND
ai_accredited_study_program IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
);
-- Add document verification fields to candidate_document table
ALTER TABLE app.candidate_document
ADD COLUMN document_verified_at TIMESTAMPTZ,
ADD COLUMN document_verified_by UUID REFERENCES app.user(user_id);
-- Update candidate table qualification status fields
ALTER TABLE app.candidate
ADD COLUMN qualification_status_home_country app.nurse_recognition,
ADD COLUMN qualification_status_germany app.nurse_recognition,
DROP COLUMN recognition_status;
-- Add transcript summary fields to candidate table
ALTER TABLE app.candidate
ADD COLUMN transcripts_total_hours INTEGER,
ADD COLUMN transcripts_total_theory_hours INTEGER,
ADD COLUMN transcripts_total_practice_hours INTEGER,
ADD COLUMN transcripts_theory_and_practice BOOLEAN,
ADD COLUMN transcripts_structured_training BOOLEAN,
ADD COLUMN license_mandatory BOOLEAN;
-- Drop language fields from candidate_language table
ALTER TABLE app.candidate_language
DROP COLUMN language,
DROP COLUMN ai_language;
-- Drop duplicate accreditation field from candidate_education table
ALTER TABLE app.candidate_education
DROP COLUMN is_accredited,
DROP COLUMN ai_is_accredited;

View File

@@ -0,0 +1,33 @@
-- Add transcript summary fields to candidate table
ALTER TABLE app.candidate_transcript
ADD COLUMN ai_is_nursing_focus BOOLEAN,
ADD COLUMN ai_has_theory_hours BOOLEAN,
ADD COLUMN ai_has_practice_hours BOOLEAN,
ADD COLUMN is_nursing_focus BOOLEAN,
ADD COLUMN has_theory_hours BOOLEAN,
ADD COLUMN has_practice_hours BOOLEAN;
CREATE TYPE app.nurse_recognition_home_country AS ENUM (
'nurse',
'assistant_nurse',
'nursing_helper',
'none'
);
ALTER TYPE app.nurse_recognition RENAME TO nurse_recognition_germany;
-- Change qualification_status_home_country to use the new enum type
ALTER TABLE app.candidate
ALTER COLUMN qualification_status_home_country TYPE app.nurse_recognition_home_country
USING qualification_status_home_country::text::app.nurse_recognition_home_country;
DROP TABLE app.candidate_transcript_course;
-- Add transcript summary fields to candidate table
ALTER TABLE app.candidate
DROP COLUMN transcripts_total_hours,
DROP COLUMN transcripts_total_theory_hours,
DROP COLUMN transcripts_total_practice_hours,
DROP COLUMN transcripts_theory_and_practice,
DROP COLUMN transcripts_structured_training,
ADD COLUMN transcripts_has_duration BOOLEAN;

View File

@@ -0,0 +1,4 @@
-- Rename education_country enum type to country
ALTER TYPE app.education_country RENAME TO country;
-- The column reference will automatically use the new type name

View File

@@ -0,0 +1,6 @@
-- Remove redundant transcript fields that can be calculated from hours
ALTER TABLE app.candidate_transcript
DROP COLUMN IF EXISTS has_theory_hours,
DROP COLUMN IF EXISTS has_practice_hours,
DROP COLUMN IF EXISTS ai_has_theory_hours,
DROP COLUMN IF EXISTS ai_has_practice_hours;

View File

@@ -0,0 +1,5 @@
ALTER TABLE app.candidate
RENAME COLUMN transcripts_has_duration TO duration_requirements_met;
ALTER TABLE app.candidate
RENAME COLUMN open_to_work TO join_talent_pool;

View File

@@ -0,0 +1,27 @@
-- Create document status enum
CREATE TYPE app.document_status AS ENUM (
'Missing',
'Invalid',
'Verified',
'Unverified'
);
-- Add document_status column to candidate_document table
ALTER TABLE app.candidate_document
ADD COLUMN document_status app.document_status DEFAULT 'Unverified';
-- Migrate existing data based on document_verified_at
UPDATE app.candidate_document
SET document_status = CASE
WHEN document_verified_at IS NOT NULL THEN 'Verified'::app.document_status
ELSE 'Unverified'::app.document_status
END;
-- Make document_status NOT NULL after migration
ALTER TABLE app.candidate_document
ALTER COLUMN document_status SET NOT NULL;
-- Drop the old columns as they're no longer needed
ALTER TABLE app.candidate_document
DROP COLUMN document_verified_at,
DROP COLUMN document_verified_by;

View File

@@ -0,0 +1,11 @@
-- Create applicant_status enum
CREATE TYPE app.applicant_status AS ENUM (
'Initial',
'Invalid',
'Pending',
'Complete'
);
-- Add status field to candidate table
ALTER TABLE app.candidate
ADD COLUMN status app.applicant_status DEFAULT 'Initial' NOT NULL;

View File

@@ -0,0 +1,3 @@
ALTER TABLE app.user_auth
ADD COLUMN magic_link VARCHAR,
ADD COLUMN magic_link_expiry TIMESTAMP;

View File

@@ -0,0 +1,3 @@
ALTER TABLE app.candidate_education
DROP COLUMN IF EXISTS duration_years,
DROP COLUMN IF EXISTS ai_duration_years;

View File

@@ -0,0 +1,29 @@
-- Remove total hours fields from candidate_transcript
ALTER TABLE app.candidate_transcript
DROP COLUMN IF EXISTS total_theory_hours,
DROP COLUMN IF EXISTS total_practical_hours,
DROP COLUMN IF EXISTS ai_total_theory_hours,
DROP COLUMN IF EXISTS ai_total_practical_hours;
-- Add boolean fields to candidate_transcript
ALTER TABLE app.candidate_transcript
ADD COLUMN has_theory BOOLEAN,
ADD COLUMN has_practice BOOLEAN,
ADD COLUMN duration_hours INTEGER,
ADD COLUMN ai_has_theory BOOLEAN,
ADD COLUMN ai_has_practice BOOLEAN,
ADD COLUMN ai_duration_hours INTEGER;
-- Update the constraint to reflect new fields
ALTER TABLE app.candidate_transcript
DROP CONSTRAINT IF EXISTS ai_data_requires_document;
ALTER TABLE app.candidate_transcript
ADD CONSTRAINT ai_data_requires_document CHECK (
(source_document_id IS NOT NULL) OR
(ai_has_theory IS NULL AND
ai_has_practice IS NULL AND
ai_duration_hours IS NULL AND
ai_extracted_by IS NULL AND
ai_extraction_date IS NULL)
);

View File

@@ -0,0 +1,300 @@
DROP TABLE IF EXISTS app.countries;
CREATE TABLE app.countries (
"iso3" char(3) PRIMARY KEY,
"iso2" char(2) NOT NULL,
"name" varchar(100) NOT NULL,
"name_br" varchar(100),
"name_ko" varchar(100),
"name_pt_br" varchar(100),
"name_pt" varchar(100),
"name_nl" varchar(100),
"name_hr" varchar(100),
"name_fa" varchar(100),
"name_de" varchar(100),
"name_es" varchar(100),
"name_fr" varchar(100),
"name_ja" varchar(100),
"name_it" varchar(100),
"name_zh_cn" varchar(100),
"name_tr" varchar(100),
"name_ru" varchar(100),
"name_uk" varchar(100),
"name_pl" varchar(100),
"created_at" timestamp NULL DEFAULT now(),
"updated_at" timestamp NOT NULL DEFAULT now()
);
INSERT INTO app.countries (
iso3, iso2, name,
name_br, name_ko, name_pt_br, name_pt, name_nl, name_hr, name_fa, name_de,
name_es, name_fr, name_ja, name_it, name_zh_cn, name_tr, name_ru, name_uk, name_pl
)
VALUES
('AFG', 'AF', 'Afghanistan', 'Afghanistan', '아프가니스탄', 'Afeganistão', 'Afeganistão', 'Afghanistan', 'Afganistan', 'افغانستان', 'Afghanistan', 'Afganistán', 'Afghanistan', 'アフガニスタン', 'Afghanistan', '阿富汗', 'Afganistan', 'Афганистан', 'Афганістан', 'Afganistan'),
('ALA', 'AX', 'Aland Islands', 'Åland', '올란드 제도', 'Ilhas de Aland', 'Ilhas de Aland', 'Ålandeilanden', 'Ålandski otoci', 'جزایر الند', 'Åland', 'Alandia', 'Åland', 'オーランド諸島', 'Isole Aland', '奥兰群岛', 'Åland Adalari', 'Аландские острова', 'Аландські острови', 'Wyspy Alandzkie'),
('ALB', 'AL', 'Albania', 'Albania', '알바니아', 'Albânia', 'Albânia', 'Albanië', 'Albanija', 'آلبانی', 'Albanien', 'Albania', 'Albanie', 'アルバニア', 'Albania', '阿尔巴尼亚', 'Arnavutluk', 'Албания', 'Албанія', 'Albania'),
('DZA', 'DZ', 'Algeria', 'Aljeria', '알제리', 'Argélia', 'Argélia', 'Algerije', 'Alžir', 'الجزایر', 'Algerien', 'Argelia', 'Algérie', 'アルジェリア', 'Algeria', '阿尔及利亚', 'Cezayir', 'Алжир', 'Алжир', 'Algieria'),
('ASM', 'AS', 'American Samoa', 'Samoa Amerikan', '아메리칸사모아', 'Samoa Americana', 'Samoa Americana', 'Amerikaans Samoa', 'Američka Samoa', 'ساموآی آمریکا', 'Amerikanisch-Samoa', 'Samoa Americana', 'Samoa américaines', 'アメリカ領サモア', 'Samoa Americane', '美属萨摩亚', 'Amerikan Samoasi', 'Американское Самоа', 'Американське Самоа', 'Samoa Amerykańskie'),
('AND', 'AD', 'Andorra', 'Andorra', '안도라', 'Andorra', 'Andorra', 'Andorra', 'Andora', 'آندورا', 'Andorra', 'Andorra', 'Andorre', 'アンドラ', 'Andorra', '安道尔', 'Andorra', 'Андорра', 'Андорра', 'Andora'),
('AGO', 'AO', 'Angola', 'Angola', '앙골라', 'Angola', 'Angola', 'Angola', 'Angola', 'آنگولا', 'Angola', 'Angola', 'Angola', 'アンゴラ', 'Angola', '安哥拉', 'Angola', 'Ангола', 'Ангола', 'Angola'),
('AIA', 'AI', 'Anguilla', 'Anguilla', '앵귈라', 'Anguila', 'Anguila', 'Anguilla', 'Angvila', 'آنگویلا', 'Anguilla', 'Anguilla', 'Anguilla', 'アンギラ', 'Anguilla', '安圭拉', 'Anguilla', 'Ангилья', 'Ангілья', 'Anguilla'),
('ATA', 'AQ', 'Antarctica', 'Antarktika', '남극', 'Antártida', 'Antárctida', 'Antarctica', 'Antarktika', 'جنوبگان', 'Antarktika', 'Antártida', 'Antarctique', '南極大陸', 'Antartide', '南极洲', 'Antartika', 'Антарктида', 'Антарктида', 'Antarktyda'),
('ATG', 'AG', 'Antigua and Barbuda', 'Antigua-ha-Barbuda', '앤티가 바부다', 'Antígua e Barbuda', 'Antígua e Barbuda', 'Antigua en Barbuda', 'Antigva i Barbuda', 'آنتیگوا و باربودا', 'Antigua und Barbuda', 'Antigua y Barbuda', 'Antigua-et-Barbuda', 'アンティグア・バーブーダ', 'Antigua e Barbuda', '安提瓜和巴布达', 'Antigua Ve Barbuda', 'Антигуа и Барбуда', 'Антигуа і Барбуда', 'Antigua i Barbuda'),
('ARG', 'AR', 'Argentina', 'Arc''hantina', '아르헨티나', 'Argentina', 'Argentina', 'Argentinië', 'Argentina', 'آرژانتین', 'Argentinien', 'Argentina', 'Argentine', 'アルゼンチン', 'Argentina', '阿根廷', 'Arjantin', 'Аргентина', 'Аргентина', 'Argentyna'),
('ARM', 'AM', 'Armenia', 'Armenia', '아르메니아', 'Armênia', 'Arménia', 'Armenië', 'Armenija', 'ارمنستان', 'Armenien', 'Armenia', 'Arménie', 'アルメニア', 'Armenia', '亚美尼亚', 'Ermenistan', 'Армения', 'Вірменія', 'Armenia'),
('ABW', 'AW', 'Aruba', 'Aruba', '아루바', 'Aruba', 'Aruba', 'Aruba', 'Aruba', 'آروبا', 'Aruba', 'Aruba', 'Aruba', 'アルバ', 'Aruba', '阿鲁巴', 'Aruba', 'Аруба', 'Аруба', 'Aruba'),
('AUS', 'AU', 'Australia', 'Aostralia', '호주', 'Austrália', 'Austrália', 'Australië', 'Australija', 'استرالیا', 'Australien', 'Australia', 'Australie', 'オーストラリア', 'Australia', '澳大利亚', 'Avustralya', 'Австралия', 'Австралія', 'Australia'),
('AUT', 'AT', 'Austria', 'Aostria', '오스트리아', 'áustria', 'áustria', 'Oostenrijk', 'Austrija', 'اتریش', 'Österreich', 'Austria', 'Autriche', 'オーストリア', 'Austria', '奥地利', 'Avusturya', 'Австрия', 'Австрія', 'Austria'),
('AZE', 'AZ', 'Azerbaijan', 'Azerbaidjan', '아제르바이잔', 'Azerbaijão', 'Azerbaijão', 'Azerbeidzjan', 'Azerbajdžan', 'آذربایجان', 'Aserbaidschan', 'Azerbaiyán', 'Azerbaïdjan', 'アゼルバイジャン', 'Azerbaijan', '阿塞拜疆', 'Azerbaycan', 'Азербайджан', 'Азербайджан', 'Azerbejdżan'),
('BHR', 'BH', 'Bahrain', 'Bahrein', '바레인', 'Bahrein', 'Barém', 'Bahrein', 'Bahrein', 'بحرین', 'Bahrain', 'Bahrein', 'Bahreïn', 'バーレーン', 'Bahrein', '巴林', 'Bahreyn', 'Бахрейн', 'Бахрейн', 'Bahrajn'),
('BGD', 'BD', 'Bangladesh', 'Bangladesh', '방글라데시', 'Bangladesh', 'Bangladeche', 'Bangladesh', 'Bangladeš', 'بنگلادش', 'Bangladesch', 'Bangladesh', 'Bangladesh', 'バングラデシュ', 'Bangladesh', '孟加拉', 'Bangladeş', 'Бангладеш', 'Бангладеш', 'Bangladesz'),
('BRB', 'BB', 'Barbados', 'Barbados', '바베이도스', 'Barbados', 'Barbados', 'Barbados', 'Barbados', 'باربادوس', 'Barbados', 'Barbados', 'Barbade', 'バルバドス', 'Barbados', '巴巴多斯', 'Barbados', 'Барбадос', 'Барбадос', 'Barbados'),
('BLR', 'BY', 'Belarus', 'Belarus', '벨라루스', 'Bielorrússia', 'Bielorrússia', 'Wit-Rusland', 'Bjelorusija', 'بلاروس', 'Weißrussland', 'Bielorrusia', 'Biélorussie', 'ベラルーシ', 'Bielorussia', '白俄罗斯', 'Belarus', 'Беларусь', 'Білорусь', 'Białoruś'),
('BEL', 'BE', 'Belgium', 'Belgia', '벨기에', 'Bélgica', 'Bélgica', 'België', 'Belgija', 'بلژیک', 'Belgien', 'Bélgica', 'Belgique', 'ベルギー', 'Belgio', '比利时', 'Belçika', 'Бельгия', 'Бельгія', 'Belgia'),
('BLZ', 'BZ', 'Belize', 'Belize', '벨리즈', 'Belize', 'Belize', 'Belize', 'Belize', 'بلیز', 'Belize', 'Belice', 'Belize', 'ベリーズ', 'Belize', '伯利兹', 'Belize', 'Белиз', 'Беліз', 'Belize'),
('BEN', 'BJ', 'Benin', 'Benin', '베냉', 'Benin', 'Benim', 'Benin', 'Benin', 'بنین', 'Benin', 'Benín', 'Bénin', 'ベナン', 'Benin', '贝宁', 'Benin', 'Бенин', 'Бенін', 'Benin'),
('BMU', 'BM', 'Bermuda', 'Bermuda', '버뮤다', 'Bermudas', 'Bermudas', 'Bermuda', 'Bermudi', 'برمودا', 'Bermuda', 'Bermudas', 'Bermudes', 'バミューダ', 'Bermuda', '百慕大', 'Bermuda', 'Бермуды', 'Бермудські острови', 'Bermudy'),
('BTN', 'BT', 'Bhutan', 'Bhoutan', '부탄', 'Butão', 'Butão', 'Bhutan', 'Butan', 'بوتان', 'Bhutan', 'Bután', 'Bhoutan', 'ブータン', 'Bhutan', '不丹', 'Butan', 'Бутан', 'Бутан', 'Bhutan'),
('BOL', 'BO', 'Bolivia', 'Bolivia', '볼리비아', 'Bolívia', 'Bolívia', 'Bolivia', 'Bolivija', 'بولیوی', 'Bolivien', 'Bolivia', 'Bolivie', 'ボリビア多民族国', 'Bolivia', '玻利维亚', 'Bolivya', 'Боливия', 'Болівія', 'Boliwia'),
('BES', 'BQ', 'Bonaire, Sint Eustatius and Saba', 'Izelvroioù ar C''harib', '보네르 섬', 'Bonaire', 'Bonaire', NULL, NULL, 'بونیر', 'Bonaire, Sint Eustatius und Saba', NULL, 'Bonaire, Saint-Eustache et Saba', NULL, 'Bonaire, Saint-Eustache e Saba', '博内尔岛、圣尤斯特歇斯和萨巴岛', 'Karayip Hollandasi', 'Бонайре, Синт-Эстатиус и Саба', 'Бонайре, Сент-Естатіус і Саба', 'Bonaire, Sint Eustatius i Saba'),
('BIH', 'BA', 'Bosnia and Herzegovina', 'Bosnia-ha-Herzegovina', '보스니아 헤르체고비나', 'Bósnia e Herzegovina', 'Bósnia e Herzegovina', 'Bosnië en Herzegovina', 'Bosna i Hercegovina', 'بوسنی و هرزگوین', 'Bosnien und Herzegowina', 'Bosnia y Herzegovina', 'Bosnie-Herzégovine', 'ボスニア・ヘルツェゴビナ', 'Bosnia ed Erzegovina', '波斯尼亚和黑塞哥维那', 'Bosna Hersek', 'Босния и Герцеговина', 'Боснія і Герцеговина', 'Bośnia i Hercegowina'),
('BWA', 'BW', 'Botswana', 'Botswana', '보츠와나', 'Botsuana', 'Botsuana', 'Botswana', 'Bocvana', 'بوتسوانا', 'Botswana', 'Botswana', 'Botswana', 'ボツワナ', 'Botswana', '博茨瓦纳', 'Botsvana', 'Ботсвана', 'Ботсвана', 'Botswana'),
('BVT', 'BV', 'Bouvet Island', 'Enez Bouvet', '부벳 섬', 'Ilha Bouvet', 'Ilha Bouvet', 'Bouveteiland', 'Otok Bouvet', 'جزیره بووه', 'Bouvetinsel', 'Isla Bouvet', 'Île Bouvet', 'ブーベ島', 'Isola Bouvet', '布维岛', 'Bouvet Adasi', 'Остров Буве', 'Острів Буве', 'Wyspa Bouveta'),
('BRA', 'BR', 'Brazil', 'Brazil', '브라질', 'Brasil', 'Brasil', 'Brazilië', 'Brazil', 'برزیل', 'Brasilien', 'Brasil', 'Brésil', 'ブラジル', 'Brasile', '巴西', 'Brezilya', 'Бразилия', 'Бразилія', 'Brazylia'),
('IOT', 'IO', 'British Indian Ocean Territory', 'Tiriad Meurvor Indez Breizh-Veur', '영국령 인도양 지역', 'Território Britânico do Oceano íÍdico', 'Território Britânico do Oceano Índico', 'Britse Gebieden in de Indische Oceaan', 'Britanski Indijskooceanski teritorij', 'قلمرو بریتانیا در اقیانوس هند', 'Britisches Territorium im Indischen Ozean', 'Territorio Británico del Océano Índico', 'Territoire britannique de l''océan Indien', 'イギリス領インド洋地域', 'Territorio britannico dell''oceano indiano', '英属印度洋领地', 'Britanya Hint Okyanusu Topraklari', 'Британская территория в Индийском океане', 'Британська територія в Індійському океані', 'Brytyjskie Terytorium Oceanu Indyjskiego'),
('BRN', 'BN', 'Brunei', 'Brunei', '브루나이', 'Brunei', 'Brunei', 'Brunei', 'Brunej', 'برونئی', 'Brunei', 'Brunei', 'Brunei', 'ブルネイ・ダルサラーム', 'Brunei', '文莱', 'Brunei', 'Бруней', 'Бруней', 'Brunei'),
('BGR', 'BG', 'Bulgaria', 'Bulgaria', '불가리아', 'Bulgária', 'Bulgária', 'Bulgarije', 'Bugarska', 'بلغارستان', 'Bulgarien', 'Bulgaria', 'Bulgarie', 'ブルガリア', 'Bulgaria', '保加利亚', 'Bulgaristan', 'Болгария', 'Болгарія', 'Bułgaria'),
('BFA', 'BF', 'Burkina Faso', 'Burkina Faso', '부르키나 파소', 'Burkina Faso', 'Burquina Faso', 'Burkina Faso', 'Burkina Faso', 'بورکینافاسو', 'Burkina Faso', 'Burkina Faso', 'Burkina Faso', 'ブルキナファソ', 'Burkina Faso', '布基纳法索', 'Burkina Faso', 'Буркина-Фасо', 'Буркіна-Фасо', 'Burkina Faso'),
('BDI', 'BI', 'Burundi', 'Burundi', '부룬디', 'Burundi', 'Burúndi', 'Burundi', 'Burundi', 'بوروندی', 'Burundi', 'Burundi', 'Burundi', 'ブルンジ', 'Burundi', '布隆迪', 'Burundi', 'Бурунди', 'Бурунді', 'Burundi'),
('KHM', 'KH', 'Cambodia', 'Kambodja', '캄보디아', 'Camboja', 'Camboja', 'Cambodja', 'Kambodža', 'کامبوج', 'Kambodscha', 'Camboya', 'Cambodge', 'カンボジア', 'Cambogia', '柬埔寨', 'Kamboçya', 'Камбоджа', 'Камбоджа', 'Kambodża'),
('CMR', 'CM', 'Cameroon', 'Kameroun', '카메룬', 'Camarões', 'Camarões', 'Kameroen', 'Kamerun', 'کامرون', 'Kamerun', 'Camerún', 'Cameroun', 'カメルーン', 'Camerun', '喀麦隆', 'Kamerun', 'Камерун', 'Камерун', 'Kamerun'),
('CAN', 'CA', 'Canada', 'Kanada', '캐나다', 'Canadá', 'Canadá', 'Canada', 'Kanada', 'کانادا', 'Kanada', 'Canadá', 'Canada', 'カナダ', 'Canada', '加拿大', 'Kanada', 'Канада', 'Канада', 'Kanada'),
('CPV', 'CV', 'Cape Verde', 'Kab Glas', '카보베르데', 'Cabo Verde', 'Cabo Verde', 'Kaapverdië', 'Zelenortska Republika', 'کیپ ورد', 'Kap Verde', 'Cabo Verde', 'Cap Vert', 'カーボベルデ', 'Capo Verde', '佛得角', 'Cabo Verde', 'Кабо-Верде', 'Кабо-Верде', 'Republika Zielonego Przylądka'),
('CYM', 'KY', 'Cayman Islands', 'Inizi Cayman', '케이먼 제도', 'Ilhas Cayman', 'Ilhas Caimão', 'Caymaneilanden', 'Kajmanski otoci', 'جزایر کیمن', 'Kaimaninseln', 'Islas Caimán', 'Îles Caïmans', 'ケイマン諸島', 'Isole Cayman', '开曼群岛', 'Cayman Adalari', 'Каймановы острова', 'Кайманові острови', 'Kajmany'),
('CAF', 'CF', 'Central African Republic', 'Republik Kreizafrikan', '중앙아프리카 공화국', 'República Centro-Africana', 'República Centro-Africana', 'Centraal-Afrikaanse Republiek', 'Srednjoafrička Republika', 'جمهوری آفریقای مرکزی', 'Zentralafrikanische Republik', 'República Centroafricana', 'République centrafricaine', '中央アフリカ共和国', 'Repubblica Centrafricana', '中非', 'Orta Afrika Cumhuriyeti', 'Центральноафриканская Республика', 'Центральноафриканська Республіка', 'Republika Środkowoafrykańska'),
('TCD', 'TD', 'Chad', 'Tchad', '차드', 'Chade', 'Chade', 'Tsjaad', 'Čad', 'چاد', 'Tschad', 'Chad', 'Tchad', 'チャド', 'Ciad', '乍得', 'Çad', 'Чад', 'Чад.', 'Czad'),
('CHL', 'CL', 'Chile', 'Chile', '칠리', 'Chile', 'Chile', 'Chili', 'Čile', 'شیلی', 'Chile', 'Chile', 'Chili', 'チリ', 'Cile', '智利', 'Şili', 'Чили', 'Чилі', 'Chile'),
('CHN', 'CN', 'China', 'Sina', '중국', 'China', 'China', 'China', 'Kina', 'چین', 'China', 'China', 'Chine', '中国', 'Cina', '中国', 'Çin', 'Китай', 'Китай', 'Chiny'),
('CXR', 'CX', 'Christmas Island', 'Enez Christmas', '크리스마스 섬', 'Ilha Christmas', 'Ilha do Natal', 'Christmaseiland', 'Božićni otok', 'جزیره کریسمس', 'Weihnachtsinsel', 'Isla de Navidad', 'Île Christmas', 'クリスマス島', 'Isola di Natale', '圣诞岛', 'Christmas Adasi', 'Остров Рождества', 'Острів Різдва', 'Wyspa Bożego Narodzenia'),
('CCK', 'CC', 'Cocos (Keeling) Islands', 'Inizi Cocos', '코코스 제도', 'Ilhas Cocos', 'Ilhas dos Cocos', 'Cocoseilanden', 'Kokosovi Otoci', 'جزایر کوکوس', 'Kokosinseln', 'Islas Cocos o Islas Keeling', 'Îles Cocos', 'ココス(キーリング)諸島', 'Isole Cocos e Keeling', '科科斯(基林)群岛', 'Cocos Adalari', 'Кокосовые (Килинг) острова', 'Кокосові (Кілінг) острови', 'Wyspy Kokosowe (Keelinga)'),
('COL', 'CO', 'Colombia', 'Kolombia', '콜롬비아', 'Colômbia', 'Colômbia', 'Colombia', 'Kolumbija', 'کلمبیا', 'Kolumbien', 'Colombia', 'Colombie', 'コロンビア', 'Colombia', '哥伦比亚', 'Kolombiya', 'Колумбия', 'Колумбія', 'Kolumbia'),
('COM', 'KM', 'Comoros', 'Komorez', '코모로', 'Comores', 'Comores', 'Comoren', 'Komori', 'کومور', 'Union der Komoren', 'Comoras', 'Comores', 'コモロ', 'Comore', '科摩罗', 'Komorlar', 'Коморские острова', 'Коморські острови', 'Komory'),
('COG', 'CG', 'Congo', 'Republik Kongo', '콩고', 'Congo', 'Congo', 'Congo [Republiek]', 'Kongo', 'کنگو', 'Kongo', 'Congo', 'Congo', 'コンゴ共和国', 'Congo', '刚果', 'Kongo', 'Конго', 'Конго', 'Kongo'),
('COK', 'CK', 'Cook Islands', 'Inizi Cook', '쿡 제도', 'Ilhas Cook', 'Ilhas Cook', 'Cookeilanden', 'Cookovo Otočje', 'جزایر کوک', 'Cookinseln', 'Islas Cook', 'Îles Cook', 'クック諸島', 'Isole Cook', '库克群岛', 'Cook Adalari', 'Острова Кука', 'Острови Кука', 'Wyspy Cooka'),
('CRI', 'CR', 'Costa Rica', 'Costa Rica', '코스타리카', 'Costa Rica', 'Costa Rica', 'Costa Rica', 'Kostarika', 'کاستاریکا', 'Costa Rica', 'Costa Rica', 'Costa Rica', 'コスタリカ', 'Costa Rica', '哥斯达黎加', 'Kosta Rika', 'Коста-Рика', 'Коста-Ріка', 'Kostaryka'),
('CIV', 'CI', 'Cote D''Ivoire (Ivory Coast)', 'Aod an Olifant', '코트디부아르', 'Costa do Marfim', 'Costa do Marfim', 'Ivoorkust', 'Obala Bjelokosti', 'ساحل عاج', 'Elfenbeinküste', 'Costa de Marfil', 'Côte d''Ivoire', 'コートジボワール', 'Costa D''Avorio', '科特迪瓦', 'Kotdivuar', 'Кот-д''Ивуар (Берег Слоновой Кости)', 'Кот-д''Івуар (Берег Слонової Кістки)', 'Cote D''Ivoire (Wybrzeże Kości Słoniowej)'),
('HRV', 'HR', 'Croatia', 'Kroatia', '크로아티아', 'Croácia', 'Croácia', 'Kroatië', 'Hrvatska', 'کرواسی', 'Kroatien', 'Croacia', 'Croatie', 'クロアチア', 'Croazia', '克罗地亚', 'Hirvatistan', 'Хорватия', 'Хорватія', 'Chorwacja'),
('CUB', 'CU', 'Cuba', 'Kuba', '쿠바', 'Cuba', 'Cuba', 'Cuba', 'Kuba', 'کوبا', 'Kuba', 'Cuba', 'Cuba', 'キューバ', 'Cuba', '古巴', 'Küba', 'Куба', 'Куба', 'Kuba'),
('CUW', 'CW', 'Curaçao', 'Curaçao', '퀴라소', 'Curaçao', 'Curaçao', 'Curaçao', NULL, 'کوراسائو', 'Curaçao', NULL, 'Curaçao', NULL, 'Curaçao', '库拉索', 'Curaçao', 'Кюрасао', 'Кюрасао', 'Curaçao'),
('CYP', 'CY', 'Cyprus', 'Republik Kiprenez', '키프로스', 'Chipre', 'Chipre', 'Cyprus', 'Cipar', 'قبرس', 'Zypern', 'Chipre', 'Chypre', 'キプロス', 'Cipro', '塞浦路斯', 'Kuzey Kıbrıs Türk Cumhuriyeti', 'Кипр', 'Кіпр', 'Cypr'),
('CZE', 'CZ', 'Czech Republic', 'Tchekia', '체코', 'República Tcheca', 'República Checa', 'Tsjechië', 'Češka', 'جمهوری چک', 'Tschechische Republik', 'República Checa', 'République tchèque', 'チェコ', 'Repubblica Ceca', '捷克', 'Çekya', 'Чешская Республика', 'Чеська Республіка', 'Republika Czeska'),
('COD', 'CD', 'Democratic Republic of the Congo', 'Kongo (RD)', '콩고 민주 공화국', 'RD Congo', 'RD Congo', 'Congo [DRC]', 'Kongo, Demokratska Republika', 'جمهوری کنگو', 'Kongo (Dem. Rep.)', 'Congo (Rep. Dem.)', 'Congo (Rép. dém.)', 'コンゴ民主共和国', 'Congo (Rep. Dem.)', '刚果(金)', 'Kongo Demokratik Cumhuriyeti', 'Демократическая Республика Конго', 'Демократична Республіка Конго', 'Demokratyczna Republika Konga'),
('DNK', 'DK', 'Denmark', 'Danmark', '덴마크', 'Dinamarca', 'Dinamarca', 'Denemarken', 'Danska', 'دانمارک', 'Dänemark', 'Dinamarca', 'Danemark', 'デンマーク', 'Danimarca', '丹麦', 'Danimarka', 'Дания', 'Данія', 'Dania'),
('DJI', 'DJ', 'Djibouti', 'Djibouti', '지부티', 'Djibuti', 'Djibuti', 'Djibouti', 'Džibuti', 'جیبوتی', 'Dschibuti', 'Yibuti', 'Djibouti', 'ジブチ', 'Gibuti', '吉布提', 'Cibuti', 'Джибути', 'Джибуті', 'Dżibuti'),
('DMA', 'DM', 'Dominica', 'Dominika', '도미니카 연방', 'Dominica', 'Dominica', 'Dominica', 'Dominika', 'دومینیکا', 'Dominica', 'Dominica', 'Dominique', 'ドミニカ国', 'Dominica', '多米尼加', 'Dominika', 'Доминика', 'Домініка', 'Dominika'),
('DOM', 'DO', 'Dominican Republic', 'Republik Dominikan', '도미니카 공화국', 'República Dominicana', 'República Dominicana', 'Dominicaanse Republiek', 'Dominikanska Republika', 'جمهوری دومینیکن', 'Dominikanische Republik', 'República Dominicana', 'République dominicaine', 'ドミニカ共和国', 'Repubblica Dominicana', '多明尼加共和国', 'Dominik Cumhuriyeti', 'Доминиканская Республика', 'Домініканська Республіка', 'Republika Dominikańska'),
('ECU', 'EC', 'Ecuador', 'Ecuador', '에콰도르', 'Equador', 'Equador', 'Ecuador', 'Ekvador', 'اکوادور', 'Ecuador', 'Ecuador', 'Équateur', 'エクアドル', 'Ecuador', '厄瓜多尔', 'Ekvator', 'Эквадор', 'Еквадор', 'Ekwador'),
('EGY', 'EG', 'Egypt', 'Egipt', '이집트', 'Egito', 'Egipto', 'Egypte', 'Egipat', 'مصر', 'Ägypten', 'Egipto', 'Égypte', 'エジプト', 'Egitto', '埃及', 'Mısır', 'Египет', 'Єгипет', 'Egipt'),
('SLV', 'SV', 'El Salvador', 'El Salvador', '엘살바도르', 'El Salvador', 'El Salvador', 'El Salvador', 'Salvador', 'السالوادور', 'El Salvador', 'El Salvador', 'Salvador', 'エルサルバドル', 'El Salvador', '萨尔瓦多', 'El Salvador', 'Сальвадор', 'Сальвадор', 'Salwador'),
('GNQ', 'GQ', 'Equatorial Guinea', 'Ginea ar C''heheder', '적도 기니', 'Guiné Equatorial', 'Guiné Equatorial', 'Equatoriaal-Guinea', 'Ekvatorijalna Gvineja', 'گینه استوایی', 'Äquatorial-Guinea', 'Guinea Ecuatorial', 'Guinée-Équatoriale', '赤道ギニア', 'Guinea Equatoriale', '赤道几内亚', 'Ekvator Ginesi', 'Экваториальная Гвинея', 'Екваторіальна Гвінея', 'Gwinea Równikowa'),
('ERI', 'ER', 'Eritrea', 'Eritrea', '에리트레아', 'Eritreia', 'Eritreia', 'Eritrea', 'Eritreja', 'اریتره', 'Eritrea', 'Eritrea', 'Érythrée', 'エリトリア', 'Eritrea', '厄立特里亚', 'Eritre', 'Эритрея', 'Еритрея', 'Erytrea'),
('EST', 'EE', 'Estonia', 'Estonia', '에스토니아', 'Estônia', 'Estónia', 'Estland', 'Estonija', 'استونی', 'Estland', 'Estonia', 'Estonie', 'エストニア', 'Estonia', '爱沙尼亚', 'Estonya', 'Эстония', 'Естонія', 'Estonia'),
('SWZ', 'SZ', 'Eswatini', 'Eswatini', '에스와티니', 'Suazilândia', 'Suazilândia', 'Swaziland', 'Svazi', 'سوازیلند', 'Swasiland', 'Suazilandia', 'Swaziland', 'スワジランド', 'Swaziland', '斯威士兰', 'Esvatini', 'Эсватини', 'Есватіні', 'Eswatini'),
('ETH', 'ET', 'Ethiopia', 'Etiopia', '에티오피아', 'Etiópia', 'Etiópia', 'Ethiopië', 'Etiopija', 'اتیوپی', 'Äthiopien', 'Etiopía', 'Éthiopie', 'エチオピア', 'Etiopia', '埃塞俄比亚', 'Etiyopya', 'Эфиопия', 'Ефіопія', 'Etiopia'),
('FLK', 'FK', 'Falkland Islands', 'Inizi Maloù', '포클랜드 제도', 'Ilhas Malvinas', 'Ilhas Falkland', 'Falklandeilanden [Islas Malvinas]', 'Falklandski Otoci', 'جزایر فالکلند', 'Falklandinseln', 'Islas Malvinas', 'Îles Malouines', 'フォークランド(マルビナス)諸島', 'Isole Falkland o Isole Malvine', '福克兰群岛', 'Falkland Adalari', 'Фолклендские острова', 'Фолклендські острови', 'Falklandy'),
('FRO', 'FO', 'Faroe Islands', 'Faero', '페로 제도', 'Ilhas Faroé', 'Ilhas Faroé', 'Faeröer', 'Farski Otoci', 'جزایر فارو', 'Färöer-Inseln', 'Islas Faroe', 'Îles Féroé', 'フェロー諸島', 'Isole Far Oer', '法罗群岛', 'Faroe Adalari', 'Фарерские острова', 'Фарерські острови', 'Wyspy Owcze'),
('FJI', 'FJ', 'Fiji Islands', 'Fidji', '피지', 'Fiji', 'Fiji', 'Fiji', 'Fiđi', 'فیجی', 'Fidschi', 'Fiyi', 'Fidji', 'フィジー', 'Figi', '斐济', 'Fiji', 'Острова Фиджи', 'Острови Фіджі', 'Wyspy Fidżi'),
('FIN', 'FI', 'Finland', 'Finland', '핀란드', 'Finlândia', 'Finlândia', 'Finland', 'Finska', 'فنلاند', 'Finnland', 'Finlandia', 'Finlande', 'フィンランド', 'Finlandia', '芬兰', 'Finlandiya', 'Финляндия', 'Фінляндія', 'Finlandia'),
('FRA', 'FR', 'France', 'Frañs', '프랑스', 'França', 'França', 'Frankrijk', 'Francuska', 'فرانسه', 'Frankreich', 'Francia', 'France', 'フランス', 'Francia', '法国', 'Fransa', 'Франция', 'Франція', 'Francja'),
('GUF', 'GF', 'French Guiana', 'Gwiana', '프랑스령 기아나', 'Guiana Francesa', 'Guiana Francesa', 'Frans-Guyana', 'Francuska Gvajana', 'گویان فرانسه', 'Französisch Guyana', 'Guayana Francesa', 'Guayane', 'フランス領ギアナ', 'Guyana francese', '法属圭亚那', 'Fransiz Guyanasi', 'Французская Гвиана', 'Французька Гвіана', 'Gujana Francuska'),
('PYF', 'PF', 'French Polynesia', 'Polinezia C''hall', '프랑스령 폴리네시아', 'Polinésia Francesa', 'Polinésia Francesa', 'Frans-Polynesië', 'Francuska Polinezija', 'پلی‌نزی فرانسه', 'Französisch-Polynesien', 'Polinesia Francesa', 'Polynésie française', 'フランス領ポリネシア', 'Polinesia Francese', '法属波利尼西亚', 'Fransiz Polinezyasi', 'Французская Полинезия', 'Французька Полінезія', 'Polinezja Francuska'),
('ATF', 'TF', 'French Southern Territories', 'Douaroù Aostral hag Antarktikel Frañs', '프랑스령 남방 및 남극', 'Terras Austrais e Antárticas Francesas', 'Terras Austrais e Antárticas Francesas', 'Franse Gebieden in de zuidelijke Indische Oceaan', 'Francuski južni i antarktički teritoriji', 'سرزمین‌های جنوبی و جنوبگانی فرانسه', 'Französische Süd- und Antarktisgebiete', 'Tierras Australes y Antárticas Francesas', 'Terres australes et antarctiques françaises', 'フランス領南方・南極地域', 'Territori Francesi del Sud', '法属南部领地', 'Fransiz Güney Topraklari', 'Французские южные территории', 'Французькі південні території', 'Francuskie terytoria południowe'),
('GAB', 'GA', 'Gabon', 'Gabon', '가봉', 'Gabão', 'Gabão', 'Gabon', 'Gabon', 'گابن', 'Gabun', 'Gabón', 'Gabon', 'ガボン', 'Gabon', '加蓬', 'Gabon', 'Габон', 'Габон', 'Gabon'),
('GEO', 'GE', 'Georgia', 'Jorjia', '조지아', 'Geórgia', 'Geórgia', 'Georgië', 'Gruzija', 'گرجستان', 'Georgien', 'Georgia', 'Géorgie', 'グルジア', 'Georgia', '格鲁吉亚', 'Gürcistan', 'Джорджия', 'Грузія', 'Gruzja'),
('DEU', 'DE', 'Germany', 'Alamagn', '독일', 'Alemanha', 'Alemanha', 'Duitsland', 'Njemačka', 'آلمان', 'Deutschland', 'Alemania', 'Allemagne', 'ドイツ', 'Germania', '德国', 'Almanya', 'Германия', 'Німеччина', 'Niemcy'),
('GHA', 'GH', 'Ghana', 'Ghana', '가나', 'Gana', 'Gana', 'Ghana', 'Gana', 'غنا', 'Ghana', 'Ghana', 'Ghana', 'ガーナ', 'Ghana', '加纳', 'Gana', 'Гана', 'Гана', 'Ghana'),
('GIB', 'GI', 'Gibraltar', 'Jibraltar', '지브롤터', 'Gibraltar', 'Gibraltar', 'Gibraltar', 'Gibraltar', 'جبل‌طارق', 'Gibraltar', 'Gibraltar', 'Gibraltar', 'ジブラルタル', 'Gibilterra', '直布罗陀', 'Cebelitarik', 'Гибралтар', 'Гібралтар', 'Gibraltar'),
('GRC', 'GR', 'Greece', 'Gres', '그리스', 'Grécia', 'Grécia', 'Griekenland', 'Grčka', 'یونان', 'Griechenland', 'Grecia', 'Grèce', 'ギリシャ', 'Grecia', '希腊', 'Yunanistan', 'Греция', 'Греція', 'Grecja'),
('GRL', 'GL', 'Greenland', 'Greunland', '그린란드', 'Groelândia', 'Gronelândia', 'Groenland', 'Grenland', 'گرینلند', 'Grönland', 'Groenlandia', 'Groenland', 'グリーンランド', 'Groenlandia', '格陵兰岛', 'Grönland', 'Гренландия', 'Гренландія', 'Grenlandia'),
('GRD', 'GD', 'Grenada', 'Grenada', '그레나다', 'Granada', 'Granada', 'Grenada', 'Grenada', 'گرنادا', 'Grenada', 'Grenada', 'Grenade', 'グレナダ', 'Grenada', '格林纳达', 'Grenada', 'Гренада', 'Гренада', 'Grenada'),
('GLP', 'GP', 'Guadeloupe', 'Gwadloup', '과들루프', 'Guadalupe', 'Guadalupe', 'Guadeloupe', 'Gvadalupa', 'جزیره گوادلوپ', 'Guadeloupe', 'Guadalupe', 'Guadeloupe', 'グアドループ', 'Guadeloupa', '瓜德罗普岛', 'Guadeloupe', 'Гваделупа', 'Гваделупа', 'Gwadelupa'),
('GUM', 'GU', 'Guam', 'Guam', '', 'Guam', 'Guame', 'Guam', 'Guam', 'گوام', 'Guam', 'Guam', 'Guam', 'グアム', 'Guam', '关岛', 'Guam', 'Гуам', 'Гуам', 'Guam'),
('GTM', 'GT', 'Guatemala', 'Guatemala', '과테말라', 'Guatemala', 'Guatemala', 'Guatemala', 'Gvatemala', 'گواتمالا', 'Guatemala', 'Guatemala', 'Guatemala', 'グアテマラ', 'Guatemala', '危地马拉', 'Guatemala', 'Гватемала', 'Гватемала', 'Gwatemala'),
('GGY', 'GG', 'Guernsey', 'Gwernenez', '건지, 올더니', 'Guernsey', 'Guernsey', 'Guernsey', 'Guernsey', 'گرنزی', 'Guernsey', 'Guernsey', 'Guernesey', 'ガーンジー', 'Guernsey', '根西岛', 'Alderney', 'Гернси и Олдерни', 'Гернсі та Олдерні', 'Guernsey i Alderney'),
('GIN', 'GN', 'Guinea', 'Ginea', '기니', 'Guiné', 'Guiné', 'Guinee', 'Gvineja', 'گینه', 'Guinea', 'Guinea', 'Guinée', 'ギニア', 'Guinea', '几内亚', 'Gine', 'Гвинея', 'Гвінея', 'Gwinea'),
('GNB', 'GW', 'Guinea-Bissau', 'Ginea-Bissau', '기니비사우', 'Guiné-Bissau', 'Guiné-Bissau', 'Guinee-Bissau', 'Gvineja Bisau', 'گینه بیسائو', 'Guinea-Bissau', 'Guinea-Bisáu', 'Guinée-Bissau', 'ギニアビサウ', 'Guinea-Bissau', '几内亚比绍', 'Gine-bissau', 'Гвинея-Бисау', 'Гвінея-Бісау', 'Gwinea Bissau'),
('GUY', 'GY', 'Guyana', 'Guyana', '가이아나', 'Guiana', 'Guiana', 'Guyana', 'Gvajana', 'گویان', 'Guyana', 'Guyana', 'Guyane', 'ガイアナ', 'Guyana', '圭亚那', 'Guyana', 'Гайана', 'Гайана', 'Gujana'),
('HTI', 'HT', 'Haiti', 'Haiti', '아이티', 'Haiti', 'Haiti', 'Haïti', 'Haiti', 'هائیتی', 'Haiti', 'Haiti', 'Haïti', 'ハイチ', 'Haiti', '海地', 'Haiti', 'Гаити', 'Гаїті', 'Haiti'),
('HMD', 'HM', 'Heard Island and McDonald Islands', 'Inizi Heard ha McDonald', '허드 맥도날드 제도', 'Ilha Heard e Ilhas McDonald', 'Ilha Heard e Ilhas McDonald', 'Heard- en McDonaldeilanden', 'Otok Heard i otočje McDonald', 'جزیره هرد و جزایر مک‌دونالد', 'Heard und die McDonaldinseln', 'Islas Heard y McDonald', 'Îles Heard-et-MacDonald', 'ハード島とマクドナルド諸島', 'Isole Heard e McDonald', '赫德·唐纳岛及麦唐纳岛', 'Heard Adasi Ve Mcdonald Adalari', 'Остров Херд и острова Макдональд', 'Острів Херд та острови Макдональд', 'Wyspa Heard i Wyspy McDonalda'),
('HND', 'HN', 'Honduras', 'Honduras', '온두라스', 'Honduras', 'Honduras', 'Honduras', 'Honduras', 'هندوراس', 'Honduras', 'Honduras', 'Honduras', 'ホンジュラス', 'Honduras', '洪都拉斯', 'Honduras', 'Гондурас', 'Гондурас', 'Honduras'),
('HKG', 'HK', 'Hong Kong S.A.R.', 'Hong Kong', '홍콩', 'Hong Kong', 'Hong Kong', 'Hongkong', 'Hong Kong', 'هنگ‌کنگ', 'Hong Kong', 'Hong Kong', 'Hong Kong', '香港', 'Hong Kong', '中国香港', 'Hong Kong', 'Гонконг С.А.Р.', 'Гонконг САР.', 'Hongkong S.A.R.'),
('HUN', 'HU', 'Hungary', 'Hungaria', '헝가리', 'Hungria', 'Hungria', 'Hongarije', 'Mađarska', 'مجارستان', 'Ungarn', 'Hungría', 'Hongrie', 'ハンガリー', 'Ungheria', '匈牙利', 'Macaristan', 'Венгрия', 'Угорщина', 'Węgry'),
('ISL', 'IS', 'Iceland', 'Island', '아이슬란드', 'Islândia', 'Islândia', 'IJsland', 'Island', 'ایسلند', 'Island', 'Islandia', 'Islande', 'アイスランド', 'Islanda', '冰岛', 'İzlanda', 'Исландия', 'Ісландія', 'Islandia'),
('IND', 'IN', 'India', 'India', '인도', 'Índia', 'Índia', 'India', 'Indija', 'هند', 'Indien', 'India', 'Inde', 'インド', 'India', '印度', 'Hindistan', 'Индия', 'Індія', 'Indie'),
('IDN', 'ID', 'Indonesia', 'Indonezia', '인도네시아', 'Indonésia', 'Indonésia', 'Indonesië', 'Indonezija', 'اندونزی', 'Indonesien', 'Indonesia', 'Indonésie', 'インドネシア', 'Indonesia', '印度尼西亚', 'Endonezya', 'Индонезия', 'Індонезія', 'Indonezja'),
('IRN', 'IR', 'Iran', 'Iran', '이란', 'Irã', 'Irão', 'Iran', 'Iran', 'ایران', 'Iran', 'Iran', 'Iran', 'イラン・イスラム共和国', NULL, '伊朗', 'İran', 'Иран', 'Іран', 'Iran'),
('IRQ', 'IQ', 'Iraq', 'Irak', '이라크', 'Iraque', 'Iraque', 'Irak', 'Irak', 'عراق', 'Irak', 'Irak', 'Irak', 'イラク', 'Iraq', '伊拉克', 'Irak', 'Ирак', 'Ірак', 'Irak'),
('IRL', 'IE', 'Ireland', 'Iwerzhon', '아일랜드', 'Irlanda', 'Irlanda', 'Ierland', 'Irska', 'ایرلند', 'Irland', 'Irlanda', 'Irlande', 'アイルランド', 'Irlanda', '爱尔兰', 'İrlanda', 'Ирландия', 'Ірландія', 'Irlandia'),
('ISR', 'IL', 'Israel', 'Israel', '이스라엘', 'Israel', 'Israel', 'Israël', 'Izrael', 'اسرائیل', 'Israel', 'Israel', 'Israël', 'イスラエル', 'Israele', '以色列', 'İsrail', 'Израиль', 'Ізраїль', 'Izrael'),
('ITA', 'IT', 'Italy', 'Italia', '이탈리아', 'Itália', 'Itália', 'Italië', 'Italija', 'ایتالیا', 'Italien', 'Italia', 'Italie', 'イタリア', 'Italia', '意大利', 'İtalya', 'Италия', 'Італія', 'Włochy'),
('JAM', 'JM', 'Jamaica', 'Jamaika', '자메이카', 'Jamaica', 'Jamaica', 'Jamaica', 'Jamajka', 'جامائیکا', 'Jamaika', 'Jamaica', 'Jamaïque', 'ジャマイカ', 'Giamaica', '牙买加', 'Jamaika', 'Ямайка', 'Ямайка', 'Jamajka'),
('JPN', 'JP', 'Japan', 'Japan', '일본', 'Japão', 'Japão', 'Japan', 'Japan', 'ژاپن', 'Japan', 'Japón', 'Japon', '日本', 'Giappone', '日本', 'Japonya', 'Япония', 'Японія', 'Japonia'),
('JEY', 'JE', 'Jersey', 'Jerzenez', '저지 섬', 'Jersey', 'Jersey', 'Jersey', 'Jersey', 'جرزی', 'Jersey', 'Jersey', 'Jersey', 'ジャージー', 'Isola di Jersey', '泽西岛', 'Jersey', 'Джерси', 'Джерсі', 'Jersey'),
('JOR', 'JO', 'Jordan', 'Jordania', '요르단', 'Jordânia', 'Jordânia', 'Jordanië', 'Jordan', 'اردن', 'Jordanien', 'Jordania', 'Jordanie', 'ヨルダン', 'Giordania', '约旦', 'Ürdün', 'Джордан', 'Йорданія', 'Jordan'),
('KAZ', 'KZ', 'Kazakhstan', 'Kazakstan', '카자흐스탄', 'Cazaquistão', 'Cazaquistão', 'Kazachstan', 'Kazahstan', 'قزاقستان', 'Kasachstan', 'Kazajistán', 'Kazakhstan', 'カザフスタン', 'Kazakistan', '哈萨克斯坦', 'Kazakistan', 'Казахстан', 'Казахстан', 'Kazachstan'),
('KEN', 'KE', 'Kenya', 'Kenya', '케냐', 'Quênia', 'Quénia', 'Kenia', 'Kenija', 'کنیا', 'Kenia', 'Kenia', 'Kenya', 'ケニア', 'Kenya', '肯尼亚', 'Kenya', 'Кения', 'Кенія', 'Kenia'),
('KIR', 'KI', 'Kiribati', 'Kiribati', '키리바시', 'Kiribati', 'Quiribáti', 'Kiribati', 'Kiribati', 'کیریباتی', 'Kiribati', 'Kiribati', 'Kiribati', 'キリバス', 'Kiribati', '基里巴斯', 'Kiribati', 'Кирибати', 'Кірібаті', 'Kiribati'),
('XKX', 'XK', 'Kosovo', 'Kosovo', '코소보', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '科索沃', 'Kosova', 'Косово', 'Косово', 'Kosowo'),
('KWT', 'KW', 'Kuwait', 'Koweit', '쿠웨이트', 'Kuwait', 'Kuwait', 'Koeweit', 'Kuvajt', 'کویت', 'Kuwait', 'Kuwait', 'Koweït', 'クウェート', 'Kuwait', '科威特', 'Kuveyt', 'Кувейт', 'Кувейт', 'Kuwejt'),
('KGZ', 'KG', 'Kyrgyzstan', 'Kirgizstan', '키르기스스탄', 'Quirguistão', 'Quirguizistão', 'Kirgizië', 'Kirgistan', 'قرقیزستان', 'Kirgisistan', 'Kirguizistán', 'Kirghizistan', 'キルギス', 'Kirghizistan', '吉尔吉斯斯坦', 'Kirgizistan', 'Кыргызстан', 'Киргизстан', 'Kirgistan'),
('LAO', 'LA', 'Laos', 'Laos', '라오스', 'Laos', 'Laos', 'Laos', 'Laos', 'لائوس', 'Laos', 'Laos', 'Laos', 'ラオス人民民主共和国', 'Laos', '寮人民民主共和国', 'Laos', 'Лаос', 'Лаос', 'Laos'),
('LVA', 'LV', 'Latvia', 'Latvia', '라트비아', 'Letônia', 'Letónia', 'Letland', 'Latvija', 'لتونی', 'Lettland', 'Letonia', 'Lettonie', 'ラトビア', 'Lettonia', '拉脱维亚', 'Letonya', 'Латвия', 'Латвія', 'Łotwa'),
('LBN', 'LB', 'Lebanon', 'Liban', '레바논', 'Líbano', 'Líbano', 'Libanon', 'Libanon', 'لبنان', 'Libanon', 'Líbano', 'Liban', 'レバノン', 'Libano', '黎巴嫩', 'Lübnan', 'Ливан', 'Ліван', 'Liban'),
('LSO', 'LS', 'Lesotho', 'Lesotho', '레소토', 'Lesoto', 'Lesoto', 'Lesotho', 'Lesoto', 'لسوتو', 'Lesotho', 'Lesotho', 'Lesotho', 'レソト', 'Lesotho', '莱索托', 'Lesotho', 'Лесото', 'Лесото', 'Lesotho'),
('LBR', 'LR', 'Liberia', 'Liberia', '라이베리아', 'Libéria', 'Libéria', 'Liberia', 'Liberija', 'لیبریا', 'Liberia', 'Liberia', 'Liberia', 'リベリア', 'Liberia', '利比里亚', 'Liberya', 'Либерия', 'Ліберія', 'Liberia'),
('LBY', 'LY', 'Libya', 'Libia', '리비아', 'Líbia', 'Líbia', 'Libië', 'Libija', 'لیبی', 'Libyen', 'Libia', 'Libye', 'リビア', 'Libia', '利比亚', 'Libya', 'Ливия', 'Лівія', 'Libia'),
('LIE', 'LI', 'Liechtenstein', 'Liechtenstein', '리히텐슈타인', 'Liechtenstein', 'Listenstaine', 'Liechtenstein', 'Lihtenštajn', 'لیختن‌اشتاین', 'Liechtenstein', 'Liechtenstein', 'Liechtenstein', 'リヒテンシュタイン', 'Liechtenstein', '列支敦士登', 'Lihtenştayn', 'Лихтенштейн', 'Ліхтенштейн', 'Liechtenstein'),
('LTU', 'LT', 'Lithuania', 'Lituania', '리투아니아', 'Lituânia', 'Lituânia', 'Litouwen', 'Litva', 'لیتوانی', 'Litauen', 'Lituania', 'Lituanie', 'リトアニア', 'Lituania', '立陶宛', 'Litvanya', 'Литва', 'Литва', 'Litwa'),
('LUX', 'LU', 'Luxembourg', 'Luksembourg', '룩셈부르크', 'Luxemburgo', 'Luxemburgo', 'Luxemburg', 'Luksemburg', 'لوکزامبورگ', 'Luxemburg', 'Luxemburgo', 'Luxembourg', 'ルクセンブルク', 'Lussemburgo', '卢森堡', 'Lüksemburg', 'Люксембург', 'Люксембург', 'Luksemburg'),
('MAC', 'MO', 'Macau S.A.R.', 'Makao', '마카오', 'Macau', 'Macau', 'Macao', 'Makao', 'مکائو', 'Macao', 'Macao', 'Macao', 'マカオ', 'Macao', '中国澳门', 'Makao', 'Макао С.А.Р.', 'САР Макао.', 'Macau S.A.R.'),
('MDG', 'MG', 'Madagascar', 'Madagaskar', '마다가스카르', 'Madagascar', 'Madagáscar', 'Madagaskar', 'Madagaskar', 'ماداگاسکار', 'Madagaskar', 'Madagascar', 'Madagascar', 'マダガスカル', 'Madagascar', '马达加斯加', 'Madagaskar', 'Мадагаскар', 'Мадагаскар', 'Madagaskar'),
('MWI', 'MW', 'Malawi', 'Malawi', '말라위', 'Malawi', 'Malávi', 'Malawi', 'Malavi', 'مالاوی', 'Malawi', 'Malawi', 'Malawi', 'マラウイ', 'Malawi', '马拉维', 'Malavi', 'Малави', 'Малаві', 'Malawi'),
('MYS', 'MY', 'Malaysia', 'Malaysia', '말레이시아', 'Malásia', 'Malásia', 'Maleisië', 'Malezija', 'مالزی', 'Malaysia', 'Malasia', 'Malaisie', 'マレーシア', 'Malesia', '马来西亚', 'Malezya', 'Малайзия', 'Малайзія', 'Malezja'),
('MDV', 'MV', 'Maldives', 'Maldivez', '몰디브', 'Maldivas', 'Maldivas', 'Maldiven', 'Maldivi', 'مالدیو', 'Malediven', 'Maldivas', 'Maldives', 'モルディブ', 'Maldive', '马尔代夫', 'Maldivler', 'Мальдивы', 'Мальдіви', 'Malediwy'),
('MLI', 'ML', 'Mali', 'Mali', '말리', 'Mali', 'Mali', 'Mali', 'Mali', 'مالی', 'Mali', 'Mali', 'Mali', 'マリ', 'Mali', '马里', 'Mali', 'Мали', 'Малі', 'Mali'),
('MLT', 'MT', 'Malta', 'Malta', '몰타', 'Malta', 'Malta', 'Malta', 'Malta', 'مالت', 'Malta', 'Malta', 'Malte', 'マルタ', 'Malta', '马耳他', 'Malta', 'Мальта', 'Мальта', 'Malta'),
('IMN', 'IM', 'Man (Isle of)', 'Manav', '맨 섬', 'Ilha de Man', 'Ilha de Man', 'Isle of Man', 'Otok Man', 'جزیره من', 'Insel Man', 'Isla de Man', 'Île de Man', 'マン島', 'Isola di Man', '马恩岛', 'Man Adasi', 'Мэн (остров)', 'Мен (острів Мен)', 'Man (Wyspa)'),
('MHL', 'MH', 'Marshall Islands', 'Inizi Marshall', '마셜 제도', 'Ilhas Marshall', 'Ilhas Marshall', 'Marshalleilanden', 'Maršalovi Otoci', 'جزایر مارشال', 'Marshallinseln', 'Islas Marshall', 'Îles Marshall', 'マーシャル諸島', 'Isole Marshall', '马绍尔群岛', 'Marşal Adalari', 'Маршалловы острова', 'Маршаллові острови', 'Wyspy Marshalla'),
('MTQ', 'MQ', 'Martinique', 'Martinik', '마르티니크', 'Martinica', 'Martinica', 'Martinique', 'Martinique', 'مونتسرات', 'Martinique', 'Martinica', 'Martinique', 'マルティニーク', 'Martinica', '马提尼克岛', 'Martinik', 'Мартиника', 'Мартініка', 'Martynika'),
('MRT', 'MR', 'Mauritania', 'Maouritania', '모리타니', 'Mauritânia', 'Mauritânia', 'Mauritanië', 'Mauritanija', 'موریتانی', 'Mauretanien', 'Mauritania', 'Mauritanie', 'モーリタニア', 'Mauritania', '毛里塔尼亚', 'Moritanya', 'Мавритания', 'Мавританія', 'Mauretania'),
('MUS', 'MU', 'Mauritius', 'Moris', '모리셔스', 'Maurício', 'Maurícia', 'Mauritius', 'Mauricijus', 'موریس', 'Mauritius', 'Mauricio', 'Île Maurice', 'モーリシャス', 'Mauritius', '毛里求斯', 'Morityus', 'Маврикий', 'Маврикій', 'Mauritius'),
('MYT', 'YT', 'Mayotte', 'Mayotte', '마요트', 'Mayotte', 'Mayotte', 'Mayotte', 'Mayotte', 'مایوت', 'Mayotte', 'Mayotte', 'Mayotte', 'マヨット', 'Mayotte', '马约特', 'Mayotte', 'Майотта', 'Майотта', 'Majotta'),
('MEX', 'MX', 'Mexico', NULL, '멕시코', 'México', 'México', 'Mexico', 'Meksiko', 'مکزیک', 'Mexibr', 'México', 'Mexique', 'メキシコ', 'Messico', '墨西哥', 'Meksika', 'Мексика', 'Мексика', 'Meksyk'),
('FSM', 'FM', 'Micronesia', 'Mikronezia', '미크로네시아 연방', 'Micronésia', 'Micronésia', 'Micronesië', 'Mikronezija', 'ایالات فدرال میکرونزی', 'Mikronesien', 'Micronesia', 'Micronésie', 'ミクロネシア連邦', 'Micronesia', '密克罗尼西亚', 'Mikronezya', 'Микронезия', 'Мікронезія', 'Mikronezja'),
('MDA', 'MD', 'Moldova', 'Moldova', '몰도바', 'Moldávia', 'Moldávia', 'Moldavië', 'Moldova', 'مولداوی', 'Moldawie', 'Moldavia', 'Moldavie', 'モルドバ共和国', 'Moldavia', '摩尔多瓦', 'Moldova', 'Молдова', 'Молдова', 'Mołdawia'),
('MCO', 'MC', 'Monaco', NULL, '모나코', 'Mônaco', 'Mónaco', 'Monaco', 'Monako', 'موناکو', 'Monaco', 'Mónaco', 'Monaco', 'モナコ', 'Principato di Monaco', '摩纳哥', 'Monako', 'Монако', 'Монако', 'Monabr'),
('MNG', 'MN', 'Mongolia', 'Mongolia', '몽골', 'Mongólia', 'Mongólia', 'Mongolië', 'Mongolija', 'مغولستان', 'Mongolei', 'Mongolia', 'Mongolie', 'モンゴル', 'Mongolia', '蒙古', 'Moğolistan', 'Монголия', 'Монголія', 'Mongolia'),
('MNE', 'ME', 'Montenegro', 'Montenegro', '몬테네그로', 'Montenegro', 'Montenegro', 'Montenegro', 'Crna Gora', 'مونته‌نگرو', 'Montenegro', 'Montenegro', 'Monténégro', 'モンテネグロ', 'Montenegro', '黑山', 'Karadağ', 'Черногория', 'Чорногорія', 'Czarnogóra'),
('MSR', 'MS', 'Montserrat', 'Montserrat', '몬트세랫', 'Montserrat', 'Monserrate', 'Montserrat', 'Montserrat', 'مایوت', 'Montserrat', 'Montserrat', 'Montserrat', 'モントセラト', 'Montserrat', '蒙特塞拉特', 'Montserrat', 'Монтсеррат', 'Монтсеррат', 'Montserrat'),
('MAR', 'MA', 'Morocco', NULL, '모로코', 'Marrocos', 'Marrocos', 'Marokko', 'Maroko', 'مراکش', 'Marokko', 'Marruecos', 'Maroc', 'モロッコ', 'Marocco', '摩洛哥', 'Fas', 'Марокко', 'Марокко', 'Maroko'),
('MOZ', 'MZ', 'Mozambique', 'Mozambik', '모잠비크', 'Moçambique', 'Moçambique', 'Mozambique', 'Mozambik', 'موزامبیک', 'Mosambik', 'Mozambique', 'Mozambique', 'モザンビーク', 'Mozambico', '莫桑比克', 'Mozambik', 'Мозамбик', 'Мозамбік', 'Mozambik'),
('MMR', 'MM', 'Myanmar', 'Myanmar', '미얀마', 'Myanmar', 'Myanmar', 'Myanmar', 'Mijanmar', 'میانمار', 'Myanmar', 'Myanmar', 'Myanmar', 'ミャンマー', 'Birmania', '缅甸', 'Myanmar', 'Мьянма', 'М''янма', 'Birma'),
('NAM', 'NA', 'Namibia', 'Namibia', '나미비아', 'Namíbia', 'Namíbia', 'Namibië', 'Namibija', 'نامیبیا', 'Namibia', 'Namibia', 'Namibie', 'ナミビア', 'Namibia', '纳米比亚', 'Namibya', 'Намибия', 'Намібія', 'Namibia'),
('NRU', 'NR', 'Nauru', 'Nauru', '나우루', 'Nauru', 'Nauru', 'Nauru', 'Nauru', 'نائورو', 'Nauru', 'Nauru', 'Nauru', 'ナウル', 'Nauru', '瑙鲁', 'Nauru', 'Науру', 'Науру', 'Nauru'),
('NPL', 'NP', 'Nepal', 'Nepal', '네팔', 'Nepal', 'Nepal', 'Nepal', 'Nepal', 'نپال', 'Népal', 'Nepal', 'Népal', 'ネパール', 'Nepal', '尼泊尔', 'Nepal', 'Непал', 'Непал', 'Nepal'),
('NLD', 'NL', 'Netherlands', 'Izelvroioù', '네덜란드 ', 'Holanda', 'Países Baixos', 'Nederland', 'Nizozemska', 'پادشاهی هلند', 'Niederlande', 'Países Bajos', 'Pays-Bas', 'オランダ', 'Paesi Bassi', '荷兰', 'Hollanda', 'Нидерланды', 'Нідерланди', 'Holandia'),
('NCL', 'NC', 'New Caledonia', 'Kaledonia-Nevez', '누벨칼레도니', 'Nova Caledônia', 'Nova Caledónia', 'Nieuw-Caledonië', 'Nova Kaledonija', 'کالدونیای جدید', 'Neukaledonien', 'Nueva Caledonia', 'Nouvelle-Calédonie', 'ニューカレドニア', 'Nuova Caledonia', '新喀里多尼亚', 'Yeni Kaledonya', 'Новая Каледония', 'Нова Каледонія', 'Nowa Kaledonia'),
('NZL', 'NZ', 'New Zealand', 'Zeland-Nevez', '뉴질랜드', 'Nova Zelândia', 'Nova Zelândia', 'Nieuw-Zeeland', 'Novi Zeland', 'نیوزیلند', 'Neuseeland', 'Nueva Zelanda', 'Nouvelle-Zélande', 'ニュージーランド', 'Nuova Zelanda', '新西兰', 'Yeni Zelanda', 'Новая Зеландия', 'Нова Зеландія', 'Nowa Zelandia'),
('NIC', 'NI', 'Nicaragua', 'Nicaragua', '니카라과', 'Nicarágua', 'Nicarágua', 'Nicaragua', 'Nikaragva', 'نیکاراگوئه', 'Nicaragua', 'Nicaragua', 'Nicaragua', 'ニカラグア', 'Nicaragua', '尼加拉瓜', 'Nikaragua', 'Никарагуа', 'Нікарагуа', 'Nikaragua'),
('NER', 'NE', 'Niger', 'Niger', '니제르', 'Níger', 'Níger', 'Niger', 'Niger', 'نیجر', 'Niger', 'Níger', 'Niger', 'ニジェール', 'Niger', '尼日尔', 'Nijer', 'Нигер', 'Нігер', 'Niger'),
('NGA', 'NG', 'Nigeria', 'Nigeria', '나이지리아', 'Nigéria', 'Nigéria', 'Nigeria', 'Nigerija', 'نیجریه', 'Nigeria', 'Nigeria', 'Nigéria', 'ナイジェリア', 'Nigeria', '尼日利亚', 'Nijerya', 'Нигерия', 'Нігерія', 'Nigeria'),
('NIU', 'NU', 'Niue', 'Niue', '니우에', 'Niue', 'Niue', 'Niue', 'Niue', 'نیووی', 'Niue', 'Niue', 'Niue', 'ニウエ', 'Niue', '纽埃', 'Niue', 'Ниуэ', 'Ніуе', 'Niue'),
('NFK', 'NF', 'Norfolk Island', 'Enez Norfolk', '노퍽 섬', 'Ilha Norfolk', 'Ilha Norfolk', 'Norfolkeiland', 'Otok Norfolk', 'جزیره نورفک', 'Norfolkinsel', 'Isla de Norfolk', 'Île de Norfolk', 'ノーフォーク島', 'Isola Norfolk', '诺福克岛', 'Norfolk Adasi', 'Остров Норфолк', 'Острів Норфолк', 'Wyspa Norfolk'),
('PRK', 'KP', 'North Korea', 'Korea an Norzh', '조선민주주의인민공화국', 'Coreia do Norte', 'Coreia do Norte', 'Noord-Korea', 'Sjeverna Koreja', 'کره جنوبی', 'Nordkorea', 'Corea del Norte', 'Corée du Nord', '朝鮮民主主義人民共和国', 'Corea del Nord', '朝鲜', 'Kuzey Kore', 'Северная Корея', 'Північна Корея', 'Korea Północna'),
('MKD', 'MK', 'North Macedonia', 'Makedonia an Norzh', '북마케도니아', 'Macedônia do Norte', 'Macedónia do Norte', 'Noord-Macedonië', 'Sjeverna Makedonija', 'ﻢﻗﺩﻮﻨﯿﻫ ﺶﻣﺎﻠﯾ', 'Nordmazedonien', 'Macedonia del Norte', 'Macédoine du Nord', '北マケドニア', 'Macedonia del Nord', '北馬其頓', 'Kuzey Makedonya', 'Северная Македония', 'Північна Македонія', 'Macedonia Północna'),
('MNP', 'MP', 'Northern Mariana Islands', 'Mariana an Norzh', '북마리아나 제도', 'Ilhas Marianas', 'Ilhas Marianas', 'Noordelijke Marianeneilanden', 'Sjevernomarijanski otoci', 'جزایر ماریانای شمالی', 'Nördliche Marianen', 'Islas Marianas del Norte', 'Îles Mariannes du Nord', '北マリアナ諸島', 'Isole Marianne Settentrionali', '北马里亚纳群岛', 'Kuzey Mariana Adalari', 'Северные Марианские острова', 'Північні Маріанські острови', 'Mariany Północne'),
('NOR', 'NO', 'Norway', 'Norvegia', '노르웨이', 'Noruega', 'Noruega', 'Noorwegen', 'Norveška', 'نروژ', 'Norwegen', 'Noruega', 'Norvège', 'ノルウェー', 'Norvegia', '挪威', 'Norveç', 'Норвегия', 'Норвегія', 'Norwegia'),
('OMN', 'OM', 'Oman', 'Oman', '오만', 'Omã', 'Omã', 'Oman', 'Oman', 'عمان', 'Oman', 'Omán', 'Oman', 'オマーン', 'oman', '阿曼', 'Umman', 'Оман', 'Оман', 'Oman'),
('PAK', 'PK', 'Pakistan', 'Pakistan', '파키스탄', 'Paquistão', 'Paquistão', 'Pakistan', 'Pakistan', 'پاکستان', 'Pakistan', 'Pakistán', 'Pakistan', 'パキスタン', 'Pakistan', '巴基斯坦', 'Pakistan', 'Пакистан', 'Пакистан', 'Pakistan'),
('PLW', 'PW', 'Palau', 'Palau', '팔라우', 'Palau', 'Palau', 'Palau', 'Palau', 'پالائو', 'Palau', 'Palau', 'Palaos', 'パラオ', 'Palau', '帕劳', 'Palau', 'Палау', 'Палау', 'Palau'),
('PSE', 'PS', 'Palestinian Territory Occupied', 'Palestina', '팔레스타인 영토', 'Palestina', 'Palestina', 'Palestijnse gebieden', 'Palestina', 'فلسطین', 'Palästina', 'Palestina', 'Palestine', 'パレスチナ', 'Palestina', '巴勒斯坦', 'Filistin', 'Оккупированная палестинская территория', 'Окупована палестинська територія', 'Okupowane terytorium palestyńskie'),
('PAN', 'PA', 'Panama', 'Panamá', '파나마', 'Panamá', 'Panamá', 'Panama', 'Panama', 'پاناما', 'Panama', 'Panamá', 'Panama', 'パナマ', 'Panama', '巴拿马', 'Panama', 'Панама', 'Панама', 'Panama'),
('PNG', 'PG', 'Papua New Guinea', 'Papoua Ginea-Nevez', '파푸아뉴기니', 'Papua Nova Guiné', 'Papua Nova Guiné', 'Papoea-Nieuw-Guinea', 'Papua Nova Gvineja', 'پاپوآ گینه نو', 'Papua-Neuguinea', 'Papúa Nueva Guinea', 'Papouasie-Nouvelle-Guinée', 'パプアニューギニア', 'Papua Nuova Guinea', '巴布亚新几内亚', 'Papua Yeni Gine', 'Папуа - Новая Гвинея', 'Папуа-Нова Гвінея', 'Papua-Nowa Gwinea'),
('PRY', 'PY', 'Paraguay', 'Paraguay', '파라과이', 'Paraguai', 'Paraguai', 'Paraguay', 'Paragvaj', 'پاراگوئه', 'Paraguay', 'Paraguay', 'Paraguay', 'パラグアイ', 'Paraguay', '巴拉圭', 'Paraguay', 'Парагвай', 'Парагвай', 'Paragwaj'),
('PER', 'PE', 'Peru', 'Perou', '페루', 'Peru', 'Peru', 'Peru', 'Peru', 'پرو', 'Peru', 'Perú', 'Pérou', 'ペルー', 'Perù', '秘鲁', 'Peru', 'Перу', 'Перу', 'Peru'),
('PHL', 'PH', 'Philippines', 'Filipinez', '필리핀', 'Filipinas', 'Filipinas', 'Filipijnen', 'Filipini', 'جزایر الندفیلیپین', 'Philippinen', 'Filipinas', 'Philippines', 'フィリピン', 'Filippine', '菲律宾', 'Filipinler', 'Филиппины', 'Філіппіни', 'Filipiny'),
('PCN', 'PN', 'Pitcairn Island', 'Inizi Pitcairn', '핏케언 제도', 'Ilhas Pitcairn', 'Ilhas Picárnia', 'Pitcairneilanden', 'Pitcairnovo otočje', 'پیتکرن', 'Pitcairn', 'Islas Pitcairn', 'Îles Pitcairn', 'ピトケアン', 'Isole Pitcairn', '皮特凯恩群岛', 'Pitcairn Adalari', 'Остров Питкэрн', 'Острів Піткерн', 'Wyspa Pitcairn'),
('POL', 'PL', 'Poland', 'Polonia', '폴란드', 'Polônia', 'Polónia', 'Polen', 'Poljska', 'لهستان', 'Polen', 'Polonia', 'Pologne', 'ポーランド', 'Polonia', '波兰', 'Polonya', 'Польша', 'Польща', 'Polska'),
('PRT', 'PT', 'Portugal', 'Portugal', '포르투갈', 'Portugal', 'Portugal', 'Portugal', 'Portugal', 'پرتغال', 'Portugal', 'Portugal', 'Portugal', 'ポルトガル', 'Portogallo', '葡萄牙', 'Portekiz', 'Португалия', 'Португалія', 'Portugalia'),
('PRI', 'PR', 'Puerto Rico', NULL, '푸에르토리코', 'Porto Rico', 'Porto Rico', 'Puerto Rico', 'Portoriko', 'پورتو ریکو', 'Puerto Rico', 'Puerto Rico', 'Porto Rico', 'プエルトリコ', 'Porto Rico', '波多黎各', 'Porto Riko', 'Пуэрто-Рико', 'Пуерто-Ріко', 'Puerto Rico'),
('QAT', 'QA', 'Qatar', 'Qatar', '카타르', 'Catar', 'Catar', 'Qatar', 'Katar', 'قطر', 'Katar', 'Catar', 'Qatar', 'カタール', 'Qatar', '卡塔尔', 'Katar', 'Катар', 'Катар', 'Katar'),
('REU', 'RE', 'Reunion', 'Reünion', '레위니옹', 'Reunião', 'Reunião', 'Réunion', 'Réunion', 'رئونیون', 'Réunion', 'Reunión', 'Réunion', 'レユニオン', 'Riunione', '留尼汪岛', 'Réunion', 'Воссоединение', 'Возз''єднання', 'Reunion'),
('ROU', 'RO', 'Romania', 'Roumania', '루마니아', 'Romênia', 'Roménia', 'Roemenië', 'Rumunjska', 'رومانی', 'Rumänien', 'Rumania', 'Roumanie', 'ルーマニア', 'Romania', '罗马尼亚', 'Romanya', 'Румыния', 'Румунія', 'Rumunia'),
('RUS', 'RU', 'Russia', 'Rusia', '러시아', 'Rússia', 'Rússia', 'Rusland', 'Rusija', 'روسیه', 'Russland', 'Rusia', 'Russie', 'ロシア連邦', 'Russia', '俄罗斯联邦', 'Rusya', 'Россия', 'Росія', 'Rosja'),
('RWA', 'RW', 'Rwanda', 'Rwanda', '르완다', 'Ruanda', 'Ruanda', 'Rwanda', 'Ruanda', 'رواندا', 'Ruanda', 'Ruanda', 'Rwanda', 'ルワンダ', 'Ruanda', '卢旺达', 'Ruanda', 'Руанда', 'Руанда', 'Rwanda'),
('SHN', 'SH', 'Saint Helena', 'Saint Helena, Ascension ha Tristan da Cunha', '세인트헬레나', 'Santa Helena', 'Santa Helena', 'Sint-Helena', 'Sveta Helena', 'سنت هلنا، اسنشن و تریستان دا کونا', 'Sankt Helena', 'Santa Helena', 'Sainte-Hélène', 'セントヘレナ・アセンションおよびトリスタンダクーニャ', 'Sant''Elena', '圣赫勒拿', 'Saint Helena', 'Святая Елена', 'Свята Єлена', 'Święta Helena'),
('KNA', 'KN', 'Saint Kitts and Nevis', 'Saint Kitts ha Nevis', '세인트키츠 네비스', 'São Cristóvão e Neves', 'São Cristóvão e Neves', 'Saint Kitts en Nevis', 'Sveti Kristof i Nevis', 'سنت کیتس و نویس', 'St. Kitts und Nevis', 'San Cristóbal y Nieves', 'Saint-Christophe-et-Niévès', 'セントクリストファー・ネイビス', 'Saint Kitts e Nevis', '圣基茨和尼维斯', 'Saint Kitts Ve Nevis', 'Сент-Китс и Невис', 'Сент-Кітс і Невіс', 'Saint Kitts i Nevis'),
('LCA', 'LC', 'Saint Lucia', 'Santez-Lusia', '세인트루시아', 'Santa Lúcia', 'Santa Lúcia', 'Saint Lucia', 'Sveta Lucija', 'سنت لوسیا', 'Saint Lucia', 'Santa Lucía', 'Saint-Lucie', 'セントルシア', 'Santa Lucia', '圣卢西亚', 'Saint Lucia', 'Сент-Люсия', 'Сент-Люсія', 'Saint Lucia'),
('SPM', 'PM', 'Saint Pierre and Miquelon', 'Sant-Pêr-ha-Mikelon', '생피에르 미클롱', 'Saint-Pierre e Miquelon', 'São Pedro e Miquelon', 'Saint Pierre en Miquelon', 'Sveti Petar i Mikelon', 'سن پیر و میکلن', 'Saint-Pierre und Miquelon', 'San Pedro y Miquelón', 'Saint-Pierre-et-Miquelon', 'サンピエール島・ミクロン島', 'Saint-Pierre e Miquelon', '圣皮埃尔和密克隆', 'Saint Pierre Ve Miquelon', 'Сен-Пьер и Микелон', 'Сен-П''єр і Мікелон', 'Saint-Pierre i Miquelon'),
('VCT', 'VC', 'Saint Vincent and the Grenadines', 'Sant-Visant hag ar Grenadinez', '세인트빈센트 그레나딘', 'São Vicente e Granadinas', 'São Vicente e Granadinas', 'Saint Vincent en de Grenadines', 'Sveti Vincent i Grenadini', 'سنت وینسنت و گرنادین‌ها', 'Saint Vincent und die Grenadinen', 'San Vicente y Granadinas', 'Saint-Vincent-et-les-Grenadines', 'セントビンセントおよびグレナディーン諸島', 'Saint Vincent e Grenadine', '圣文森特和格林纳丁斯', 'Saint Vincent Ve Grenadinler', 'Сент-Винсент и Гренадины', 'Сент-Вінсент і Гренадини', 'Saint Vincent i Grenadyny'),
('BLM', 'BL', 'Saint-Barthelemy', 'Saint-Barthélemy', '생바르텔레미', 'São Bartolomeu', 'São Bartolomeu', 'Saint Barthélemy', 'Saint Barthélemy', 'سن-بارتلمی', 'Saint-Barthélemy', 'San Bartolomé', 'Saint-Barthélemy', 'サン・バルテルミー', 'Antille Francesi', '圣巴泰勒米', 'Saint Barthélemy', 'Сен-Бартелеми', 'Сен-Бартелемі', 'Saint-Barthelemy'),
('MAF', 'MF', 'Saint-Martin (French part)', 'Saint-Martin', '세인트마틴 섬', 'Saint Martin', 'Ilha São Martinho', 'Saint-Martin', 'Sveti Martin', 'سینت مارتن', 'Saint Martin', 'Saint Martin', 'Saint-Martin', 'サン・マルタン(フランス領)', 'Saint Martin', '密克罗尼西亚', 'Saint Martin', 'Сен-Мартен (французская часть)', 'Сен-Мартен (французька частина)', 'Saint-Martin (część francuska)'),
('WSM', 'WS', 'Samoa', 'Samoa', '사모아', 'Samoa', 'Samoa', 'Samoa', 'Samoa', 'ساموآ', 'Samoa', 'Samoa', 'Samoa', 'サモア', 'Samoa', '萨摩亚', 'Samoa', 'Самоа', 'Самоа', 'Samoa'),
('SMR', 'SM', 'San Marino', 'San Marino', '산마리노', 'San Marino', 'São Marinho', 'San Marino', 'San Marino', 'سان مارینو', 'San Marino', 'San Marino', 'Saint-Marin', 'サンマリノ', 'San Marino', '圣马力诺', 'San Marino', 'Сан-Марино', 'Сан-Марино', 'San Marino'),
('STP', 'ST', 'Sao Tome and Principe', 'São Tomé ha Príncipe', '상투메 프린시페', 'São Tomé e Príncipe', 'São Tomé e Príncipe', 'Sao Tomé en Principe', 'Sveti Toma i Princip', 'کواترو دو فرویرو', 'São Tomé und Príncipe', 'Santo Tomé y Príncipe', 'Sao Tomé-et-Principe', 'サントメ・プリンシペ', 'São Tomé e Príncipe', '圣多美和普林西比', 'Sao Tome Ve Prinsipe', 'Сан-Томе и Принсипи', 'Сан-Томе і Принсіпі', 'Wyspy Świętego Tomasza i Książęca'),
('SAU', 'SA', 'Saudi Arabia', 'Arabia Saoudat', '사우디아라비아', 'Arábia Saudita', 'Arábia Saudita', 'Saoedi-Arabië', 'Saudijska Arabija', 'عربستان سعودی', 'Saudi-Arabien', 'Arabia Saudí', 'Arabie Saoudite', 'サウジアラビア', 'Arabia Saudita', '沙特阿拉伯', 'Suudi Arabistan', 'Саудовская Аравия', 'Саудівська Аравія', 'Arabia Saudyjska'),
('SEN', 'SN', 'Senegal', 'Senegal', '세네갈', 'Senegal', 'Senegal', 'Senegal', 'Senegal', 'سنگال', 'Senegal', 'Senegal', 'Sénégal', 'セネガル', 'Senegal', '塞内加尔', 'Senegal', 'Сенегал', 'Сенегал', 'Senegal'),
('SRB', 'RS', 'Serbia', 'Serbia', '세르비아', 'Sérvia', 'Sérvia', 'Servië', 'Srbija', 'صربستان', 'Serbien', 'Serbia', 'Serbie', 'セルビア', 'Serbia', '塞尔维亚', 'Sirbistan', 'Сербия', 'Сербія', 'Serbia'),
('SYC', 'SC', 'Seychelles', 'Sechelez', '세이셸', 'Seicheles', 'Seicheles', 'Seychellen', 'Sejšeli', 'سیشل', 'Seychellen', 'Seychelles', 'Seychelles', 'セーシェル', 'Seychelles', '塞舌尔', 'Seyşeller', 'Сейшельские острова', 'Сейшельські острови', 'Seszele'),
('SLE', 'SL', 'Sierra Leone', 'Sierra Leone', '시에라리온', 'Serra Leoa', 'Serra Leoa', 'Sierra Leone', 'Sijera Leone', 'سیرالئون', 'Sierra Leone', 'Sierra Leone', 'Sierra Leone', 'シエラレオネ', 'Sierra Leone', '塞拉利昂', 'Sierra Leone', 'Сьерра-Леоне', 'Сьєрра-Леоне', 'Sierra Leone'),
('SGP', 'SG', 'Singapore', 'Singapour', '싱가포르', 'Singapura', 'Singapura', 'Singapore', 'Singapur', 'سنگاپور', 'Singapur', 'Singapur', 'Singapour', 'シンガポール', 'Singapore', '新加坡', 'Singapur', 'Сингапур', 'Сінгапур', 'Singapur'),
('SXM', 'SX', 'Sint Maarten (Dutch part)', 'Sint Maarten', '신트마르턴', 'Sint Maarten', 'São Martinho', 'Sint Maarten', NULL, 'سینت مارتن', 'Sint Maarten (niederl. Teil)', NULL, 'Saint Martin (partie néerlandaise)', NULL, 'Saint Martin (parte olandese)', '圣马丁岛(荷兰部分)', 'Sint Maarten', 'Синт-Мартен (голландская часть)', 'Сінт-Мартен (голландська частина)', 'Sint Maarten (część niderlandzka)'),
('SVK', 'SK', 'Slovakia', 'Slovakia', '슬로바키아', 'Eslováquia', 'Eslováquia', 'Slowakije', 'Slovačka', 'اسلواکی', 'Slowakei', 'República Eslovaca', 'Slovaquie', 'スロバキア', 'Slovacchia', '斯洛伐克', 'Slovakya', 'Словакия', 'Словаччина', 'Słowacja'),
('SVN', 'SI', 'Slovenia', 'Slovenia', '슬로베니아', 'Eslovênia', 'Eslovénia', 'Slovenië', 'Slovenija', 'اسلوونی', 'Slowenien', 'Eslovenia', 'Slovénie', 'スロベニア', 'Slovenia', '斯洛文尼亚', 'Slovenya', 'Словения', 'Словенія', 'Słowenia'),
('SLB', 'SB', 'Solomon Islands', 'Inizi Salomon', '솔로몬 제도', 'Ilhas Salomão', 'Ilhas Salomão', 'Salomonseilanden', 'Solomonski Otoci', 'جزایر سلیمان', 'Salomonen', 'Islas Salomón', 'Îles Salomon', 'ソロモン諸島', 'Isole Salomone', '所罗门群岛', 'Solomon Adalari', 'Соломоновы острова', 'Соломонові острови', 'Wyspy Salomona'),
('SOM', 'SO', 'Somalia', 'Somalia', '소말리아', 'Somália', 'Somália', 'Somalië', 'Somalija', 'سومالی', 'Somalia', 'Somalia', 'Somalie', 'ソマリア', 'Somalia', '索马里', 'Somali', 'Сомали', 'Сомалі', 'Somalia'),
('ZAF', 'ZA', 'South Africa', 'Suafrika', '남아프리카 공화국', 'República Sul-Africana', 'República Sul-Africana', 'Zuid-Afrika', 'Južnoafrička Republika', 'آفریقای جنوبی', 'Republik Südafrika', 'República de Sudáfrica', 'Afrique du Sud', '南アフリカ', 'Sud Africa', '南非', 'Güney Afrika Cumhuriyeti', 'Южная Африка', 'Південна Африка', 'Republika Południowej Afryki'),
('SGS', 'GS', 'South Georgia', 'Georgia ar Su hag Inizi Sandwich ar Su', '사우스조지아', 'Ilhas Geórgias do Sul e Sandwich do Sul', 'Ilhas Geórgia do Sul e Sanduíche do Sul', 'Zuid-Georgia en Zuidelijke Sandwicheilanden', 'Južna Georgija i otočje Južni Sandwich', 'جزایر جورجیای جنوبی و ساندویچ جنوبی', 'Südgeorgien und die Südlichen Sandwichinseln', 'Islas Georgias del Sur y Sandwich del Sur', 'Géorgie du Sud-et-les Îles Sandwich du Sud', 'サウスジョージア・サウスサンドウィッチ諸島', 'Georgia del Sud e Isole Sandwich Meridionali', '南乔治亚', 'Güney Georgia', 'Южная Джорджия', 'Південна Джорджія', 'Południowa Georgia'),
('KOR', 'KR', 'South Korea', 'Republik Korea', '대한민국', 'Coreia do Sul', 'Coreia do Sul', 'Zuid-Korea', 'Južna Koreja', 'کره شمالی', 'Südkorea', 'Corea del Sur', 'Corée du Sud', '大韓民国', 'Corea del Sud', '韩国', 'Güney Kore', 'Южная Корея', 'Південна Корея', 'Korea Południowa'),
('SSD', 'SS', 'South Sudan', 'Soudan ar Su', '남수단', 'Sudão do Sul', 'Sudão do Sul', 'Zuid-Soedan', 'Južni Sudan', 'سودان جنوبی', 'Südsudan', 'Sudán del Sur', 'Soudan du Sud', '南スーダン', 'Sudan del sud', '南苏丹', 'Güney Sudan', 'Южный Судан', 'Південний Судан', 'Sudan Południowy'),
('ESP', 'ES', 'Spain', 'Spagn', '스페인', 'Espanha', 'Espanha', 'Spanje', 'Španjolska', 'اسپانیا', 'Spanien', 'España', 'Espagne', 'スペイン', 'Spagna', '西班牙', 'İspanya', 'Испания', 'Іспанія', 'Hiszpania'),
('LKA', 'LK', 'Sri Lanka', 'Sri Lanka', '스리랑카', 'Sri Lanka', 'Sri Lanka', 'Sri Lanka', 'Šri Lanka', 'سری‌لانکا', 'Sri Lanka', 'Sri Lanka', 'Sri Lanka', 'スリランカ', 'Sri Lanka', '斯里兰卡', 'Sri Lanka', 'Шри-Ланка', 'Шрі-Ланка', 'Sri Lanka'),
('SDN', 'SD', 'Sudan', 'Soudan', '수단', 'Sudão', 'Sudão', 'Soedan', 'Sudan', 'سودان', 'Sudan', 'Sudán', 'Soudan', 'スーダン', 'Sudan', '苏丹', 'Sudan', 'Судан', 'Судан', 'Sudan'),
('SUR', 'SR', 'Suriname', 'Surinam', '수리남', 'Suriname', 'Suriname', 'Suriname', 'Surinam', 'سورینام', 'Suriname', 'Surinam', 'Surinam', 'スリナム', 'Suriname', '苏里南', 'Surinam', 'Суринам', 'Суринам', 'Surinam'),
('SJM', 'SJ', 'Svalbard and Jan Mayen Islands', 'Svalbard ha Enez Jan Mayen', '스발바르 얀마옌 제도', 'Svalbard', 'Svalbard', 'Svalbard en Jan Mayen', 'Svalbard i Jan Mayen', 'سوالبارد و یان ماین', 'Svalbard und Jan Mayen', 'Islas Svalbard y Jan Mayen', 'Svalbard et Jan Mayen', 'スヴァールバル諸島およびヤンマイエン島', 'Svalbard e Jan Mayen', '斯瓦尔巴和扬马延群岛', 'Svalbard Ve Jan Mayen', 'Шпицберген и острова Ян-Майен', 'Шпіцберген та острови Ян-Майєн', 'Wyspy Svalbard i Jan Mayen'),
('SWE', 'SE', 'Sweden', 'Sveden', '스웨덴', 'Suécia', 'Suécia', 'Zweden', 'Švedska', 'سوئد', 'Schweden', 'Suecia', 'Suède', 'スウェーデン', 'Svezia', '瑞典', 'İsveç', 'Швеция', 'Швеція', 'Szwecja'),
('CHE', 'CH', 'Switzerland', 'Suis', '스위스', 'Suíça', 'Suíça', 'Zwitserland', 'Švicarska', 'سوئیس', 'Schweiz', 'Suiza', 'Suisse', 'スイス', 'Svizzera', '瑞士', 'İsviçre', 'Швейцария', 'Швейцарія', 'Szwajcaria'),
('SYR', 'SY', 'Syria', 'Siria', '시리아', 'Síria', 'Síria', 'Syrië', 'Sirija', 'سوریه', 'Syrien', 'Siria', 'Syrie', 'シリア・アラブ共和国', 'Siria', '叙利亚', 'Suriye', 'Сирия', 'Сирія', 'Syria'),
('TWN', 'TW', 'Taiwan', 'Taiwan', '대만', 'Taiwan', 'Taiwan', 'Taiwan', 'Tajvan', 'تایوان', 'Taiwan', 'Taiwán', 'Taïwan', '台湾(中華民国)', 'Taiwan', '中国台湾', 'Tayvan', 'Тайвань', 'Тайвань', 'Tajwan'),
('TJK', 'TJ', 'Tajikistan', 'Tadjikistan', '타지키스탄', 'Tajiquistão', 'Tajiquistão', 'Tadzjikistan', 'Tađikistan', 'تاجیکستان', 'Tadschikistan', 'Tayikistán', 'Tadjikistan', 'タジキスタン', 'Tagikistan', '塔吉克斯坦', 'Tacikistan', 'Таджикистан', 'Таджикистан', 'Tadżykistan'),
('TZA', 'TZ', 'Tanzania', 'Tanzania', '탄자니아', 'Tanzânia', 'Tanzânia', 'Tanzania', 'Tanzanija', 'تانزانیا', 'Tansania', 'Tanzania', 'Tanzanie', 'タンザニア', 'Tanzania', '坦桑尼亚', 'Tanzanya', 'Танзания', 'Танзанія', 'Tanzania'),
('THA', 'TH', 'Thailand', 'Thailand', '태국', 'Tailândia', 'Tailândia', 'Thailand', 'Tajland', 'تایلند', 'Thailand', 'Tailandia', 'Thaïlande', 'タイ', 'Tailandia', '泰国', 'Tayland', 'Таиланд', 'Таїланд', 'Tajlandia'),
('BHS', 'BS', 'The Bahamas', 'Bahamas', '바하마', 'Bahamas', 'Baamas', 'Bahamas', 'Bahami', 'باهاما', 'Bahamas', 'Bahamas', 'Bahamas', 'バハマ', 'Bahamas', '巴哈马', 'Bahamalar', 'Багамы', 'Багамські острови', 'Bahamy'),
('GMB', 'GM', 'The Gambia', 'Gambia', '감비아', 'Gâmbia', 'Gâmbia', 'Gambia', 'Gambija', 'گامبیا', 'Gambia', 'Gambia', 'Gambie', 'ガンビア', 'Gambia', '冈比亚', 'Gambiya', 'Гамбия', 'Гамбія The', 'Gambia The'),
('TLS', 'TL', 'Timor-Leste', 'Timor ar Reter', '동티모르', 'Timor Leste', 'Timor Leste', 'Oost-Timor', 'Istočni Timor', 'تیمور شرقی', 'Timor-Leste', 'Timor Oriental', 'Timor oriental', '東ティモール', 'Timor Est', '东帝汶', 'Doğu Timor', 'Тимор-Лешти', 'Тимор-Лешті', 'Timor Wschodni'),
('TGO', 'TG', 'Togo', 'Togo', '토고', 'Togo', 'Togo', 'Togo', 'Togo', 'توگو', 'Togo', 'Togo', 'Togo', 'トーゴ', 'Togo', '多哥', 'Togo', 'Того', 'Того', 'Togo'),
('TKL', 'TK', 'Tokelau', 'Tokelau', '토켈라우', 'Tokelau', 'Toquelau', 'Tokelau', 'Tokelau', 'توکلائو', 'Tokelau', 'Islas Tokelau', 'Tokelau', 'トケラウ', 'Isole Tokelau', '托克劳', 'Tokelau', 'Токелау', 'Токелау', 'Tokelau'),
('TON', 'TO', 'Tonga', 'Tonga', '통가', 'Tonga', 'Tonga', 'Tonga', 'Tonga', 'تونگا', 'Tonga', 'Tonga', 'Tonga', 'トンガ', 'Tonga', '汤加', 'Tonga', 'Тонга', 'Тонга', 'Tonga'),
('TTO', 'TT', 'Trinidad and Tobago', 'Trinidad ha Tobago', '트리니다드 토바고', 'Trinidad e Tobago', 'Trindade e Tobago', 'Trinidad en Tobago', 'Trinidad i Tobago', 'ترینیداد و توباگو', 'Trinidad und Tobago', 'Trinidad y Tobago', 'Trinité et Tobago', 'トリニダード・トバゴ', 'Trinidad e Tobago', '特立尼达和多巴哥', 'Trinidad Ve Tobago', 'Тринидад и Тобаго', 'Тринідад і Тобаго', 'Trynidad i Tobago'),
('TUN', 'TN', 'Tunisia', 'Tunizia', '튀니지', 'Tunísia', 'Tunísia', 'Tunesië', 'Tunis', 'تونس', 'Tunesien', 'Túnez', 'Tunisie', 'チュニジア', 'Tunisia', '突尼斯', 'Tunus', 'Тунис', 'Туніс', 'Tunezja'),
('TUR', 'TR', 'Turkey', 'Turkia', '터키', 'Turquia', 'Turquia', 'Turkije', 'Turska', 'ترکیه', 'Türkei', 'Turquía', 'Turquie', 'トルコ', 'Turchia', '土耳其', 'Türkiye', 'Турция', 'Туреччина', 'Turcja'),
('TKM', 'TM', 'Turkmenistan', 'Turkmenistan', '투르크메니스탄', 'Turcomenistão', 'Turquemenistão', 'Turkmenistan', 'Turkmenistan', 'ترکمنستان', 'Turkmenistan', 'Turkmenistán', 'Turkménistan', 'トルクメニスタン', 'Turkmenistan', '土库曼斯坦', 'Türkmenistan', 'Туркменистан', 'Туркменістан', 'Turkmenistan'),
('TCA', 'TC', 'Turks and Caicos Islands', 'Inizi Turks ha Caicos', '터크스 케이커스 제도', 'Ilhas Turcas e Caicos', 'Ilhas Turcas e Caicos', 'Turks- en Caicoseilanden', 'Otoci Turks i Caicos', 'جزایر تورکس و کایکوس', 'Turks- und Caicosinseln', 'Islas Turks y Caicos', 'Îles Turques-et-Caïques', 'タークス・カイコス諸島', 'Isole Turks e Caicos', '特克斯和凯科斯群岛', 'Turks Ve Caicos Adalari', 'Острова Теркс и Кайкос', 'Острови Теркс і Кайкос', 'Wyspy Turks i Caicos'),
('TUV', 'TV', 'Tuvalu', 'Tuvalu', '투발루', 'Tuvalu', 'Tuvalu', 'Tuvalu', 'Tuvalu', 'تووالو', 'Tuvalu', 'Tuvalu', 'Tuvalu', 'ツバル', 'Tuvalu', '图瓦卢', 'Tuvalu', 'Тувалу', 'Тувалу', 'Tuvalu'),
('UGA', 'UG', 'Uganda', 'Ouganda', '우간다', 'Uganda', 'Uganda', 'Oeganda', 'Uganda', 'اوگاندا', 'Uganda', 'Uganda', 'Uganda', 'ウガンダ', 'Uganda', '乌干达', 'Uganda', 'Уганда', 'Уганда', 'Uganda'),
('UKR', 'UA', 'Ukraine', 'Ukraina', '우크라이나', 'Ucrânia', 'Ucrânia', 'Oekraïne', 'Ukrajina', 'وکراین', 'Ukraine', 'Ucrania', 'Ukraine', 'ウクライナ', 'Ucraina', '乌克兰', 'Ukrayna', 'Украина', 'Україна', 'Ukraina'),
('ARE', 'AE', 'United Arab Emirates', 'Emirelezhioù Arab Unanet', '아랍에미리트', 'Emirados árabes Unidos', 'Emirados árabes Unidos', 'Verenigde Arabische Emiraten', 'Ujedinjeni Arapski Emirati', 'امارات متحده عربی', 'Vereinigte Arabische Emirate', 'Emiratos Árabes Unidos', 'Émirats arabes unis', 'アラブ首長国連邦', 'Emirati Arabi Uniti', '阿拉伯联合酋长国', 'Birleşik Arap Emirlikleri', 'Объединенные Арабские Эмираты', 'Об''єднані Арабські Емірати', 'Zjednoczone Emiraty Arabskie'),
('GBR', 'GB', 'United Kingdom', 'Rouantelezh-Unanet', '영국', 'Reino Unido', 'Reino Unido', 'Verenigd Koninkrijk', 'Ujedinjeno Kraljevstvo', 'بریتانیای کبیر و ایرلند شمالی', 'Vereinigtes Königreich', 'Reino Unido', 'Royaume-Uni', 'イギリス', 'Regno Unito', '英国', 'Birleşik Krallik', 'Великобритания', 'Сполучене Королівство', 'Wielka Brytania'),
('USA', 'US', 'United States', 'Stadoù-Unanet', '미국', 'Estados Unidos', 'Estados Unidos', 'Verenigde Staten', 'Sjedinjene Američke Države', 'ایالات متحده آمریکا', 'Vereinigte Staaten von Amerika', 'Estados Unidos', 'États-Unis', 'アメリカ合衆国', 'Stati Uniti D''America', '美国', 'Amerika', 'Соединенные Штаты', 'Сполучені Штати', 'Stany Zjednoczone'),
('UMI', 'UM', 'United States Minor Outlying Islands', 'Inizi Minor A-bell Stadoù-Unanet', '미국령 군소 제도', 'Ilhas Menores Distantes dos Estados Unidos', 'Ilhas Menores Distantes dos Estados Unidos', 'Kleine afgelegen eilanden van de Verenigde Staten', 'Mali udaljeni otoci SAD-a', 'جزایر کوچک حاشیه‌ای ایالات متحده آمریکا', 'Kleinere Inselbesitzungen der Vereinigten Staaten', 'Islas Ultramarinas Menores de Estados Unidos', 'Îles mineures éloignées des États-Unis', '合衆国領有小離島', 'Isole minori esterne degli Stati Uniti d''America', '美国本土外小岛屿', 'Abd Küçük Harici Adalari', 'Малые отдаленные острова Соединенных Штатов', 'Малі віддалені острови Сполучених Штатів', 'Mniejsze Wyspy Zewnętrzne Stanów Zjednoczonych'),
('URY', 'UY', 'Uruguay', 'Uruguay', '우루과이', 'Uruguai', 'Uruguai', 'Uruguay', 'Urugvaj', 'اروگوئه', 'Uruguay', 'Uruguay', 'Uruguay', 'ウルグアイ', 'Uruguay', '乌拉圭', 'Uruguay', 'Уругвай', 'Уругвай', 'Urugwaj'),
('UZB', 'UZ', 'Uzbekistan', 'Ouzbekistan', '우즈베키스탄', 'Uzbequistão', 'Usbequistão', 'Oezbekistan', 'Uzbekistan', 'ازبکستان', 'Usbekistan', 'Uzbekistán', 'Ouzbékistan', 'ウズベキスタン', 'Uzbekistan', '乌兹别克斯坦', 'Özbekistan', 'Узбекистан', 'Узбекистан', 'Uzbekistan'),
('VUT', 'VU', 'Vanuatu', 'Vanuatu', '바누아투', 'Vanuatu', 'Vanuatu', 'Vanuatu', 'Vanuatu', 'وانواتو', 'Vanuatu', 'Vanuatu', 'Vanuatu', 'バヌアツ', 'Vanuatu', '瓦努阿图', 'Vanuatu', 'Вануату', 'Вануату', 'Vanuatu'),
('VAT', 'VA', 'Vatican City State (Holy See)', 'Vatikan', '바티칸 시국', 'Vaticano', 'Vaticano', 'Heilige Stoel', 'Sveta Stolica', 'سریر مقدس', 'Heiliger Stuhl', 'Santa Sede', 'voir Saint', '聖座', 'Santa Sede', '梵蒂冈', 'Vatikan', 'Город-государство Ватикан (Святой Престол)', 'Держава-місто Ватикан (Святий Престол)', 'Państwo Watykańskie (Stolica Apostolska)'),
('VEN', 'VE', 'Venezuela', 'Venezuela', '베네수엘라', 'Venezuela', 'Venezuela', 'Venezuela', 'Venezuela', 'ونزوئلا', 'Venezuela', 'Venezuela', 'Venezuela', 'ベネズエラ・ボリバル共和国', 'Venezuela', '委内瑞拉', 'Venezuela', 'Венесуэла', 'Венесуела', 'Wenezuela'),
('VNM', 'VN', 'Vietnam', 'Viêt Nam', '베트남', 'Vietnã', 'Vietname', 'Vietnam', 'Vijetnam', 'ویتنام', 'Vietnam', 'Vietnam', 'Viêt Nam', 'ベトナム', 'Vietnam', '越南', 'Vietnam', 'Вьетнам', 'В''єтнам', 'Wietnam'),
('VGB', 'VG', 'Virgin Islands (British)', 'Inizi Gwerc''h Breizhveurat', '영국령 버진아일랜드', 'Ilhas Virgens Britânicas', 'Ilhas Virgens Britânicas', 'Britse Maagdeneilanden', 'Britanski Djevičanski Otoci', 'جزایر ویرجین بریتانیا', 'Britische Jungferninseln', 'Islas Vírgenes del Reino Unido', 'Îles Vierges britanniques', 'イギリス領ヴァージン諸島', 'Isole Vergini Britanniche', '圣文森特和格林纳丁斯', 'Britanya Virjin Adalari', 'Виргинские острова (Британские)', 'Віргінські острови (Британські)', 'Wyspy Dziewicze (Brytyjskie)'),
('VIR', 'VI', 'Virgin Islands (US)', 'Inizi Gwerc''h ar Stadoù-Unanet', '미국령 버진아일랜드', 'Ilhas Virgens Americanas', 'Ilhas Virgens Americanas', 'Verenigde Staten Maagdeneilanden', NULL, 'جزایر ویرجین آمریکا', 'Amerikanische Jungferninseln', 'Islas Vírgenes de los Estados Unidos', 'Îles Vierges des États-Unis', 'アメリカ領ヴァージン諸島', 'Isole Vergini americane', '维尔京群岛(美国)', 'Abd Virjin Adalari', 'Виргинские острова (США)', 'Віргінські острови (США)', 'Wyspy Dziewicze (USA)'),
('WLF', 'WF', 'Wallis and Futuna Islands', 'Wallis ha Futuna', '왈리스 푸투나', 'Wallis e Futuna', 'Wallis e Futuna', 'Wallis en Futuna', 'Wallis i Fortuna', 'والیس و فوتونا', 'Wallis und Futuna', 'Wallis y Futuna', 'Wallis-et-Futuna', 'ウォリス・フツナ', 'Wallis e Futuna', '瓦利斯群岛和富图纳群岛', 'Wallis Ve Futuna', 'Острова Уоллис и Футуна', 'Острови Уолліс і Футуна', 'Wyspy Wallis i Futuna'),
('ESH', 'EH', 'Western Sahara', 'Sahara ar C''hornôg', '서사하라', 'Saara Ocidental', 'Saara Ocidental', 'Westelijke Sahara', 'Zapadna Sahara', 'جمهوری دموکراتیک عربی صحرا', 'Westsahara', 'Sahara Occidental', 'Sahara Occidental', '西サハラ', 'Sahara Occidentale', '西撒哈拉', 'Bati Sahra', 'Западная Сахара', 'Західна Сахара', 'Sahara Zachodnia'),
('YEM', 'YE', 'Yemen', 'Yemen', '예멘', 'Iêmen', 'Iémen', 'Jemen', 'Jemen', 'یمن', 'Jemen', 'Yemen', 'Yémen', 'イエメン', 'Yemen', '也门', 'Yemen', 'Йемен', 'Ємен', 'Jemen'),
('ZMB', 'ZM', 'Zambia', 'Zambia', '잠비아', 'Zâmbia', 'Zâmbia', 'Zambia', 'Zambija', 'زامبیا', 'Sambia', 'Zambia', 'Zambie', 'ザンビア', 'Zambia', '赞比亚', 'Zambiya', 'Замбия', 'Замбія', 'Zambia'),
('ZWE', 'ZW', 'Zimbabwe', 'Zimbabwe', '짐바브웨', 'Zimbabwe', 'Zimbabué', 'Zimbabwe', 'Zimbabve', 'زیمباوه', 'Simbabwe', 'Zimbabue', 'Zimbabwe', 'ジンバブエ', 'Zimbabwe', '津巴布韦', 'Zimbabve', 'Зимбабве', 'Зімбабве', 'Zimbabwe');
-- Drop all candidate data
TRUNCATE TABLE app.candidate_document CASCADE;
TRUNCATE TABLE app.candidate CASCADE;
-- Alter the column to VARCHAR(3) and add foreign key constraint to countries table
ALTER TABLE app.candidate
ALTER COLUMN country_education TYPE VARCHAR(3);
-- Add foreign key constraint to reference countries.iso3
ALTER TABLE app.candidate
ADD CONSTRAINT fk_candidate_country
FOREIGN KEY (country_education)
REFERENCES app.countries(iso3);
-- Drop the old enum type
DROP TYPE app.country;

View File

@@ -0,0 +1,54 @@
-- Add ON DELETE CASCADE to all foreign key constraints referencing candidate_document
-- This allows deleting documents without violating foreign key constraints
-- Drop and recreate foreign key constraints with ON DELETE CASCADE
-- 1. candidate_education.source_document_id
ALTER TABLE app.candidate_education
DROP CONSTRAINT IF EXISTS candidate_education_source_document_id_fkey;
ALTER TABLE app.candidate_education
ADD CONSTRAINT candidate_education_source_document_id_fkey
FOREIGN KEY (source_document_id)
REFERENCES app.candidate_document(document_id)
ON DELETE CASCADE;
-- 2. candidate_transcript.source_document_id
ALTER TABLE app.candidate_transcript
DROP CONSTRAINT IF EXISTS candidate_transcript_source_document_id_fkey;
ALTER TABLE app.candidate_transcript
ADD CONSTRAINT candidate_transcript_source_document_id_fkey
FOREIGN KEY (source_document_id)
REFERENCES app.candidate_document(document_id)
ON DELETE CASCADE;
-- 3. candidate_license.source_document_id
ALTER TABLE app.candidate_license
DROP CONSTRAINT IF EXISTS candidate_license_source_document_id_fkey;
ALTER TABLE app.candidate_license
ADD CONSTRAINT candidate_license_source_document_id_fkey
FOREIGN KEY (source_document_id)
REFERENCES app.candidate_document(document_id)
ON DELETE CASCADE;
-- 4. candidate_language.source_document_id
ALTER TABLE app.candidate_language
DROP CONSTRAINT IF EXISTS candidate_language_source_document_id_fkey;
ALTER TABLE app.candidate_language
ADD CONSTRAINT candidate_language_source_document_id_fkey
FOREIGN KEY (source_document_id)
REFERENCES app.candidate_document(document_id)
ON DELETE CASCADE;
-- 5. candidate_experience.source_document_id
ALTER TABLE app.candidate_experience
DROP CONSTRAINT IF EXISTS candidate_experience_source_document_id_fkey;
ALTER TABLE app.candidate_experience
ADD CONSTRAINT candidate_experience_source_document_id_fkey
FOREIGN KEY (source_document_id)
REFERENCES app.candidate_document(document_id)
ON DELETE CASCADE;

View File

@@ -0,0 +1,2 @@
-- Add NONE to language_level enum at the beginning
ALTER TYPE app.language_level ADD VALUE 'NONE' BEFORE 'A_ONE';

View File

@@ -0,0 +1,67 @@
-- Add CASCADE to all foreign keys referencing candidate to allow candidate deletion
ALTER TABLE app.candidate_document
DROP CONSTRAINT candidate_document_candidate_id_fkey,
ADD CONSTRAINT candidate_document_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
ALTER TABLE app.candidate_education
DROP CONSTRAINT candidate_education_candidate_id_fkey,
ADD CONSTRAINT candidate_education_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
ALTER TABLE app.candidate_transcript
DROP CONSTRAINT candidate_transcript_candidate_id_fkey,
ADD CONSTRAINT candidate_transcript_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
ALTER TABLE app.candidate_license
DROP CONSTRAINT candidate_license_candidate_id_fkey,
ADD CONSTRAINT candidate_license_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
ALTER TABLE app.candidate_language
DROP CONSTRAINT candidate_language_candidate_id_fkey,
ADD CONSTRAINT candidate_language_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
ALTER TABLE app.candidate_experience
DROP CONSTRAINT candidate_experience_candidate_id_fkey,
ADD CONSTRAINT candidate_experience_candidate_id_fkey
FOREIGN KEY (candidate_id)
REFERENCES app.candidate(candidate_id)
ON DELETE CASCADE;
-- Delete duplicate emails, keeping only the first created occurrence
DELETE FROM app.candidate
WHERE candidate_id NOT IN (
SELECT candidate_id
FROM (
SELECT candidate_id,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at ASC) as rn
FROM app.candidate
WHERE email IS NOT NULL
) sub
WHERE rn = 1
);
-- Add email verification token to user table for double opt-in
ALTER TABLE app.user ADD COLUMN email_verification_token VARCHAR;
-- Remove magic_link_expiry since JWT handles expiry internally
ALTER TABLE app.user_auth DROP COLUMN magic_link_expiry;
-- Add unique constraint to candidate email to prevent duplicate registrations
ALTER TABLE app.candidate ADD CONSTRAINT candidate_email_unique UNIQUE (email);
-- Add field to track when incomplete process reminder was sent
ALTER TABLE app.candidate ADD COLUMN incomplete_reminder_sent_at TIMESTAMP;

View File

@@ -0,0 +1,3 @@
-- Remove obsolete access_token column from user_auth table
-- The system now uses JWT-based magic links for authentication instead
ALTER TABLE app.user_auth DROP COLUMN access_token;

View File

@@ -0,0 +1,6 @@
-- Add recognition_likelihood enum type
CREATE TYPE app.recognition_likelihood AS ENUM ('low', 'medium', 'high');
-- Add recognition_likelihood column to candidate table
ALTER TABLE app.candidate
ADD COLUMN recognition_likelihood app.recognition_likelihood;

View File

@@ -0,0 +1,21 @@
-- Create professional_recognition_status enum if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'professional_recognition_status') THEN
CREATE TYPE app.professional_recognition_status AS ENUM ('NOT_STARTED', 'IN_PROGRESS', 'COMPLETED');
END IF;
END $$;
-- Create language_code enum if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'language_code') THEN
CREATE TYPE app.language_code AS ENUM ('en', 'ar', 'bs', 'fil', 'hi', 'es', 'tr', 'uk', 'vi');
END IF;
END $$;
-- Add columns to candidate table for applicant profile
ALTER TABLE app.candidate
ADD COLUMN IF NOT EXISTS professional_recognition_status app.professional_recognition_status,
ADD COLUMN IF NOT EXISTS nationality VARCHAR,
ADD COLUMN IF NOT EXISTS languages_spoken app.language_code[];

View File

@@ -0,0 +1,9 @@
ALTER TABLE app.candidate_education
ADD COLUMN IF NOT EXISTS has_theory BOOLEAN,
ADD COLUMN IF NOT EXISTS has_practice BOOLEAN,
ADD COLUMN IF NOT EXISTS duration_hours INTEGER,
ADD COLUMN IF NOT EXISTS is_nursing_focus BOOLEAN,
ADD COLUMN IF NOT EXISTS ai_has_theory BOOLEAN,
ADD COLUMN IF NOT EXISTS ai_has_practice BOOLEAN,
ADD COLUMN IF NOT EXISTS ai_duration_hours INTEGER,
ADD COLUMN IF NOT EXISTS ai_is_nursing_focus BOOLEAN;

View File

@@ -0,0 +1,137 @@
ALTER TABLE app.candidate_education DROP CONSTRAINT IF EXISTS ai_data_requires_document;
ALTER TABLE app.candidate_license DROP CONSTRAINT IF EXISTS ai_data_requires_document;
ALTER TABLE app.candidate_language DROP CONSTRAINT IF EXISTS ai_data_requires_document;
ALTER TABLE app.candidate_experience DROP CONSTRAINT IF EXISTS ai_data_requires_document;
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM app.candidate_education
GROUP BY candidate_id
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Manual migration required: candidate_education still has multiple rows per candidate.';
END IF;
IF EXISTS (
SELECT 1
FROM app.candidate_license
GROUP BY candidate_id
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Manual migration required: candidate_license still has multiple rows per candidate.';
END IF;
IF EXISTS (
SELECT 1
FROM app.candidate_language
GROUP BY candidate_id
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Manual migration required: candidate_language still has multiple rows per candidate.';
END IF;
IF EXISTS (
SELECT 1
FROM app.candidate_experience
GROUP BY candidate_id
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Manual migration required: candidate_experience still has multiple rows per candidate.';
END IF;
IF EXISTS (
SELECT 1
FROM app.candidate_document
WHERE category = 'transcript'::app.candidate_document_type
) THEN
RAISE EXCEPTION 'Manual migration required: transcript documents must be re-categorized before applying schema contract.';
END IF;
END;
$$;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'candidate_education_candidate_id_key'
) THEN
ALTER TABLE app.candidate_education
ADD CONSTRAINT candidate_education_candidate_id_key UNIQUE (candidate_id);
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'candidate_license_candidate_id_key'
) THEN
ALTER TABLE app.candidate_license
ADD CONSTRAINT candidate_license_candidate_id_key UNIQUE (candidate_id);
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'candidate_language_candidate_id_key'
) THEN
ALTER TABLE app.candidate_language
ADD CONSTRAINT candidate_language_candidate_id_key UNIQUE (candidate_id);
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'candidate_experience_candidate_id_key'
) THEN
ALTER TABLE app.candidate_experience
ADD CONSTRAINT candidate_experience_candidate_id_key UNIQUE (candidate_id);
END IF;
END;
$$;
ALTER TABLE app.candidate_education
DROP CONSTRAINT IF EXISTS candidate_education_source_document_id_fkey,
DROP COLUMN IF EXISTS source_document_id;
ALTER TABLE app.candidate_license
DROP CONSTRAINT IF EXISTS candidate_license_source_document_id_fkey,
DROP COLUMN IF EXISTS source_document_id;
ALTER TABLE app.candidate_language
DROP CONSTRAINT IF EXISTS candidate_language_source_document_id_fkey,
DROP COLUMN IF EXISTS source_document_id;
ALTER TABLE app.candidate_experience
DROP CONSTRAINT IF EXISTS candidate_experience_source_document_id_fkey,
DROP COLUMN IF EXISTS source_document_id;
DROP TABLE IF EXISTS app.candidate_transcript CASCADE;
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM pg_type
WHERE typnamespace = 'app'::regnamespace
AND typname = 'candidate_document_type_v2'
) THEN
DROP TYPE app.candidate_document_type_v2;
END IF;
END;
$$;
CREATE TYPE app.candidate_document_type_v2 AS ENUM (
'education',
'license',
'language',
'work_experience'
);
ALTER TABLE app.candidate_document
ALTER COLUMN category TYPE app.candidate_document_type_v2
USING category::text::app.candidate_document_type_v2;
DROP TYPE app.candidate_document_type;
ALTER TYPE app.candidate_document_type_v2 RENAME TO candidate_document_type;

View File

@@ -0,0 +1,73 @@
ALTER TYPE app.applicant_status ADD VALUE IF NOT EXISTS 'Failed';
ALTER TABLE app.candidate
ADD COLUMN IF NOT EXISTS status_changed_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
ADD COLUMN IF NOT EXISTS lifecycle_notifications jsonb DEFAULT '{}'::jsonb NOT NULL,
ADD COLUMN IF NOT EXISTS analysis_last_run_at timestamp with time zone,
ADD COLUMN IF NOT EXISTS analysis_input_fingerprint text,
ADD COLUMN IF NOT EXISTS invalidated_at timestamp with time zone,
ADD COLUMN IF NOT EXISTS reupload_requested_at timestamp with time zone,
ADD COLUMN IF NOT EXISTS reuploaded_at timestamp with time zone,
ADD COLUMN IF NOT EXISTS failed_purged_at timestamp with time zone;
UPDATE app.candidate
SET status_changed_at = CASE
WHEN status = 'Initial'::app.applicant_status THEN COALESCE(created_at, last_updated_at, CURRENT_TIMESTAMP)
WHEN status = 'Pending'::app.applicant_status THEN COALESCE(submitted_at, last_updated_at, created_at, CURRENT_TIMESTAMP)
ELSE COALESCE(last_updated_at, submitted_at, created_at, CURRENT_TIMESTAMP)
END;
CREATE INDEX IF NOT EXISTS idx_candidate_status_changed_at ON app.candidate (status, status_changed_at);
CREATE INDEX IF NOT EXISTS idx_candidate_reupload_flags ON app.candidate (invalidated_at, reuploaded_at);
CREATE OR REPLACE FUNCTION app.handle_candidate_status_lifecycle()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.status IS DISTINCT FROM OLD.status THEN
NEW.status_changed_at = CURRENT_TIMESTAMP;
IF NEW.status = 'Invalid'::app.applicant_status THEN
NEW.invalidated_at = CURRENT_TIMESTAMP;
NEW.reuploaded_at = NULL;
ELSIF OLD.status = 'Invalid'::app.applicant_status
AND NEW.status = 'Initial'::app.applicant_status THEN
NEW.reupload_requested_at = CURRENT_TIMESTAMP;
END IF;
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS candidate_status_lifecycle_trigger ON app.candidate;
CREATE TRIGGER candidate_status_lifecycle_trigger
BEFORE UPDATE OF status ON app.candidate
FOR EACH ROW
EXECUTE FUNCTION app.handle_candidate_status_lifecycle();
CREATE OR REPLACE FUNCTION app.mark_candidate_reuploaded_after_invalid()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.uploaded IS TRUE
AND (OLD.uploaded IS DISTINCT FROM TRUE) THEN
UPDATE app.candidate
SET reuploaded_at = CURRENT_TIMESTAMP
WHERE candidate_id = NEW.candidate_id
AND invalidated_at IS NOT NULL
AND status = 'Initial'::app.applicant_status
AND (reuploaded_at IS NULL OR reuploaded_at < invalidated_at);
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS candidate_document_reupload_marker_trigger ON app.candidate_document;
CREATE TRIGGER candidate_document_reupload_marker_trigger
AFTER UPDATE OF uploaded ON app.candidate_document
FOR EACH ROW
EXECUTE FUNCTION app.mark_candidate_reuploaded_after_invalid();

View File

@@ -0,0 +1 @@
DROP TABLE IF EXISTS app.candidate_clinical_placement CASCADE;

View File

@@ -0,0 +1,2 @@
ALTER TYPE app.candidate_document_type
ADD VALUE IF NOT EXISTS 'profile_image';

View File

@@ -0,0 +1,3 @@
CREATE UNIQUE INDEX IF NOT EXISTS idx_candidate_profile_image_unique
ON app.candidate_document (candidate_id)
WHERE category = 'profile_image';

View File

@@ -0,0 +1,99 @@
ALTER TABLE app.candidate_experience
DROP CONSTRAINT IF EXISTS ai_data_requires_document,
DROP CONSTRAINT IF EXISTS candidate_experience_source_document_id_fkey,
DROP CONSTRAINT IF EXISTS candidate_experience_candidate_id_key;
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'employer'
) AND EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'employer_name'
) THEN
UPDATE app.candidate_experience
SET employer_name = employer
WHERE employer_name IS NULL
AND employer IS NOT NULL;
ALTER TABLE app.candidate_experience DROP COLUMN employer;
ELSIF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'employer'
) AND NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'employer_name'
) THEN
ALTER TABLE app.candidate_experience RENAME COLUMN employer TO employer_name;
END IF;
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'position'
) AND EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'role_title'
) THEN
UPDATE app.candidate_experience
SET role_title = "position"
WHERE role_title IS NULL
AND "position" IS NOT NULL;
ALTER TABLE app.candidate_experience DROP COLUMN "position";
ELSIF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'position'
) AND NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'app'
AND table_name = 'candidate_experience'
AND column_name = 'role_title'
) THEN
ALTER TABLE app.candidate_experience RENAME COLUMN "position" TO role_title;
END IF;
END;
$$;
ALTER TABLE app.candidate_experience
ADD COLUMN IF NOT EXISTS country VARCHAR,
ADD COLUMN IF NOT EXISTS city VARCHAR,
ADD COLUMN IF NOT EXISTS facility_type VARCHAR;
ALTER TABLE app.candidate_experience
DROP COLUMN IF EXISTS source_document_id,
DROP COLUMN IF EXISTS duration_months,
DROP COLUMN IF EXISTS is_full_time,
DROP COLUMN IF EXISTS duties,
DROP COLUMN IF EXISTS ai_employer,
DROP COLUMN IF EXISTS ai_position,
DROP COLUMN IF EXISTS ai_department,
DROP COLUMN IF EXISTS ai_start_date,
DROP COLUMN IF EXISTS ai_end_date,
DROP COLUMN IF EXISTS ai_duration_months,
DROP COLUMN IF EXISTS ai_is_full_time,
DROP COLUMN IF EXISTS ai_duties,
DROP COLUMN IF EXISTS ai_extracted_by,
DROP COLUMN IF EXISTS ai_extraction_date;

View File

@@ -0,0 +1,22 @@
CREATE TABLE IF NOT EXISTS app.leads (
lead_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
first_name VARCHAR NOT NULL,
last_name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
phone VARCHAR,
facility_name VARCHAR NOT NULL,
facility_type VARCHAR NOT NULL,
nurses_needed_range VARCHAR,
message TEXT,
source VARCHAR NOT NULL DEFAULT 'pilot',
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
last_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS leads_created_at_idx ON app.leads (created_at DESC);
CREATE INDEX IF NOT EXISTS leads_email_idx ON app.leads (email);
DROP TRIGGER IF EXISTS update_leads_timestamp ON app.leads;
CREATE TRIGGER update_leads_timestamp
BEFORE UPDATE ON app.leads
FOR EACH ROW EXECUTE PROCEDURE app.update_lastupdated_timestamp();

View File

@@ -0,0 +1,51 @@
CREATE TABLE IF NOT EXISTS app.auth_user (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE,
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
image VARCHAR,
role VARCHAR NOT NULL DEFAULT 'owner',
type VARCHAR NOT NULL DEFAULT 'candidate',
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS app.auth_session (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
expires_at TIMESTAMPTZ NOT NULL,
token VARCHAR NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR,
user_agent VARCHAR,
user_id UUID NOT NULL REFERENCES app.auth_user(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS app.auth_account (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id VARCHAR NOT NULL,
provider_id VARCHAR NOT NULL,
user_id UUID NOT NULL REFERENCES app.auth_user(id) ON DELETE CASCADE,
access_token VARCHAR,
refresh_token VARCHAR,
id_token VARCHAR,
access_token_expires_at TIMESTAMPTZ,
refresh_token_expires_at TIMESTAMPTZ,
scope VARCHAR,
password VARCHAR,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS app.auth_verification (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
identifier VARCHAR NOT NULL,
value VARCHAR NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_auth_session_user_id ON app.auth_session(user_id);
CREATE INDEX IF NOT EXISTS idx_auth_account_user_id ON app.auth_account(user_id);
CREATE INDEX IF NOT EXISTS idx_auth_verification_identifier ON app.auth_verification(identifier);

View File

@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS app.backend_translation (
locale TEXT NOT NULL,
namespace TEXT NOT NULL,
content_json JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (locale, namespace)
);