ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / db/migrations/0087_org_settings.sql

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / db/migrations/0087_org_settings.sql
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberdb/migrations/0087_org_settings.sql
Original SHA-256446e5ab76c533c4b58c8b3a05b5300e39429e2cdf15221e9cd5690f4017acf78
Git blob SHAd3c207af01423bcdf07f43f3de097c97f477e4d9
Reading-copy SHA-256446e5ab76c533c4b58c8b3a05b5300e39429e2cdf15221e9cd5690f4017acf78

Original source ↗

Recovered source transcript

-- +goose Up -- PER ORGANIZATION SETTINGS AND PER ORGANIZATION SECRETS. -- -- WHY THIS EXISTS. Three separate asks land on the same missing thing. Invites had to be delivered by hand -- because the platform had no way to hold a customer's mail credentials. Recruiters were doubling work on the -- same candidate because nothing recorded who was already on it. Rates were visible to everyone because -- sensitivity had nowhere to be configured. All three need a place where a tenant states how it works, and one -- of them needs a place where a tenant stores a password. So this is two tables, not one, because a setting -- and a secret deserve different handling. -- -- SECRETS ARE SEALED, NEVER STORED. org_secrets holds AES 256 GCM ciphertext under a key that lives only in -- the server env file, carried with a key_version so the key can rotate without a flag day. That is exactly -- the mfa_totp pattern from migration 0009, deliberately reused rather than reinvented: one definition of what -- encrypted at rest means in this system. NOTHING in this table is a fragment of a plaintext secret. There is -- no last_four, no hint, no length column, because each of those is a free guess for anyone who reaches the -- row. -- -- SETTINGS MAY NOT WEAKEN A COMPLIANCE GUARANTEE, and that bound is the reason this table is typed columns -- rather than a key value bag. Human approval of every slate member, adverse impact reporting, the audit -- trail, and the fixed NIST session timeouts are NOT here and must never be added here. A tenant configures -- how its people work. A tenant does not configure whether this is still an auditable Automated Employment -- Decision Tool. A key value bag would have made the wrong setting a one line insert; typed columns make it a -- migration somebody has to justify. -- -- POLICIES CARRY NO "TO" CLAUSE. Same reason as migration 0086: a policy naming only missionmatch_app does not -- apply to missionmatch_staging_app, and with no applicable policy RLS denies everything, which is what broke -- Gate A. An unaddressed policy applies to every role and is correct in every environment. -- ============================================================================ -- 1. org_settings -- ============================================================================ CREATE TABLE org_settings ( organization_id uuid PRIMARY KEY REFERENCES organizations(id) ON DELETE CASCADE, -- ---- outbound email ----------------------------------------------------------------------------- -- Off by default, so an organization that never configures mail keeps exactly the behaviour it has today: -- the invite endpoint returns the one time link and a human delivers it. Turning this on is a deliberate -- act, and it only takes effect once a test send has actually succeeded (see smtp_verified_at). email_delivery_enabled boolean NOT NULL DEFAULT false, email_from_address text, email_from_name text, email_reply_to text, smtp_host text, smtp_port int CHECK (smtp_port IS NULL OR (smtp_port BETWEEN 1 AND 65535)), smtp_username text, -- THERE IS NO PLAINTEXT OPTION. Cleartext SMTP is not offered at any port, because the two things this -- transport carries are an activation credential and a candidate's name, and neither belongs on the wire -- in the clear. starttls upgrades an established session, implicit_tls dials TLS immediately (port 465). smtp_security text NOT NULL DEFAULT 'starttls' CHECK (smtp_security IN ('starttls', 'implicit_tls')), -- Set ONLY by a successful test send and cleared by any settings change that could invalidate it. Mail is -- never attempted against an unverified configuration, so a typo in a host name surfaces when an admin -- presses test, not when a candidate never receives an invite and nobody finds out for a week. smtp_verified_at timestamptz, smtp_last_attempt_at timestamptz, -- The transport's own error text, kept so an admin can self serve a fix. It is a connection level message, -- never a credential, and the application refuses to write it if it would echo the username or password. smtp_last_error text, -- ---- who can see what a recruiter is working on ------------------------------------------------- -- The ask this answers is double work: two recruiters calling the same person on the same day makes the -- agency look disorganised to the one human whose opinion decides the placement. organization is the -- default because visibility is the entire point, and the narrower settings exist for firms that run -- competing desks and genuinely do not want a shared pipeline. work_visibility text NOT NULL DEFAULT 'organization' CHECK (work_visibility IN ('private', 'team', 'organization')), -- Presence is the soft version: not a lock, just a note that somebody else is here. It is what stops most -- collisions without stopping anybody from working. show_activity_presence boolean NOT NULL DEFAULT true, -- Claiming is the hard version, for firms that want exclusivity on a candidate while somebody works them. claim_required boolean NOT NULL DEFAULT false, -- A claim nobody releases is a claim that silently owns a candidate forever, which is worse than no -- claiming at all, so claims expire and the default is three working days. claim_expiry_hours int NOT NULL DEFAULT 72 CHECK (claim_expiry_hours BETWEEN 1 AND 2160), -- ---- field sensitivity -------------------------------------------------------------------------- -- Pay data is the field where a wrong default is a real harm, not an inconvenience. A junior recruiter who -- can see the bill rate can infer the margin, and a candidate who learns the margin is a candidate who has -- learned what the agency makes on them. The industry default is that pay data is management visible, so -- that is the default here. rate_visibility text NOT NULL DEFAULT 'managers' CHECK (rate_visibility IN ('owner', 'managers', 'team', 'organization')), margin_visibility text NOT NULL DEFAULT 'owner' CHECK (margin_visibility IN ('owner', 'managers', 'team', 'organization')), -- Contact details are the other sensitive class and for the opposite reason: they are the asset a leaving -- recruiter walks out with. team by default, so a desk sees its own people and not the whole database. contact_visibility text NOT NULL DEFAULT 'team' CHECK (contact_visibility IN ('owner', 'managers', 'team', 'organization')), -- ---- operating defaults ------------------------------------------------------------------------- -- The settings nobody asks for until the day they are wrong. A deadline rendered in the wrong zone is a -- missed submission, and this platform's whole calendar is federal due dates. time_zone text NOT NULL DEFAULT 'America/New_York', invite_expiry_hours int NOT NULL DEFAULT 72 CHECK (invite_expiry_hours BETWEEN 1 AND 336), -- The role a new invite proposes. It is a default in the user interface, NOT an authority bound: the -- separation of duties rule that an inviter may only invite strictly below themselves still decides what -- is actually permitted, and this cannot raise it. default_invite_role text NOT NULL DEFAULT 'recruiter', updated_at timestamptz NOT NULL DEFAULT now(), updated_by uuid, CONSTRAINT fk_org_settings_updated_by FOREIGN KEY (organization_id, updated_by) REFERENCES users (organization_id, id), -- Delivery cannot be switched on against a configuration that has never worked. The application checks -- this too, and says so in a sentence; the constraint is here because a check that lives only in a handler -- is a check the second caller skips. CONSTRAINT ck_org_settings_email_ready CHECK ( email_delivery_enabled = false OR (smtp_host IS NOT NULL AND smtp_port IS NOT NULL AND email_from_address IS NOT NULL AND smtp_verified_at IS NOT NULL) ) ); ALTER TABLE org_settings ENABLE ROW LEVEL SECURITY; ALTER TABLE org_settings FORCE ROW LEVEL SECURITY; CREATE POLICY org_settings_isolation ON org_settings USING (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid) WITH CHECK (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid); GRANT SELECT, INSERT, UPDATE ON org_settings TO missionmatch_app; -- ============================================================================ -- 2. org_secrets -- ============================================================================ -- One sealed value per (organization, name). name is a stable key the application knows, for example -- smtp_password today and a source connector credential when in place federation lands, which is the whole -- reason this is a general table and not two columns on org_settings. CREATE TABLE org_secrets ( organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name text NOT NULL CHECK (name ~ '^[a-z][a-z0-9_.]{1,62}$'), ciphertext bytea NOT NULL, nonce bytea NOT NULL, key_version int NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), updated_by uuid, PRIMARY KEY (organization_id, name), CONSTRAINT fk_org_secrets_updated_by FOREIGN KEY (organization_id, updated_by) REFERENCES users (organization_id, id) ); ALTER TABLE org_secrets ENABLE ROW LEVEL SECURITY; ALTER TABLE org_secrets FORCE ROW LEVEL SECURITY; CREATE POLICY org_secrets_isolation ON org_secrets USING (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid) WITH CHECK (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid); -- DELETE is granted here and nowhere else in this schema, and the exception is deliberate. Everywhere else a -- removed row is a historical claim that has to stay auditable. A revoked credential is the opposite: leaving -- the ciphertext behind after an admin removes it means the value is still one key compromise away from being -- read. Removing a secret is recorded in audit_logs by name, never by value. GRANT SELECT, INSERT, UPDATE, DELETE ON org_secrets TO missionmatch_app; -- ============================================================================ -- 3. who is working what, the double work answer -- ============================================================================ -- work_claims records that a named person is on a named record right now. It is one table across entity types -- rather than a claimed_by column on each, because the question a recruiter asks is "is anyone on this" and -- the answer has to be the same shape for a candidate, a requisition and an opportunity. -- -- THIS IS NOT A SECOND OWNERSHIP COLUMN. clients and requisitions already carry owner_user_id from migration -- 0047, with claim and reassign routes in internal/modules/recruiting/ownership.go, and that column stays -- authoritative for whose desk a record belongs to. A claim here is a DIFFERENT and shorter lived fact: not -- "this account is mine" but "I am on this right now, do not also call them today". The two coexist, and the -- read surface shows both, because a candidate being on Dana's desk and Marcus actively submitting them this -- afternoon are both true and a recruiter needs to see each. CANDIDATES are the case that has neither today, -- and a candidate called twice in one day by the same agency is the exact complaint this closes. -- -- It is NOT a lock. released_at and expires_at both exist, and a claim that expires simply stops being a -- claim: nothing in the application blocks a second person from working a claimed record unless the -- organization has set claim_required, and even then the block is a warning path with an override, because a -- staffing firm that cannot reassign a desk at five o'clock on a deadline day is a staffing firm that loses -- the award. CREATE TABLE work_claims ( organization_id uuid NOT NULL REFERENCES organizations(id), id uuid NOT NULL DEFAULT gen_random_uuid(), entity_type text NOT NULL CHECK (entity_type IN ('candidate', 'requisition', 'opportunity', 'proposal', 'client')), entity_id uuid NOT NULL, user_id uuid NOT NULL, -- What they are doing, so the note a colleague sees is useful rather than merely a name. activity text NOT NULL DEFAULT 'working' CHECK (activity IN ('working', 'screening', 'submitting', 'interviewing', 'negotiating')), note text NOT NULL DEFAULT '', claimed_at timestamptz NOT NULL DEFAULT now(), expires_at timestamptz NOT NULL, released_at timestamptz, released_by uuid, PRIMARY KEY (organization_id, id), CONSTRAINT fk_work_claims_user FOREIGN KEY (organization_id, user_id) REFERENCES users (organization_id, id), CONSTRAINT ck_work_claims_window CHECK (expires_at > claimed_at) ); -- One live claim per record per organization. The partial unique index is what makes "who is on this" a single -- row answer rather than a list to reconcile, and it is enforced by the database because two recruiters -- pressing claim at the same instant is precisely the case a handler side check loses. CREATE UNIQUE INDEX uq_work_claims_live ON work_claims (organization_id, entity_type, entity_id) WHERE released_at IS NULL; CREATE INDEX idx_work_claims_user ON work_claims (organization_id, user_id, claimed_at DESC) WHERE released_at IS NULL; CREATE INDEX idx_work_claims_expiry ON work_claims (expires_at) WHERE released_at IS NULL; ALTER TABLE work_claims ENABLE ROW LEVEL SECURITY; ALTER TABLE work_claims FORCE ROW LEVEL SECURITY; CREATE POLICY work_claims_isolation ON work_claims USING (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid) WITH CHECK (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid); GRANT SELECT, INSERT, UPDATE ON work_claims TO missionmatch_app; -- ============================================================================ -- 4. lightweight presence, the soft half of the same answer -- ============================================================================ -- work_touches is the "Dana looked at this eleven minutes ago" signal. It is separate from work_claims because -- it answers a different question and has a different lifetime: a claim is an intention that lasts days, a -- touch is a fact that stops being interesting within the hour. -- -- IT IS UPSERTED, NEVER APPENDED. One row per person per record, overwritten on each visit. An append only -- design here would generate a row per page view per recruiter per candidate, which is millions of rows a -- month describing something nobody will ever read twice, and it would put a browsing history of a named -- employee in a table that is trivially reportable. This is presence, not surveillance. CREATE TABLE work_touches ( organization_id uuid NOT NULL REFERENCES organizations(id), entity_type text NOT NULL CHECK (entity_type IN ('candidate', 'requisition', 'opportunity', 'proposal', 'client')), entity_id uuid NOT NULL, user_id uuid NOT NULL, last_seen_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (organization_id, entity_type, entity_id, user_id), CONSTRAINT fk_work_touches_user FOREIGN KEY (organization_id, user_id) REFERENCES users (organization_id, id) ); CREATE INDEX idx_work_touches_recent ON work_touches (organization_id, entity_type, entity_id, last_seen_at DESC); ALTER TABLE work_touches ENABLE ROW LEVEL SECURITY; ALTER TABLE work_touches FORCE ROW LEVEL SECURITY; CREATE POLICY work_touches_isolation ON work_touches USING (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid) WITH CHECK (organization_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid); GRANT SELECT, INSERT, UPDATE ON work_touches TO missionmatch_app; -- ============================================================================ -- 5. every existing organization gets its defaults now -- ============================================================================ -- Backfilled rather than created lazily, so a read never has to decide whether an absent row means defaults or -- means something went wrong. Provisioning inserts one too, see below. INSERT INTO org_settings (organization_id) SELECT id FROM organizations ON CONFLICT (organization_id) DO NOTHING; -- Staging parity, the same call migration 0086 ends with. Roles are cluster wide but privileges are per -- database, so the helper is a no op unless this really is the staging database. SELECT mm_mirror_staging_role_privileges(); -- +goose Down DROP TABLE IF EXISTS work_touches; DROP TABLE IF EXISTS work_claims; DROP TABLE IF EXISTS org_secrets; DROP TABLE IF EXISTS org_settings;

Search equations, builds, manuscript text, and recovered sources.