chore: replace personal seed data with generic demo profiles
Seeds now insert generic Demo User personas (INSERT OR IGNORE, so existing databases keep their current profile data). Drops the every-boot UPDATE backfills that re-asserted personal values, and removes the personal cron env example templates in favor of the generic scripts/jobber-cron.env.example.
This commit is contained in:
parent
af3d1c56b0
commit
285b094bce
10
.env.example
10
.env.example
@ -23,7 +23,7 @@ MODEL=google/gemini-3-flash-preview
|
|||||||
# Takes precedence over Settings → local path. PDF export still uses RxResume when enabled.
|
# Takes precedence over Settings → local path. PDF export still uses RxResume when enabled.
|
||||||
# Example (monorepo): hand-authored v5 JSON may live under `data/resumes/` (that folder is gitignored by default).
|
# Example (monorepo): hand-authored v5 JSON may live under `data/resumes/` (that folder is gitignored by default).
|
||||||
# If you use seeded search profiles with `resumeLocalPath` + login auto-activate, leave this unset so Settings → local path wins.
|
# If you use seeded search profiles with `resumeLocalPath` + login auto-activate, leave this unset so Settings → local path wins.
|
||||||
# JOBOPS_LOCAL_RESUME_PATH=../data/resumes/ilia-dobkin.json
|
# JOBOPS_LOCAL_RESUME_PATH=../data/resumes/demo-user.json
|
||||||
|
|
||||||
# RXResume credentials for PDF generation
|
# RXResume credentials for PDF generation
|
||||||
# Create an account at: https://v4.rxresu.me
|
# Create an account at: https://v4.rxresu.me
|
||||||
@ -37,10 +37,10 @@ RXRESUME_PASSWORD=your_password_here
|
|||||||
# BASIC_AUTH_USER_2=
|
# BASIC_AUTH_USER_2=
|
||||||
# BASIC_AUTH_PASSWORD_2=
|
# BASIC_AUTH_PASSWORD_2=
|
||||||
# Example local pairing with DB-seeded profiles (change passwords before exposing the UI):
|
# Example local pairing with DB-seeded profiles (change passwords before exposing the UI):
|
||||||
# BASIC_AUTH_USER=ilia
|
# BASIC_AUTH_USER=demo
|
||||||
# BASIC_AUTH_PASSWORD=changeme-ilia
|
# BASIC_AUTH_PASSWORD=changeme-demo
|
||||||
# BASIC_AUTH_USER_2=cherepaha
|
# BASIC_AUTH_USER_2=demo-qa
|
||||||
# BASIC_AUTH_PASSWORD_2=changeme-cherepaha
|
# BASIC_AUTH_PASSWORD_2=changeme-demo-qa
|
||||||
BASIC_AUTH_USER=
|
BASIC_AUTH_USER=
|
||||||
BASIC_AUTH_PASSWORD=
|
BASIC_AUTH_PASSWORD=
|
||||||
|
|
||||||
|
|||||||
@ -156,9 +156,9 @@ Readiness requires:
|
|||||||
### Job search profiles and local resume
|
### Job search profiles and local resume
|
||||||
|
|
||||||
- **Search profiles** store target roles, deal-breakers, locations, and scoring context. Use the profile picker in Settings to create, switch, or activate a profile.
|
- **Search profiles** store target roles, deal-breakers, locations, and scoring context. Use the profile picker in Settings to create, switch, or activate a profile.
|
||||||
- When **Basic Auth** is enabled, each login user maps to profiles whose `basicAuthUser` field lists that username. Comma-separated aliases are supported (for example `ilia,dobkin` accepts either login name).
|
- When **Basic Auth** is enabled, each login user maps to profiles whose `basicAuthUser` field lists that username. Comma-separated aliases are supported (for example `demo,demo-user` accepts either login name).
|
||||||
- Jobs are scoped per profile (`owner_profile_id`). Pipeline runs and the orchestrator board only show jobs for the profile tied to your current login.
|
- Jobs are scoped per profile (`owner_profile_id`). Pipeline runs and the orchestrator board only show jobs for the profile tied to your current login.
|
||||||
- **Local resume** JSON paths can be set per profile via `resumeLocalPath` in profile data (for example `../data/resumes/ilia-dobkin.json`). JobOps resolves that path relative to the orchestrator working directory when `JOBOPS_LOCAL_RESUME_PATH` is unset.
|
- **Local resume** JSON paths can be set per profile via `resumeLocalPath` in profile data (for example `../data/resumes/demo-user.json`). JobOps resolves that path relative to the orchestrator working directory when `JOBOPS_LOCAL_RESUME_PATH` is unset.
|
||||||
- Activating a profile on Settings calls `POST /api/profiles/:id/activate` and updates `activeProfileId`, `jobSearchProfile`, and `localResumeProfilePath` when Basic Auth is off.
|
- Activating a profile on Settings calls `POST /api/profiles/:id/activate` and updates `activeProfileId`, `jobSearchProfile`, and `localResumeProfilePath` when Basic Auth is off.
|
||||||
|
|
||||||
### Backup
|
### Backup
|
||||||
|
|||||||
@ -362,8 +362,8 @@ export const ManualImportFlow: React.FC<ManualImportFlowProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[11px] text-muted-foreground">
|
<p className="text-[11px] text-muted-foreground">
|
||||||
Synthetic postings for quick manual-import testing (Ilia vs
|
Synthetic postings for quick manual-import testing (SDET vs
|
||||||
Cherepaha-style roles).
|
Guidewire QA-style roles).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -124,10 +124,8 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
|
|||||||
only visible to this login
|
only visible to this login
|
||||||
</span>
|
</span>
|
||||||
— sign out to use another user (e.g.{" "}
|
— sign out to use another user (e.g.{" "}
|
||||||
<span className="font-mono text-foreground">ilia</span> vs{" "}
|
<span className="font-mono text-foreground">demo</span> vs{" "}
|
||||||
<span className="font-mono text-foreground">
|
<span className="font-mono text-foreground">demo-qa</span>
|
||||||
cherepaha
|
|
||||||
</span>
|
|
||||||
).
|
).
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -175,7 +175,7 @@ describe.sequential("Stats proxy routes", () => {
|
|||||||
await stopServer({ server, closeDb, tempDir });
|
await stopServer({ server, closeDb, tempDir });
|
||||||
({ server, baseUrl, closeDb, tempDir } = await startServer({
|
({ server, baseUrl, closeDb, tempDir } = await startServer({
|
||||||
env: {
|
env: {
|
||||||
BASIC_AUTH_USER: "ilia",
|
BASIC_AUTH_USER: "demo",
|
||||||
BASIC_AUTH_PASSWORD: "secret",
|
BASIC_AUTH_PASSWORD: "secret",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -228,7 +228,7 @@ describe.sequential("Tracer links routes", () => {
|
|||||||
({ server, baseUrl, closeDb, tempDir } = await startServer({
|
({ server, baseUrl, closeDb, tempDir } = await startServer({
|
||||||
env: {
|
env: {
|
||||||
// Must match a seeded search profile `basicAuthUser` (see db/migrate.ts).
|
// Must match a seeded search profile `basicAuthUser` (see db/migrate.ts).
|
||||||
BASIC_AUTH_USER: "ilia",
|
BASIC_AUTH_USER: "demo",
|
||||||
BASIC_AUTH_PASSWORD: "secret",
|
BASIC_AUTH_PASSWORD: "secret",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@ -236,7 +236,7 @@ describe.sequential("Tracer links routes", () => {
|
|||||||
const unauthorized = await fetch(`${baseUrl}/api/tracer-links/analytics`);
|
const unauthorized = await fetch(`${baseUrl}/api/tracer-links/analytics`);
|
||||||
expect(unauthorized.status).toBe(401);
|
expect(unauthorized.status).toBe(401);
|
||||||
|
|
||||||
const credentials = Buffer.from("ilia:secret").toString("base64");
|
const credentials = Buffer.from("demo:secret").toString("base64");
|
||||||
const authorized = await fetch(`${baseUrl}/api/tracer-links/analytics`, {
|
const authorized = await fetch(`${baseUrl}/api/tracer-links/analytics`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Basic ${credentials}`,
|
Authorization: `Basic ${credentials}`,
|
||||||
|
|||||||
@ -34,7 +34,7 @@ function sqlJsonLiteral(values: string[]): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Canada / remote — SDET & QA automation title variants for discovery + scoring. */
|
/** Canada / remote — SDET & QA automation title variants for discovery + scoring. */
|
||||||
const ILIA_DOBKIN_CA_TARGET_ROLES = [
|
const SDET_CA_TARGET_ROLES = [
|
||||||
"SDET",
|
"SDET",
|
||||||
"Senior SDET",
|
"Senior SDET",
|
||||||
"Lead SDET",
|
"Lead SDET",
|
||||||
@ -61,8 +61,8 @@ const ILIA_DOBKIN_CA_TARGET_ROLES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/** Job-board search terms — title variants plus common stack/tool pairings. */
|
/** Job-board search terms — title variants plus common stack/tool pairings. */
|
||||||
const ILIA_DOBKIN_CA_KEYWORD_TERMS = [
|
const SDET_CA_KEYWORD_TERMS = [
|
||||||
...ILIA_DOBKIN_CA_TARGET_ROLES.map((role) => role.toLowerCase()),
|
...SDET_CA_TARGET_ROLES.map((role) => role.toLowerCase()),
|
||||||
"playwright SDET",
|
"playwright SDET",
|
||||||
"SDET playwright",
|
"SDET playwright",
|
||||||
"SDET java",
|
"SDET java",
|
||||||
@ -78,14 +78,14 @@ const ILIA_DOBKIN_CA_KEYWORD_TERMS = [
|
|||||||
"software engineer test",
|
"software engineer test",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ILIA_DOBKIN_US_TARGET_ROLES = [
|
const SDET_US_TARGET_ROLES = [
|
||||||
...ILIA_DOBKIN_CA_TARGET_ROLES,
|
...SDET_CA_TARGET_ROLES,
|
||||||
"Computer Systems Analyst",
|
"Computer Systems Analyst",
|
||||||
"Quality Assurance Engineer",
|
"Quality Assurance Engineer",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ILIA_DOBKIN_US_KEYWORD_TERMS = [
|
const SDET_US_KEYWORD_TERMS = [
|
||||||
...ILIA_DOBKIN_CA_KEYWORD_TERMS,
|
...SDET_CA_KEYWORD_TERMS,
|
||||||
"computer systems analyst",
|
"computer systems analyst",
|
||||||
"systems analyst",
|
"systems analyst",
|
||||||
"computer systems analyst QA",
|
"computer systems analyst QA",
|
||||||
@ -99,7 +99,7 @@ const ILIA_DOBKIN_US_KEYWORD_TERMS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/** AI engineering / AI enablement — agents, MCP, RAG, evals, local LLM serving. */
|
/** AI engineering / AI enablement — agents, MCP, RAG, evals, local LLM serving. */
|
||||||
const ILIA_DOBKIN_AI_TARGET_ROLES = [
|
const AI_ENGINEER_TARGET_ROLES = [
|
||||||
"AI Engineer",
|
"AI Engineer",
|
||||||
"Senior AI Engineer",
|
"Senior AI Engineer",
|
||||||
"Staff AI Engineer",
|
"Staff AI Engineer",
|
||||||
@ -119,8 +119,8 @@ const ILIA_DOBKIN_AI_TARGET_ROLES = [
|
|||||||
"RAG Engineer",
|
"RAG Engineer",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ILIA_DOBKIN_AI_KEYWORD_TERMS = [
|
const AI_ENGINEER_KEYWORD_TERMS = [
|
||||||
...ILIA_DOBKIN_AI_TARGET_ROLES.map((role) => role.toLowerCase()),
|
...AI_ENGINEER_TARGET_ROLES.map((role) => role.toLowerCase()),
|
||||||
"LLM agents",
|
"LLM agents",
|
||||||
"MCP engineer",
|
"MCP engineer",
|
||||||
"LangGraph",
|
"LangGraph",
|
||||||
@ -919,12 +919,13 @@ const migrations = [
|
|||||||
SELECT 1 FROM keyword_sets WHERE owner_profile_id = '__default__'
|
SELECT 1 FROM keyword_sets WHERE owner_profile_id = '__default__'
|
||||||
)`,
|
)`,
|
||||||
|
|
||||||
// Seed default job-search personas (INSERT OR IGNORE — safe on existing DBs).
|
// Seed default job-search personas (INSERT OR IGNORE — safe on existing DBs;
|
||||||
|
// existing databases keep whatever profile data they already have).
|
||||||
sqlInsertSearchProfileSeed({
|
sqlInsertSearchProfileSeed({
|
||||||
id: "685b0000-0000-4000-8000-000000000001",
|
id: "685b0000-0000-4000-8000-000000000001",
|
||||||
name: "Ilia Dobkin",
|
name: "Demo User",
|
||||||
profile: {
|
profile: {
|
||||||
targetRoles: ILIA_DOBKIN_CA_TARGET_ROLES,
|
targetRoles: SDET_CA_TARGET_ROLES,
|
||||||
experienceLevel: "Senior",
|
experienceLevel: "Senior",
|
||||||
mustHaveSkills: [
|
mustHaveSkills: [
|
||||||
"Playwright",
|
"Playwright",
|
||||||
@ -957,9 +958,9 @@ const migrations = [
|
|||||||
industriesToTarget: ["Software", "FinTech", "iGaming", "Enterprise SaaS"],
|
industriesToTarget: ["Software", "FinTech", "iGaming", "Enterprise SaaS"],
|
||||||
industriesToAvoid: [],
|
industriesToAvoid: [],
|
||||||
aboutMe:
|
aboutMe:
|
||||||
"Ilia Dobkin — Senior SDET / test automation (Canada & remote). Paired login user `ilia` activates this profile and local resume ilia-dobkin.json (unset JOBOPS_LOCAL_RESUME_PATH so Settings path applies).",
|
"Demo User — Senior SDET / test automation (Canada & remote). Paired login user `demo` activates this profile and local resume demo-user.json (unset JOBOPS_LOCAL_RESUME_PATH so Settings path applies).",
|
||||||
basicAuthUser: "ilia,dobkin",
|
basicAuthUser: "demo,demo-user",
|
||||||
resumeLocalPath: "../data/resumes/ilia-dobkin.json",
|
resumeLocalPath: "../data/resumes/demo-user.json",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
`UPDATE keyword_sets
|
`UPDATE keyword_sets
|
||||||
@ -976,17 +977,12 @@ const migrations = [
|
|||||||
WHERE sp.id = keyword_sets.owner_profile_id
|
WHERE sp.id = keyword_sets.owner_profile_id
|
||||||
AND json_array_length(json_extract(sp.data, '$.targetRoles')) > 0
|
AND json_array_length(json_extract(sp.data, '$.targetRoles')) > 0
|
||||||
)`,
|
)`,
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.basicAuthUser', 'ilia,dobkin'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000001'
|
|
||||||
AND json_extract(data, '$.basicAuthUser') = 'ilia'`,
|
|
||||||
`INSERT INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
SELECT
|
SELECT
|
||||||
'ilia-dobkin-keyword-set',
|
'demo-sdet-keyword-set',
|
||||||
'685b0000-0000-4000-8000-000000000001',
|
'685b0000-0000-4000-8000-000000000001',
|
||||||
'SDET',
|
'SDET',
|
||||||
'${sqlJsonLiteral(ILIA_DOBKIN_CA_KEYWORD_TERMS)}',
|
'${sqlJsonLiteral(SDET_CA_KEYWORD_TERMS)}',
|
||||||
1,
|
1,
|
||||||
datetime('now'),
|
datetime('now'),
|
||||||
datetime('now')
|
datetime('now')
|
||||||
@ -1020,7 +1016,7 @@ const migrations = [
|
|||||||
)`,
|
)`,
|
||||||
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
'ilia-dobkin-caseware',
|
'demo-caseware',
|
||||||
'685b0000-0000-4000-8000-000000000001',
|
'685b0000-0000-4000-8000-000000000001',
|
||||||
'Caseware',
|
'Caseware',
|
||||||
'["Caseware","Caseware template developer","Caseware template specialist","Caseware engagement template","Caseware working papers","Caseware Assurance","Caseware consultant","CaseWare"]',
|
'["Caseware","Caseware template developer","Caseware template specialist","Caseware engagement template","Caseware working papers","Caseware Assurance","Caseware consultant","CaseWare"]',
|
||||||
@ -1028,13 +1024,9 @@ const migrations = [
|
|||||||
datetime('now'),
|
datetime('now'),
|
||||||
datetime('now')
|
datetime('now')
|
||||||
)`,
|
)`,
|
||||||
`UPDATE keyword_sets
|
|
||||||
SET terms = '["Caseware","Caseware template developer","Caseware template specialist","Caseware engagement template","Caseware working papers","Caseware Assurance","Caseware consultant","CaseWare"]',
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = 'ilia-dobkin-caseware'`,
|
|
||||||
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
'ilia-dobkin-lead',
|
'demo-lead',
|
||||||
'685b0000-0000-4000-8000-000000000001',
|
'685b0000-0000-4000-8000-000000000001',
|
||||||
'Lead',
|
'Lead',
|
||||||
'["lead SDET","lead QA","test lead","QA manager","engineering manager test"]',
|
'["lead SDET","lead QA","test lead","QA manager","engineering manager test"]',
|
||||||
@ -1045,7 +1037,7 @@ const migrations = [
|
|||||||
`ALTER TABLE jobs ADD COLUMN sponsorship_signals TEXT`,
|
`ALTER TABLE jobs ADD COLUMN sponsorship_signals TEXT`,
|
||||||
sqlInsertSearchProfileSeed({
|
sqlInsertSearchProfileSeed({
|
||||||
id: "685b0000-0000-4000-8000-000000000002",
|
id: "685b0000-0000-4000-8000-000000000002",
|
||||||
name: "Iliya Cherepaha",
|
name: "Demo User (QA)",
|
||||||
profile: {
|
profile: {
|
||||||
targetRoles: [
|
targetRoles: [
|
||||||
"Senior QA Analyst",
|
"Senior QA Analyst",
|
||||||
@ -1080,26 +1072,16 @@ const migrations = [
|
|||||||
],
|
],
|
||||||
industriesToAvoid: [],
|
industriesToAvoid: [],
|
||||||
aboutMe:
|
aboutMe:
|
||||||
"Iliya Cherepaha — Senior QA (Guidewire, OPS, accessibility); paired login user `cherepaha` activates this profile and local resume cherepaha.json (unset JOBOPS_LOCAL_RESUME_PATH so Settings path applies).",
|
"Demo User (QA) — Senior QA (Guidewire, accessibility, UAT); paired login user `demo-qa` activates this profile and local resume demo-qa.json (unset JOBOPS_LOCAL_RESUME_PATH so Settings path applies).",
|
||||||
basicAuthUser: "cherepaha",
|
basicAuthUser: "demo-qa",
|
||||||
resumeLocalPath: "../data/resumes/cherepaha.json",
|
resumeLocalPath: "../data/resumes/demo-qa.json",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.resumeLocalPath', '../data/resumes/ilia-dobkin.json'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000001'
|
|
||||||
AND coalesce(json_extract(data, '$.resumeLocalPath'), '') = ''`,
|
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.resumeLocalPath', '../data/resumes/cherepaha.json'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000002'
|
|
||||||
AND coalesce(json_extract(data, '$.resumeLocalPath'), '') = ''`,
|
|
||||||
sqlInsertSearchProfileSeed({
|
sqlInsertSearchProfileSeed({
|
||||||
id: "685b0000-0000-4000-8000-000000000003",
|
id: "685b0000-0000-4000-8000-000000000003",
|
||||||
name: "Ilia Dobkin (US)",
|
name: "Demo User (US)",
|
||||||
profile: {
|
profile: {
|
||||||
targetRoles: ILIA_DOBKIN_US_TARGET_ROLES,
|
targetRoles: SDET_US_TARGET_ROLES,
|
||||||
experienceLevel: "Senior",
|
experienceLevel: "Senior",
|
||||||
mustHaveSkills: [
|
mustHaveSkills: [
|
||||||
"Playwright",
|
"Playwright",
|
||||||
@ -1130,46 +1112,22 @@ const migrations = [
|
|||||||
],
|
],
|
||||||
industriesToAvoid: [],
|
industriesToAvoid: [],
|
||||||
aboutMe:
|
aboutMe:
|
||||||
"Ilia Dobkin (US) — Senior SDET / QA automation; Canadian citizen, TN-eligible (USMCA), open to U.S. relocation. Computer Systems Analyst-aligned framing. Switch to this profile in the Jobs page picker (same login as Canada).",
|
"Demo User (US) — Senior SDET / QA automation targeting U.S. remote roles. Computer Systems Analyst-aligned framing. Switch to this profile in the Jobs page picker (same login as Canada).",
|
||||||
basicAuthUser: "ilia,dobkin",
|
basicAuthUser: "demo,demo-user",
|
||||||
resumeLocalPath: "../data/resumes/ilia-dobkin-us.json",
|
resumeLocalPath: "../data/resumes/demo-user-us.json",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.targetRoles', '${sqlJsonLiteral(ILIA_DOBKIN_CA_TARGET_ROLES)}'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000001'`,
|
|
||||||
`UPDATE keyword_sets
|
|
||||||
SET terms = '${sqlJsonLiteral(ILIA_DOBKIN_CA_KEYWORD_TERMS)}',
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = 'ilia-dobkin-keyword-set'`,
|
|
||||||
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
'ilia-dobkin-us-keyword-set',
|
'demo-sdet-us-keyword-set',
|
||||||
'685b0000-0000-4000-8000-000000000003',
|
'685b0000-0000-4000-8000-000000000003',
|
||||||
'SDET',
|
'SDET',
|
||||||
'${sqlJsonLiteral(ILIA_DOBKIN_US_KEYWORD_TERMS)}',
|
'${sqlJsonLiteral(SDET_US_KEYWORD_TERMS)}',
|
||||||
1,
|
1,
|
||||||
datetime('now'),
|
datetime('now'),
|
||||||
datetime('now')
|
datetime('now')
|
||||||
)`,
|
)`,
|
||||||
`UPDATE search_profiles
|
// Remove duplicate seed profiles left by repository tests (same names, test UUIDs).
|
||||||
SET data = json_set(
|
|
||||||
json_set(data, '$.basicAuthUser', 'ilia,dobkin'),
|
|
||||||
'$.aboutMe',
|
|
||||||
'Ilia Dobkin (US) — Senior SDET / QA automation; Canadian citizen, TN-eligible (USMCA), open to U.S. relocation. Computer Systems Analyst-aligned framing. Switch to this profile in the Jobs page picker (same login as Canada).'
|
|
||||||
),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000003'`,
|
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.targetRoles', '${sqlJsonLiteral(ILIA_DOBKIN_US_TARGET_ROLES)}'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000003'`,
|
|
||||||
`UPDATE keyword_sets
|
|
||||||
SET terms = '${sqlJsonLiteral(ILIA_DOBKIN_US_KEYWORD_TERMS)}',
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = 'ilia-dobkin-us-keyword-set'`,
|
|
||||||
// Remove duplicate Ilia profiles left by repository tests (same names, test UUIDs).
|
|
||||||
`DELETE FROM keyword_sets
|
`DELETE FROM keyword_sets
|
||||||
WHERE owner_profile_id IN (
|
WHERE owner_profile_id IN (
|
||||||
'685b0000-0000-4000-8000-000000009901',
|
'685b0000-0000-4000-8000-000000009901',
|
||||||
@ -1183,9 +1141,9 @@ const migrations = [
|
|||||||
// AI engineering profile — agents, MCP, RAG, evals (paired with same login as Canada/US).
|
// AI engineering profile — agents, MCP, RAG, evals (paired with same login as Canada/US).
|
||||||
sqlInsertSearchProfileSeed({
|
sqlInsertSearchProfileSeed({
|
||||||
id: "685b0000-0000-4000-8000-000000000004",
|
id: "685b0000-0000-4000-8000-000000000004",
|
||||||
name: "Ilia Dobkin (AI)",
|
name: "Demo User (AI)",
|
||||||
profile: {
|
profile: {
|
||||||
targetRoles: ILIA_DOBKIN_AI_TARGET_ROLES,
|
targetRoles: AI_ENGINEER_TARGET_ROLES,
|
||||||
experienceLevel: "Senior",
|
experienceLevel: "Senior",
|
||||||
mustHaveSkills: [
|
mustHaveSkills: [
|
||||||
"Python",
|
"Python",
|
||||||
@ -1226,59 +1184,33 @@ const migrations = [
|
|||||||
],
|
],
|
||||||
industriesToAvoid: [],
|
industriesToAvoid: [],
|
||||||
aboutMe:
|
aboutMe:
|
||||||
"Ilia Dobkin (AI) — AI Automation Engineer / LLM agents, MCP, RAG & evals; AI enablement lead experience. Switch to this profile for AI-role discovery (same login as Canada/US). Resume: ilia-dobkin-ai.json.",
|
"Demo User (AI) — AI Automation Engineer / LLM agents, MCP, RAG & evals; AI enablement lead experience. Switch to this profile for AI-role discovery (same login as Canada/US). Resume: demo-user-ai.json.",
|
||||||
basicAuthUser: "ilia,dobkin",
|
basicAuthUser: "demo,demo-user",
|
||||||
resumeLocalPath: "../data/resumes/ilia-dobkin-ai.json",
|
resumeLocalPath: "../data/resumes/demo-user-ai.json",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
'ilia-dobkin-ai-keyword-set',
|
'demo-ai-keyword-set',
|
||||||
'685b0000-0000-4000-8000-000000000004',
|
'685b0000-0000-4000-8000-000000000004',
|
||||||
'AI Engineer',
|
'AI Engineer',
|
||||||
'${sqlJsonLiteral(ILIA_DOBKIN_AI_KEYWORD_TERMS)}',
|
'${sqlJsonLiteral(AI_ENGINEER_KEYWORD_TERMS)}',
|
||||||
1,
|
1,
|
||||||
datetime('now'),
|
datetime('now'),
|
||||||
datetime('now')
|
datetime('now')
|
||||||
)`,
|
)`,
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(
|
|
||||||
json_set(
|
|
||||||
json_set(data, '$.basicAuthUser', 'ilia,dobkin'),
|
|
||||||
'$.resumeLocalPath',
|
|
||||||
'../data/resumes/ilia-dobkin-ai.json'
|
|
||||||
),
|
|
||||||
'$.aboutMe',
|
|
||||||
'Ilia Dobkin (AI) — AI Automation Engineer / LLM agents, MCP, RAG & evals; AI enablement lead experience. Switch to this profile for AI-role discovery (same login as Canada/US). Resume: ilia-dobkin-ai.json.'
|
|
||||||
),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000004'`,
|
|
||||||
`UPDATE search_profiles
|
|
||||||
SET data = json_set(data, '$.targetRoles', '${sqlJsonLiteral(ILIA_DOBKIN_AI_TARGET_ROLES)}'),
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = '685b0000-0000-4000-8000-000000000004'`,
|
|
||||||
`UPDATE keyword_sets
|
|
||||||
SET terms = '${sqlJsonLiteral(ILIA_DOBKIN_AI_KEYWORD_TERMS)}',
|
|
||||||
name = 'AI Engineer',
|
|
||||||
is_active = 1,
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = 'ilia-dobkin-ai-keyword-set'`,
|
|
||||||
// Also add AI Engineer as an inactive keyword set on the Canada SDET profile
|
// Also add AI Engineer as an inactive keyword set on the Canada SDET profile
|
||||||
// (same pattern as Caseware / Lead) so it can be flipped without switching profiles.
|
// (same pattern as Caseware / Lead) so it can be flipped without switching profiles.
|
||||||
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
`INSERT OR IGNORE INTO keyword_sets (id, owner_profile_id, name, terms, is_active, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
'ilia-dobkin-ai',
|
'demo-ai',
|
||||||
'685b0000-0000-4000-8000-000000000001',
|
'685b0000-0000-4000-8000-000000000001',
|
||||||
'AI Engineer',
|
'AI Engineer',
|
||||||
'${sqlJsonLiteral(ILIA_DOBKIN_AI_KEYWORD_TERMS)}',
|
'${sqlJsonLiteral(AI_ENGINEER_KEYWORD_TERMS)}',
|
||||||
0,
|
0,
|
||||||
datetime('now'),
|
datetime('now'),
|
||||||
datetime('now')
|
datetime('now')
|
||||||
)`,
|
)`,
|
||||||
`UPDATE keyword_sets
|
|
||||||
SET terms = '${sqlJsonLiteral(ILIA_DOBKIN_AI_KEYWORD_TERMS)}',
|
|
||||||
updated_at = datetime('now')
|
|
||||||
WHERE id = 'ilia-dobkin-ai'`,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
console.log("🔧 Running database migrations...");
|
console.log("🔧 Running database migrations...");
|
||||||
|
|||||||
@ -45,7 +45,7 @@ describe("profiles repository", () => {
|
|||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
...sharedProfileData,
|
...sharedProfileData,
|
||||||
preferredLocations: ["Canada"],
|
preferredLocations: ["Canada"],
|
||||||
resumeLocalPath: "../data/resumes/ilia-dobkin.json",
|
resumeLocalPath: "../data/resumes/demo-user.json",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -54,16 +54,20 @@ describe("profiles repository", () => {
|
|||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
...sharedProfileData,
|
...sharedProfileData,
|
||||||
preferredLocations: ["United States"],
|
preferredLocations: ["United States"],
|
||||||
resumeLocalPath: "../data/resumes/ilia-dobkin-us.json",
|
resumeLocalPath: "../data/resumes/demo-user-us.json",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("matches comma-separated basic auth aliases", () => {
|
it("matches comma-separated basic auth aliases", () => {
|
||||||
expect(profileMatchesBasicAuthUser("ilia,dobkin", "ILIA")).toBe(true);
|
expect(profileMatchesBasicAuthUser("demo,demo-user", "DEMO")).toBe(true);
|
||||||
expect(profileMatchesBasicAuthUser("ilia,dobkin", "dobkin")).toBe(true);
|
expect(profileMatchesBasicAuthUser("demo,demo-user", "demo-user")).toBe(
|
||||||
expect(profileMatchesBasicAuthUser("ilia,dobkin", "cherepaha")).toBe(false);
|
true,
|
||||||
|
);
|
||||||
|
expect(profileMatchesBasicAuthUser("demo,demo-user", "someone-else")).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lists every profile visible to the login", async () => {
|
it("lists every profile visible to the login", async () => {
|
||||||
|
|||||||
@ -152,7 +152,7 @@ function basicAuthAliases(basicAuthUser: string | null | undefined): string[] {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* When one login maps to multiple search profiles, remember which profile is active.
|
* When one login maps to multiple search profiles, remember which profile is active.
|
||||||
* Writes the same profile id for every alias on that profile (e.g. ilia + dobkin).
|
* Writes the same profile id for every alias on that profile (e.g. demo + demo-user).
|
||||||
*/
|
*/
|
||||||
export async function setActiveSearchProfileIdForBasicAuthUser(
|
export async function setActiveSearchProfileIdForBasicAuthUser(
|
||||||
username: string,
|
username: string,
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
#
|
|
||||||
# Jobber cron env — cherepaha
|
|
||||||
# Copy to /root/.jobber-cron-cherepaha.env (chmod 600)
|
|
||||||
#
|
|
||||||
# Used by: scripts/jobber-pipeline-telegram.sh
|
|
||||||
#
|
|
||||||
|
|
||||||
# JobOps base URL (where the app is reachable from the cron host)
|
|
||||||
JOBOPS_URL=http://127.0.0.1:3005
|
|
||||||
|
|
||||||
# Optional: limit number of jobs linked in Telegram message
|
|
||||||
JOB_TELEGRAM_MAX_JOBS=25
|
|
||||||
|
|
||||||
# Optional: comma-separated sources to run (leave empty to use server defaults)
|
|
||||||
# JOBBER_PIPELINE_SOURCES=adzuna,gradcracker,ukvisajobs
|
|
||||||
|
|
||||||
# App-level Basic Auth (enables per-user separation when set on the server)
|
|
||||||
BASIC_AUTH_USER=cherepaha
|
|
||||||
BASIC_AUTH_PASSWORD=CHANGEME
|
|
||||||
|
|
||||||
# Telegram bot + chat destination
|
|
||||||
TELEGRAM_BOT_TOKEN=CHANGEME
|
|
||||||
TELEGRAM_CHAT_ID=CHANGEME
|
|
||||||
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#
|
|
||||||
# Jobber cron env — dobkin (AI Engineer)
|
|
||||||
# Copy to /root/.jobber-cron-dobkin-ai.env (chmod 600)
|
|
||||||
#
|
|
||||||
# Used by: scripts/jobber-pipeline-telegram.sh
|
|
||||||
# Activate profile "Ilia Dobkin (AI)" in the Jobs UI (or via API) before cron,
|
|
||||||
# or pass the owner profile in your pipeline wrapper if supported.
|
|
||||||
#
|
|
||||||
|
|
||||||
# JobOps base URL (where the app is reachable from the cron host)
|
|
||||||
JOBOPS_URL=http://127.0.0.1:3005
|
|
||||||
|
|
||||||
# Optional: limit number of jobs linked in Telegram message
|
|
||||||
JOB_TELEGRAM_MAX_JOBS=25
|
|
||||||
|
|
||||||
# Optional: comma-separated sources to run (leave empty to use server defaults)
|
|
||||||
# JOBBER_PIPELINE_SOURCES=adzuna,gradcracker,ukvisajobs
|
|
||||||
|
|
||||||
# App-level Basic Auth (enables per-user separation when set on the server)
|
|
||||||
BASIC_AUTH_USER=dobkin
|
|
||||||
BASIC_AUTH_PASSWORD=CHANGEME
|
|
||||||
|
|
||||||
# Telegram bot + chat destination
|
|
||||||
TELEGRAM_BOT_TOKEN=CHANGEME
|
|
||||||
TELEGRAM_CHAT_ID=CHANGEME
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#
|
|
||||||
# Jobber cron env — U.S. pipeline (optional separate cron host)
|
|
||||||
# Copy to /root/.jobber-cron-dobkin-us.env (chmod 600)
|
|
||||||
#
|
|
||||||
# Note: the U.S. profile is also available in the UI under the same ilia/dobkin
|
|
||||||
# login — use the Jobs page profile picker to switch. This env file is only
|
|
||||||
# needed if you want a dedicated cron that always runs the U.S. profile without
|
|
||||||
# switching in the UI (set BASIC_AUTH_ACTIVE_PROFILE_BY_USER or activate once).
|
|
||||||
#
|
|
||||||
# Used by: scripts/jobber-pipeline-telegram.sh
|
|
||||||
#
|
|
||||||
|
|
||||||
# JobOps base URL (where the app is reachable from the cron host)
|
|
||||||
JOBOPS_URL=http://127.0.0.1:3005
|
|
||||||
|
|
||||||
# Optional: limit number of jobs linked in Telegram message
|
|
||||||
JOB_TELEGRAM_MAX_JOBS=25
|
|
||||||
|
|
||||||
# Optional: comma-separated sources to run (leave empty to use server defaults)
|
|
||||||
# JOBBER_PIPELINE_SOURCES=usajobs,adzuna,remoteok,remotive
|
|
||||||
|
|
||||||
# Same login as Canada; activate the U.S. profile once in Settings/Jobs picker,
|
|
||||||
# or set basicAuthActiveProfileByUser in the DB for this user.
|
|
||||||
BASIC_AUTH_USER=dobkin
|
|
||||||
BASIC_AUTH_PASSWORD=CHANGEME
|
|
||||||
|
|
||||||
# Telegram bot + chat destination
|
|
||||||
TELEGRAM_BOT_TOKEN=CHANGEME
|
|
||||||
TELEGRAM_CHAT_ID=CHANGEME
|
|
||||||
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
#
|
|
||||||
# Jobber cron env — dobkin
|
|
||||||
# Copy to /root/.jobber-cron-dobkin.env (chmod 600)
|
|
||||||
#
|
|
||||||
# Used by: scripts/jobber-pipeline-telegram.sh
|
|
||||||
#
|
|
||||||
|
|
||||||
# JobOps base URL (where the app is reachable from the cron host)
|
|
||||||
JOBOPS_URL=http://127.0.0.1:3005
|
|
||||||
|
|
||||||
# Optional: limit number of jobs linked in Telegram message
|
|
||||||
JOB_TELEGRAM_MAX_JOBS=25
|
|
||||||
|
|
||||||
# Optional: comma-separated sources to run (leave empty to use server defaults)
|
|
||||||
# JOBBER_PIPELINE_SOURCES=adzuna,gradcracker,ukvisajobs
|
|
||||||
|
|
||||||
# App-level Basic Auth (enables per-user separation when set on the server)
|
|
||||||
BASIC_AUTH_USER=dobkin
|
|
||||||
BASIC_AUTH_PASSWORD=CHANGEME
|
|
||||||
|
|
||||||
# Telegram bot + chat destination
|
|
||||||
TELEGRAM_BOT_TOKEN=CHANGEME
|
|
||||||
TELEGRAM_CHAT_ID=CHANGEME
|
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ JOBOPS_URL="http://127.0.0.1:3005"
|
|||||||
# Canada + QA automation + fully remote (see JOBBER_CRON_* below):
|
# Canada + QA automation + fully remote (see JOBBER_CRON_* below):
|
||||||
# JOBBER_PIPELINE_SOURCES=linkedin,indeed,glassdoor,qajobsboard,arcdev,eluta,bctenet
|
# JOBBER_PIPELINE_SOURCES=linkedin,indeed,glassdoor,qajobsboard,arcdev,eluta,bctenet
|
||||||
|
|
||||||
# Optional: applied via PATCH /api/settings immediately before each scheduled run (ilia profile when BASIC_AUTH_USER=ilia).
|
# Optional: applied via PATCH /api/settings immediately before each scheduled run (matching profile when BASIC_AUTH_USER is set).
|
||||||
# JOBBER_CRON_SEARCH_CITIES=Canada
|
# JOBBER_CRON_SEARCH_CITIES=Canada
|
||||||
# JOBBER_CRON_JOBSPY_COUNTRY=Canada
|
# JOBBER_CRON_JOBSPY_COUNTRY=Canada
|
||||||
# JOBBER_CRON_WORKPLACE_TYPES=remote
|
# JOBBER_CRON_WORKPLACE_TYPES=remote
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user