Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions ddl/Tables/ddl-internal-applications.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
CREATE TYPE virginia_dev_saayam_rdbms.internal_app_status_type
AS ENUM ('PENDING', 'IN_VERIFICATION', 'APPROVED', 'REJECTED');

CREATE TABLE virginia_dev_saayam_rdbms.internal_applications (
user_id VARCHAR(255) PRIMARY KEY,

-- contact / identity
email VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
phone_country_code VARCHAR(10),
phone_number VARCHAR(20),
phone_extension VARCHAR(10),
linkedin_url VARCHAR(500),
github_url VARCHAR(500),
timezone VARCHAR(100),

-- academic / professional background
college VARCHAR(255),
degree_program VARCHAR(255),
dean_contact VARCHAR(255),
relevant_experience TEXT,

-- role / engagement
preferred_role VARCHAR(100),
hours_per_week INT,
start_date DATE,
engagement_type VARCHAR(50),

-- location & document type
is_us_based BOOLEAN,
need_offer_letter BOOLEAN,
document_type VARCHAR(50),
country VARCHAR(100),

-- S3 document references
resume_s3_key VARCHAR(500),
ead_card_s3_key VARCHAR(500),
i20_s3_key VARCHAR(500),
government_id_s3_key VARCHAR(500),
govt_id_path_updated_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),

-- acknowledgments
acknowledgments JSONB,
acknowledgments_accepted_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),

-- review workflow
application_status virginia_dev_saayam_rdbms.internal_app_status_type
DEFAULT 'PENDING',
reviewer_cognito_id VARCHAR(255),
reviewer_notes TEXT,
rejection_reason TEXT,

-- timestamps
created_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),
last_updated_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),
reviewed_at TIMESTAMP WITHOUT TIME ZONE,

FOREIGN KEY (user_id) REFERENCES virginia_dev_saayam_rdbms.users(user_id)
);

CREATE INDEX idx_internal_apps_status
ON virginia_dev_saayam_rdbms.internal_applications(application_status);
CREATE INDEX idx_internal_apps_reviewer
ON virginia_dev_saayam_rdbms.internal_applications(reviewer_cognito_id);
CREATE INDEX idx_internal_apps_created
ON virginia_dev_saayam_rdbms.internal_applications(created_at DESC);
44 changes: 44 additions & 0 deletions ddl/Tables/ddl-internal_app_rejections.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
CREATE TABLE virginia_dev_saayam_rdbms.internal_app_rejections (
rejection_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) NOT NULL,

-- applicant snapshot
email VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
phone_country_code VARCHAR(10),
phone_number VARCHAR(20),
linkedin_url VARCHAR(500),
github_url VARCHAR(500),
college VARCHAR(255),
degree_program VARCHAR(255),
relevant_experience TEXT,
preferred_role VARCHAR(100),
hours_per_week INT,
start_date DATE,
engagement_type VARCHAR(50),
is_us_based BOOLEAN,
country VARCHAR(100),
resume_s3_key VARCHAR(500),
ead_card_s3_key VARCHAR(500),
i20_s3_key VARCHAR(500),
government_id_s3_key VARCHAR(500),
acknowledgments JSONB,

-- rejection metadata
rejection_reason TEXT NOT NULL,
reviewer_cognito_id VARCHAR(255),
reviewer_notes TEXT,

-- timestamps
application_created_at TIMESTAMP WITHOUT TIME ZONE,
rejected_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),

FOREIGN KEY (user_id) REFERENCES virginia_dev_saayam_rdbms.users(user_id)
);

CREATE INDEX idx_internal_rejections_user
ON virginia_dev_saayam_rdbms.internal_app_rejections(user_id);
CREATE INDEX idx_internal_rejections_rejected_at
ON virginia_dev_saayam_rdbms.internal_app_rejections(rejected_at DESC);
104 changes: 104 additions & 0 deletions ddl/Tables/ddl_handle_internal_application.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
-- =====================================================================
-- 2. handle_internal_application
-- Routes the row to internal_team or internal_app_rejections based
-- on terminal application_status, then deletes the source row.
-- Mirrors handle_volunteer_application but supports TWO exits.
-- =====================================================================
CREATE OR REPLACE FUNCTION virginia_dev_saayam_rdbms.handle_internal_application()
RETURNS TRIGGER AS $$
BEGIN
-- ---- APPROVED path -> internal_team ----
IF (NEW.application_status = 'APPROVED'
AND OLD.application_status != 'APPROVED') THEN

