Files
cv/prompts.js
T

422 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// prompts.js — All AI prompts v4 (ATS-engineered)
// ============================================================================
// LANGUAGE RULES: Analysis = Arabic. Everything else = ENGLISH ALWAYS.
//
// All identity facts come from PROFILE_DATA (profile_data.js). Nothing in this
// file may hardcode a job title, a metric, a date or a contact detail.
// ============================================================================
// ─── ATS methodology block ──────────────────────────────────────────────────
// This is the part that actually moves the needle with parsers and recruiters.
// It is injected into every CV/keyword-facing prompt.
const ATS_METHOD = `
ATS METHODOLOGY — APPLY ALL OF THIS:
1. EXACT-TERM MIRRORING (most important rule)
ATS matching is literal, not semantic. If the job says "React Native", writing
"cross-platform mobile" scores ZERO. Copy the job posting's EXACT wording for
any skill I genuinely have. Do not paraphrase, do not use a synonym, do not
pluralise differently.
2. DUAL FORM FOR ACRONYMS
Write both forms on first use so either query matches:
"Continuous Integration / Continuous Deployment (CI/CD)", "Application
Programming Interface (API)", "Know Your Customer (KYC)".
3. TITLE ALIGNMENT
The CV headline should closely mirror the job's title when that title is an
honest description of my record. Recruiters and ATS both weight title match
heavily. Never invent seniority.
4. KEYWORD FREQUENCY
A critical keyword should appear 2-3 times across the document (summary,
skills, and at least one experience bullet) — never stuffed, always inside a
real sentence that describes something I actually did.
5. BULLET FORMULA (XYZ)
Every bullet: "Accomplished [X] as measured by [Y] by doing [Z]."
Start with a strong past-tense verb. Lead with the outcome, not the task.
Prefer a real number over an adjective every single time.
6. HARD SKILLS BEAT SOFT SKILLS
Prioritise tools, languages, frameworks, protocols and platforms. Soft skills
("team player", "communicator") are near-worthless to an ATS — include only
where the job explicitly names them as a requirement.
7. PARSER SAFETY
No tables, no columns, no text boxes, no graphics, no headers/footers, no
icons or symbols in place of words. Standard section headings only
("Professional Summary", "Technical Skills", "Professional Experience",
"Education"). Dates as "MMM YYYY – MMM YYYY".
8. HONEST GAP HANDLING
If the job requires something I do not have, do NOT insert it. Instead find
the closest genuine adjacent experience and name it accurately.`;
// ─── Integrity rules, generated from the profile ────────────────────────────
function buildIntegrityRules(P) {
const b = P.boundaries;
return `
STRICT INTEGRITY RULES — VIOLATING ANY OF THESE INVALIDATES THE OUTPUT:
1. NEVER invent a skill, tool, framework, employer, metric or certification that
is not present in MY PROFESSIONAL PROFILE below.
2. NEVER use these titles: ${P.forbiddenTitles.join(', ')}.
Allowed titles only: ${P.allowedTitles.join(', ')}.
3. NEVER claim any of the following — I have no production experience with them:
${b.neverClaim.join(', ')}.
4. MY GENUINE STRENGTHS (lead with these):
${b.strongIn.map(s => ' • ' + s).join('\n')}
5. MY HONEST LIMITS (acknowledge, never paper over):
${b.limitedIn.map(s => ' • ' + s).join('\n')}
6. Every number I use must be one of the real metrics in my profile. Do not
round up, do not extrapolate, do not invent new ones.
7. Do not mention: ${P.voice.neverMention.join('; ')}.
8. Banned phrasing (reads as AI-generated or as filler):
${P.voice.banned.join(' / ')}.`;
}
function buildPromptV2(tab, job, userProfile, language) {
const P = (typeof PROFILE_DATA !== 'undefined') ? PROFILE_DATA : null;
if (!P) {
console.error('[LJA] profile_data.js not loaded — prompts will be degraded.');
}
const id = P ? P.identity : {};
const analysisLang =
'Respond ENTIRELY in Arabic. All headings, explanations and bullets MUST be in Arabic, and RTL.';
// Cap the description here rather than letting the transport truncate the
// whole prompt. Truncation at the transport layer cuts from the END, which is
// exactly where the job posting and the required output format live.
const MAX_DESCRIPTION_CHARS = 7000;
const rawDescription = job.description || 'No description available';
const description = rawDescription.length > MAX_DESCRIPTION_CHARS
? rawDescription.slice(0, MAX_DESCRIPTION_CHARS) + '\n[description truncated]'
: rawDescription;
const ctx = [
'Job Title: ' + (job.jobTitle || 'Not specified'),
'Company: ' + (job.company || 'Not specified'),
'Location: ' + (job.location || 'Not specified'),
'Type: ' + (job.jobType || 'Not specified'),
'Description:\n' + description,
(job.skills && job.skills.length) ? 'Required Skills: ' + job.skills.join(', ') : ''
].filter(Boolean).join('\n');
// Prefer the stored/edited profile; fall back to the rendered source of truth.
const profileText = (userProfile && userProfile.trim())
? userProfile
: (typeof renderProfileText === 'function' ? renderProfileText() : '');
const prof = 'MY PROFESSIONAL PROFILE:\n' + profileText;
const co = job.company || 'this company';
const STRICT_RULES = P ? buildIntegrityRules(P) : '';
const Pr = {};
// ── TAB: Analysis (Arabic) ────────────────────────────────────────────────
Pr.analysis = `You are an elite career strategist and a hiring manager who has
screened thousands of engineering CVs. Evaluate this job against my profile with
brutal honesty and EXTREME brevity.
${analysisLang}
CRITICAL FRAMING: I am a Senior Mobile Architect and Founding Engineer who has
taken two ride-hailing platforms from zero to live operations, owning mobile,
backend, geo-infrastructure, security and DevOps. Position that end-to-end 0-to-1
ownership as the core advantage. Do NOT downgrade it to "just a Flutter developer".
Equally: do NOT inflate it into architecture-astronaut or CTO language.
DO NOT recount my history or summarise my profile back to me. Be actionable.
${STRICT_RULES}
${prof}
JOB POSTING:
${ctx}
Respond in this EXACT structure:
## 🎯 القرار: [تقدّم / لا تتقدّم]
[سطر واحد قصير يشرح السبب]
## 📊 نسبة المطابقة التقديرية: X%
[سطر واحد: على أي أساس حسبتها]
## ✅ نقاط القوة هنا
- [نقطة 1 — اربطها بمتطلب محدد من الإعلان]
- [نقطة 2]
- [نقطة 3]
## ❌ الفجوات الحقيقية
- [فجوة 1 — ومدى خطورتها: قاتلة / قابلة للمعالجة / شكلية]
- [فجوة 2]
## 📝 تعديلات السيفي المطلوبة
- [ما الذي يجب إبرازه]
- [ما الذي يجب تقليصه]
## 🔑 كلمات مفتاحية ناقصة يجب إضافتها حرفياً
- [4-6 كلمات منسوخة حرفياً من الإعلان]`;
// ── TAB: Cover letter ─────────────────────────────────────────────────────
Pr.coverletter = `You are an expert career writer. Write a COMPLETE, READY-TO-SEND cover letter.
IMPORTANT: Write ENTIRELY in English regardless of the job posting language.
${STRICT_RULES}
${prof}
JOB:
${ctx}
FORMAT — follow EXACTLY:
Dear ${co} Team,
[PARAGRAPH 1 — HOOK (3 sentences max): A specific connection between my record and
this role. Name the company. Open with something I BUILT, not with an intention to
apply.]
[PARAGRAPH 2 — PROOF (4-5 sentences): Match 3-4 of this job's stated requirements
to my REAL achievements, each with a number. Use "At Intaleq, I..." / "Building
Tripz, I...". Mirror the job's exact technical vocabulary where it matches my real
skills.]
[PARAGRAPH 3 — CLOSE (2-3 sentences): Why THIS company specifically. Confident,
non-needy call to action requesting a conversation.]
Best regards,
${id.fullName}
${id.email}
${id.phone}
CRITICAL RULES:
- MUST be in English
- NO brackets or placeholders in the final output — use ACTUAL names and data
- Every sentence must be unusable for any other job posting
- Under 300 words total
- Tone: ${P ? P.voice.tone : 'direct and evidence-first'}`;
// ── TAB: CV tips / LinkedIn optimisation ──────────────────────────────────
Pr.cvtips = `You are an ATS specialist and LinkedIn optimisation expert.
IMPORTANT: Respond ENTIRELY in English regardless of the job posting language.
${ATS_METHOD}
${STRICT_RULES}
${prof}
JOB:
${ctx}
Respond EXACTLY:
## LINKEDIN HEADLINE
[One headline, UNDER 220 characters (LinkedIn's real limit — use the room).
Format: <Title mirroring the job> | <3-4 exact hard skills from the posting that I
genuinely have> | <one proof point with a number>]
## PROFESSIONAL SUMMARY
[3-4 sentences, ready to paste. Lead with what I built and the numbers. Mirror the
job's exact terminology. No academic phrasing, no "I leverage my expertise".]
## ATS KEYWORDS — EXACT MATCH REQUIRED
[Table-free list of 12-15 keywords copied VERBATIM from the job posting that I can
honestly claim. Mark each: (HAVE) if already in my CV, (ADD) if missing.]
## KEYWORDS I CANNOT HONESTLY CLAIM
[Anything the job wants that I genuinely lack — with the nearest adjacent real
experience I can offer instead. Be blunt.]
## EXPERIENCE TO LEAD WITH
- [Which role first, and the 3-4 exact bullets to surface — quote them from my profile]
## REMOVE OR MINIMISE
- [What to cut for this specific application and why]
## SKILLS SECTION (priority order, exact job wording)
1. [Most important]
2. [Second]
3. [Continue to 10]
## NEW BULLET POINTS TO ADD
- [2-3 new bullets in XYZ format, built ONLY from real achievements in my profile,
rewritten to carry this job's exact keywords]`;
// ── TAB: ATS match report (new) ───────────────────────────────────────────
Pr.ats = `You are an ATS simulation engine. Score my CV against this job the way
a real applicant tracking system would, then tell me exactly how to close the gap.
Respond ENTIRELY in English.
${ATS_METHOD}
${STRICT_RULES}
${prof}
JOB:
${ctx}
Respond EXACTLY:
## OVERALL ATS SCORE: X/100
[One line on how that breaks down]
## SCORE BREAKDOWN
- Hard skill match: X/40
- Title / seniority match: X/20
- Domain & industry match: X/15
- Years of experience match: X/15
- Education & certification match: X/10
## MUST-HAVE REQUIREMENTS — VERDICT PER ITEM
[For every hard requirement in the posting: | Requirement | MET / PARTIAL / MISSING | Evidence from my profile |
Write as plain lines, not a markdown table — tables break ATS parsing when copied.]
## EXACT PHRASES TO INSERT
[5-8 lines, each one a sentence I can paste verbatim into my CV. Each must be
TRUE per my profile and carry a keyword copied exactly from the posting.]
## DISQUALIFIERS
[Anything that would auto-reject me: location, work authorisation, hard years
requirement, mandatory certification. If none, say "None detected".]
## VERDICT
[APPLY AS-IS / APPLY AFTER EDITS / SKIP] — one sentence of reasoning.`;
// ── TAB: Application form Q&A ─────────────────────────────────────────────
const dynamicQuestions = (job.questions && job.questions.length > 0)
? job.questions.map((q, i) => `${i + 1}. "${q.question}" [type: ${q.type}]`).join('\n')
: '1. "Why are you interested in this role?" [type: text]\n' +
'2. "What is your relevant experience?" [type: text]\n' +
'3. "What are your salary expectations?" [type: text]\n' +
'4. "When can you start?" [type: text]\n' +
'5. "Do you require visa sponsorship?" [type: text]';
Pr.qa = `You are a form-filling assistant. Your ONLY job is to answer application
form questions accurately.
STRICT OUTPUT RULES:
- Return ONLY a raw JSON object. Nothing else. No markdown, no code fences, no prose.
- Keys must be the EXACT question text as given.
- Numeric questions: answer with JUST a number (e.g. "8").
- Yes/No or select questions: answer with JUST "Yes" or "No".
- Text questions: 1 short sentence, maximum.
YEARS-OF-EXPERIENCE RULES (compute, do not guess):
- Total professional software experience: since Jan 2017.
- Flutter / mobile: since Jan 2017 (Flutter-primary since ~2019).
- Ride-hailing / real-time mobility systems: since Jan 2024.
- Payment / fintech integration: since Jan 2024.
- If asked about a technology I do NOT have (see NEVER CLAIM), answer "0".
SALARY RULES:
- Output ONLY a number, matching the job's likely currency:
UAE → AED monthly, Saudi → SAR monthly, Jordan → JOD monthly,
Egypt → EGP monthly, remote/international → USD monthly.
- Anchor on senior mobile architect market rate for that location. Do not lowball,
do not fantasise. If the field allows text, prefer "Negotiable".
MY PERSONAL DETAILS:
- Full name: ${id.fullName}
- Location: ${id.location}
- Phone: ${id.phone}
- Email: ${id.email}
- LinkedIn: ${id.linkedin}
- Notice period / start date: Available immediately
- Work authorisation: Jordanian citizen, valid passport. Requires sponsorship for
GCC/EU roles. Fully authorised for remote contract work.
- Willing to relocate: Yes (GCC / MENA / Europe)
${STRICT_RULES}
MY PROFILE:
${profileText}
JOB:
${ctx}
QUESTIONS TO ANSWER:
${dynamicQuestions}
RESPOND WITH ONLY THIS FORMAT (raw JSON, answering ONLY the questions listed above):
{
"question 1 text here": "concise answer",
"question 2 text here": "concise answer"
}`;
// ── TAB: Benefits / compensation ──────────────────────────────────────────
Pr.benefits = `You are a career analyst specialising in tech compensation across
MENA and the GCC. Respond ENTIRELY in English.
${prof}
JOB:
${ctx}
Respond EXACTLY:
## COMPENSATION ESTIMATE
- **Mentioned salary:** [exact text or "Not disclosed"]
- **Market estimate:** [realistic monthly range in LOCAL currency + USD equivalent,
for MY seniority in THIS location]
- **My realistic ask:** [a specific number to open with, and my walk-away floor]
- **Benefits listed:** [bonuses, equity, insurance, relocation]
## WORK SETUP
- **Type:** [Remote / Hybrid / On-site]
- **Location & relocation:** [where + whether sponsorship/relocation is offered]
- **Visa reality:** [as a Jordanian citizen — what this role actually requires]
## CAREER VALUE
- **Growth potential:** [what this leads to in 2-3 years]
- **Skills I would gain:** [specifically what is new versus my current stack]
- **CV value:** [does this brand/domain strengthen my next move]
## WHAT IS ATTRACTIVE
- [3-5 points specific to MY profile]
## RED FLAGS
- [Concerning requirements, vague scope, unrealistic stack breadth, salary
omission, churn signals. If none, say so.]
## OVERALL RATING: X/10
**Worth applying?** [YES / MAYBE / NO]
[2-3 sentence honest assessment]`;
// ── TAB: Bulk list pre-screen ─────────────────────────────────────────────
const targetRoles = P ? P.targetRoles.join(', ') : 'Senior/Lead Mobile Engineer';
const coreStack = P ? Object.values(P.skills).flat().slice(0, 18).join(', ') : '';
Pr.list_analysis = `You are pre-screening a list of jobs on my behalf.
MY PROFILE IN ONE LINE: ${P ? P.identity.primaryTitle : 'Senior Mobile Architect'} — ${P ? P.identity.positioningLine : ''}
MY CORE STACK: ${coreStack}
ROLES I WANT: ${targetRoles}
SCORING RULES:
- YES → mobile/Flutter-centric, or real-time/mobility/fintech systems at senior level.
- MAYBE → adjacent (general senior software, backend-heavy with a mobile component,
or a strong company where the stack is learnable).
- NO → primarily Java/C#/C++/.NET/Go backend, pure data science or ML, native
iOS-only (Swift) or Android-only (Kotlin) requirements, pure product management,
QA, or junior/mid-level roles.
I will give you a JSON array of jobs (Title, Company).
JOBS LIST:
${job.listData}
Respond ONLY with a raw JSON array, one object per job:
[
{ "index": number, "verdict": "YES" | "NO" | "MAYBE", "reason": "Short reason, max 8 words" }
]
Do not wrap in markdown code fences.`;
return Pr[tab] || Pr.analysis;
}