INSERT INTO virginia_dev_saayam_rdbms.internal_team (
user_id, email, first_name, last_name,
phone_country_code, phone_number, phone_extension,
linkedin_url, github_url, timezone,
internal_role, preferred_role, hours_per_week, start_date, engagement_type,
is_us_based, country, government_id_s3_key,
is_active, joined_at,
created_at, last_updated_at
) VALUES (
NEW.user_id, NEW.email, NEW.first_name, NEW.last_name,
NEW.phone_country_code, NEW.phone_number, NEW.phone_extension,
NEW.linkedin_url, NEW.github_url, NEW.timezone,
NEW.preferred_role, -- default internal_role = applied-for role
NEW.preferred_role, NEW.hours_per_week, NEW.start_date, NEW.engagement_type,
NEW.is_us_based, NEW.country, NEW.government_id_s3_key,
TRUE, (now() AT TIME ZONE 'UTC'),
NEW.last_updated_at, NEW.last_updated_at
);

DELETE FROM virginia_dev_saayam_rdbms.internal_applications
WHERE user_id = NEW.user_id;

-- ---- REJECTED path -> internal_app_rejections ----
ELSIF (NEW.application_status = 'REJECTED'
AND OLD.application_status != 'REJECTED') THEN

INSERT INTO virginia_dev_saayam_rdbms.internal_app_rejections (
user_id, email, first_name, last_name,
phone_country_code, phone_number, phone_extension,
linkedin_url, github_url,
college, degree_program, relevant_experience,
preferred_role, hours_per_week, start_date, engagement_type,
is_us_based, country,
resume_s3_key, ead_card_s3_key, i20_s3_key, government_id_s3_key,
acknowledgments,
rejection_reason, reviewer_cognito_id, reviewer_notes,
application_created_at, rejected_at
) VALUES (
NEW.user_id, NEW.email, NEW.first_name, NEW.last_name,
NEW.phone_country_code, NEW.phone_number, NEW.phone_extension,
NEW.linkedin_url, NEW.github_url,
NEW.college, NEW.degree_program, NEW.relevant_experience,
NEW.preferred_role, NEW.hours_per_week, NEW.start_date, NEW.engagement_type,
NEW.is_us_based, NEW.country,
NEW.resume_s3_key, NEW.ead_card_s3_key, NEW.i20_s3_key, NEW.government_id_s3_key,
NEW.acknowledgments,
COALESCE(NEW.rejection_reason, 'No reason supplied'),
NEW.reviewer_cognito_id, NEW.reviewer_notes,
NEW.created_at, (now() AT TIME ZONE 'UTC')
);

DELETE FROM virginia_dev_saayam_rdbms.internal_applications
WHERE user_id = NEW.user_id;
END IF;

RETURN NEW;
END;
$$ LANGUAGE plpgsql;


-- =====================================================================
-- 3. Trigger definitions
-- =====================================================================

-- BEFORE UPDATE: auto-timestamps on internal_applications
CREATE TRIGGER trg_internal_app_updated_at
BEFORE UPDATE ON virginia_dev_saayam_rdbms.internal_applications
FOR EACH ROW EXECUTE FUNCTION virginia_dev_saayam_rdbms.updated_at_handler();

-- BEFORE UPDATE: auto-timestamps on internal_team
CREATE TRIGGER trg_internal_team_updated_at
BEFORE UPDATE ON virginia_dev_saayam_rdbms.internal_team
FOR EACH ROW EXECUTE FUNCTION virginia_dev_saayam_rdbms.updated_at_handler();

-- AFTER UPDATE: route on terminal application_status
CREATE TRIGGER trg_handle_internal_application
AFTER UPDATE ON virginia_dev_saayam_rdbms.internal_applications
FOR EACH ROW EXECUTE FUNCTION virginia_dev_saayam_rdbms.handle_internal_application();


-- =====================================================================
-- 4. Explicit ENABLE (matches existing volunteer file convention)
-- =====================================================================
ALTER TABLE virginia_dev_saayam_rdbms.internal_applications
ENABLE TRIGGER trg_internal_app_updated_at;

ALTER TABLE virginia_dev_saayam_rdbms.internal_applications
ENABLE TRIGGER trg_handle_internal_application;

ALTER TABLE virginia_dev_saayam_rdbms.internal_team
ENABLE TRIGGER trg_internal_team_updated_at;
44 changes: 44 additions & 0 deletions ddl/Tables/ddl_internal_teams.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
CREATE TABLE virginia_dev_saayam_rdbms.internal_team (
user_id VARCHAR(255) PRIMARY KEY,

-- identity
email VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
phone_country_code VARCHAR(10),
phone_number VARCHAR(20),
linkedin_url VARCHAR(500),
github_url VARCHAR(500),
timezone VARCHAR(100),

-- role / engagement
internal_role VARCHAR(100),
preferred_role VARCHAR(100),
hours_per_week INT,
start_date DATE,
engagement_type VARCHAR(50),

-- location / docs
is_us_based BOOLEAN,
country VARCHAR(100),
government_id_s3_key VARCHAR(500),

-- membership lifecycle
is_active BOOLEAN DEFAULT TRUE,
joined_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),
deactivated_at TIMESTAMP WITHOUT TIME ZONE,

-- standard timestamps
created_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),
last_updated_at TIMESTAMP WITHOUT TIME ZONE
DEFAULT (now() AT TIME ZONE 'UTC'),

FOREIGN KEY (user_id) REFERENCES virginia_dev_saayam_rdbms.users(user_id)
);

CREATE INDEX idx_internal_team_role
ON virginia_dev_saayam_rdbms.internal_team(internal_role);
CREATE INDEX idx_internal_team_active
ON virginia_dev_saayam_rdbms.internal_team(is_active);
55 changes: 55 additions & 0 deletions ddl/Tables/ddl_updated_at_handler.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
CREATE OR REPLACE FUNCTION virginia_dev_saayam_rdbms.updated_at_handler()
RETURNS TRIGGER AS $$
BEGIN
-- If last_updated_at wasn't explicitly changed by the API, force UTC now.
IF (NEW.last_updated_at IS NOT DISTINCT FROM OLD.last_updated_at) THEN
NEW.last_updated_at = (now() AT TIME ZONE 'UTC');
END IF;

-- existing: volunteer_applications
IF (TG_TABLE_NAME = 'volunteer_applications') THEN
IF (NEW.govt_id_path IS DISTINCT FROM OLD.govt_id_path) THEN
NEW.path_updated_at = (now() AT TIME ZONE 'UTC');
END IF;
IF (NEW.terms_and_conditions IS TRUE
AND (OLD.terms_and_conditions IS FALSE OR OLD.terms_and_conditions IS NULL)) THEN
NEW.terms_accepted_at = (now() AT TIME ZONE 'UTC');
END IF;

-- existing: volunteer_details
ELSIF (TG_TABLE_NAME = 'volunteer_details') THEN
IF (NEW.govt_id_path1 IS DISTINCT FROM OLD.govt_id_path1) THEN
NEW.path1_updated_at = (now() AT TIME ZONE 'UTC');
END IF;
IF (NEW.govt_id_path2 IS DISTINCT FROM OLD.govt_id_path2) THEN
NEW.path2_updated_at = (now() AT TIME ZONE 'UTC');
END IF;
IF (NEW.terms_and_conditions IS TRUE
AND (OLD.terms_and_conditions IS FALSE OR OLD.terms_and_conditions IS NULL)) THEN
NEW.terms_accepted_at = (now() AT TIME ZONE 'UTC');
END IF;

-- NEW: internal_applications
ELSIF (TG_TABLE_NAME = 'internal_applications') THEN
IF (NEW.government_id_s3_key IS DISTINCT FROM OLD.government_id_s3_key) THEN
NEW.govt_id_path_updated_at = (now() AT TIME ZONE 'UTC');
END IF;
IF (NEW.acknowledgments IS DISTINCT FROM OLD.acknowledgments) THEN
NEW.acknowledgments_accepted_at = (now() AT TIME ZONE 'UTC');
END IF;
IF (NEW.application_status IS DISTINCT FROM OLD.application_status
AND NEW.application_status IN ('APPROVED', 'REJECTED')) THEN
NEW.reviewed_at = (now() AT TIME ZONE 'UTC');
END IF;

-- NEW: internal_team
ELSIF (TG_TABLE_NAME = 'internal_team') THEN
IF (NEW.is_active IS FALSE
AND (OLD.is_active IS TRUE OR OLD.is_active IS NULL)) THEN
NEW.deactivated_at = (now() AT TIME ZONE 'UTC');
END IF;
END IF;

RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Loading