Auto-deploy: 2026-08-05 16:58:10

This commit is contained in:
Hamza-Ayed
2026-08-05 16:58:10 +03:00
parent 2ca5a74fa4
commit 804be737b2
4 changed files with 150 additions and 38 deletions
+62 -13
View File
@@ -17,6 +17,7 @@ const PROFILE_DATA = {
phone: '+962 798 583 052',
email: 'hamzaayedflutter@gmail.com',
linkedin: 'linkedin.com/in/hamza-ayed',
github: 'github.com/Hamza-Ayed',
portfolio: 'intaleqapp.com/hamza.html',
productSite: 'tripz-egypt.com',
languages: 'Arabic (Native), English (Professional Working Proficiency)',
@@ -47,9 +48,13 @@ const PROFILE_DATA = {
'Engineering Manager'
],
// Opens on what was built, not on a self-description. "Proven experience" and
// "Founding Engineer" were removed: the first is filler, and the second
// contradicts the standard (non-startup) title framing when this text is used
// as the fallback summary.
summary:
'Senior Mobile Architect and Founding Engineer with proven experience building and launching two ' +
'production-grade ride-hailing platforms (Tripz — Egypt, Intaleq — Syria) from zero to live operations. ' +
'Senior Mobile Architect who built and launched two production-grade ride-hailing platforms ' +
'(Tripz — Egypt, Intaleq — Syria) from zero to live operations. ' +
'Designed and delivered full mobility ecosystems including Rider, Driver, Admin and Customer Support ' +
'applications, along with backend APIs, security layers, DevOps pipelines and fintech integrations. ' +
'Specialized in real-time systems, self-hosted geo-services, high-latency optimization and ' +
@@ -61,12 +66,16 @@ const PROFILE_DATA = {
'Founding Engineer (Mobility, Logistics, FinTech)'
],
// Headline metrics — these are the numbers that carry the CV.
// Headline metrics — ordered by how well they survive a sceptical reader.
// Delivery speed and breadth lead, because they are genuinely rare. Raw user
// counts trail: a few thousand riders is a small number to anyone who knows
// this market, so it belongs in context (see achievementsAtAGlance) rather
// than as the first claim on the page.
headlineMetrics: [
{ value: '5,275', label: 'Riders acquired across 2 launches' },
{ value: '5,750+', label: 'Drivers onboarded' },
{ value: '~80%', label: 'Map infrastructure cost cut' },
{ value: '8 apps', label: 'Shipped across 2 platforms' }
{ value: '8 apps', label: 'Shipped across 2 production platforms' },
{ value: '<4 months', label: 'Zero to live operations (Tripz, full ecosystem)' },
{ value: '$10K+/mo', label: 'Map infrastructure cost eliminated (~80% reduction)' },
{ value: '5,750+', label: 'Drivers onboarded across 2 markets' }
],
achievementsAtAGlance: [
@@ -119,14 +128,22 @@ const PROFILE_DATA = {
},
{
company: 'Tripz',
title: 'Founding Mobile Architect',
title: 'Lead Mobile Engineer',
// "Founding" is an asset applying to a startup and a liability applying
// to an established company, where it reads as flight risk and as a
// self-awarded title that no HR department can verify. Same work, same
// facts — the generator picks the framing that fits the employer.
titleVariants: {
standard: 'Lead Mobile Engineer',
founding: 'Founding Mobile Architect'
},
location: 'Cairo, Egypt (Remote)',
start: 'Jan 2024',
end: 'Dec 2024',
bullets: [
{ text: 'Built and launched a complete ride-hailing ecosystem (Rider, Driver, Admin, Customer Support apps plus backend API) in under four months, scaling to 2,464 riders and 4,318 drivers.', tags: ['delivery', 'leadership', 'mobility', 'scale', 'flutter'] },
{ text: 'Designed real-time dispatch and live tracking using WebSockets, optimized for high-latency MENA network environments.', tags: ['realtime', 'websockets', 'geo'] },
{ text: 'Reduced map infrastructure expenses by approximately 80% versus third-party API pricing by self-hosting map tiles, routing logic and polyline generation on dedicated servers.', tags: ['geo', 'cost', 'infrastructure'] },
{ text: 'Eliminated over $10,000/month in third-party mapping API spend (~80% reduction) by self-hosting map tiles, routing logic and polyline generation on dedicated servers.', tags: ['geo', 'cost', 'infrastructure'] },
{ text: 'Replaced traditional call-center hardware by engineering a secure, mobile-first Customer Support application, enabling support agents to operate entirely remotely.', tags: ['mobile', 'product', 'cost'] },
{ text: 'Automated driver onboarding through AI-powered KYC integration, reducing manual review time and minimizing fraudulent registrations.', tags: ['ai', 'automation', 'fintech', 'security'] },
{ text: 'Implemented API-level HMAC security, anti-tampering mechanisms and Fake GPS detection to protect geo-spatial and financial data.', tags: ['security', 'geo', 'fintech'] },
@@ -134,9 +151,13 @@ const PROFILE_DATA = {
]
},
{
company: 'Global Tech Projects',
// Previously "Global Tech Projects" — an invented company name reads as a
// placeholder to any experienced recruiter, and it was covering seven of
// the nine years on this CV. Naming the arrangement honestly is weaker in
// sound and considerably stronger in credibility.
company: 'Independent Consultant',
title: 'Lead Mobile Engineer (Flutter / Native)',
location: 'Freelance / Consultant',
location: 'Various Clients — MENA & Remote',
start: 'Jan 2017',
end: 'Dec 2023',
bullets: [
@@ -147,6 +168,26 @@ const PROFILE_DATA = {
}
],
// Published packages are the single most verifiable credential a mobile
// engineer can offer. They matter more here than usual: none of the three
// employers on this CV is a recognisable brand a recruiter can call, so a
// one-click-checkable artefact carries the credibility the employer names
// cannot.
openSource: [
{
name: 'intaleq_maps',
platform: 'Flutter SDK — pub.dev',
url: 'pub.dev/packages/intaleq_maps',
description: 'Map rendering, offline tile caching and route plotting, optimised for low-bandwidth environments.'
},
{
name: 'intaleq-maps-gl',
platform: 'JavaScript library — npm',
url: 'npmjs.com/package/intaleq-maps-gl',
description: 'Mapbox GL compatible web library for custom OSM tiles and routing integration.'
}
],
education: {
degree: 'BSc Mathematics',
institution: "Mu'tah University, Jordan",
@@ -232,10 +273,18 @@ function renderProfileText(p = PROFILE_DATA) {
lines.push('');
lines.push('EXPERIENCE:');
p.experience.forEach(job => {
lines.push(`- ${job.title} — ${job.company} | ${job.start} – ${job.end} | ${job.location}`);
const alt = job.titleVariants
? ` (alternate framing for startup/founding roles: ${job.titleVariants.founding})`
: '';
lines.push(`- ${job.title} — ${job.company} | ${job.start} – ${job.end} | ${job.location}${alt}`);
job.bullets.forEach(b => lines.push(` • ${b.text}`));
});
lines.push('');
lines.push('OPEN SOURCE (published, verifiable):');
(p.openSource || []).forEach(o => {
lines.push(`- ${o.name} (${o.platform}) — ${o.url}. ${o.description}`);
});
lines.push('');
lines.push('EDUCATION:');
lines.push(`- ${p.education.degree}, ${p.education.institution}. ${p.education.note}`);
p.certifications.forEach(c => lines.push(`- ${c}`));
@@ -249,7 +298,7 @@ function renderProfileText(p = PROFILE_DATA) {
lines.push('');
lines.push(`LANGUAGES: ${id.languages}`);
lines.push(`LOCATION: ${id.location} — ${id.availability}`);
lines.push(`CONTACT: ${id.email} | ${id.phone} | ${id.linkedin} | ${id.portfolio}`);
lines.push(`CONTACT: ${id.email} | ${id.phone} | ${id.linkedin} | ${id.github} | ${id.portfolio}`);
return lines.join('\n');
}
+7 -2
View File
@@ -106,10 +106,15 @@
<h2>Professional Experience</h2>
{{EXPERIENCE_BLOCK}}
<h2>Open Source</h2>
{{OPENSOURCE_BLOCK}}
<!-- Certifications sit inside Education rather than claiming a heading of
their own: they are data-analytics certificates on a mobile engineering
CV, so a dedicated section would draw the eye to the least relevant
content on the page. -->
<h2>Education</h2>
{{EDUCATION_BLOCK}}
<h2>Certifications</h2>
{{CERTIFICATIONS_BLOCK}}
<h2>Additional Information</h2>
+44 -5
View File
@@ -199,9 +199,23 @@ Return ONLY raw JSON (no markdown fences) with EXACTLY these keys:
],
"ats_keywords_matched": ["exact terms from the posting that now appear in the CV"],
"ats_keywords_missing": ["requirements from the posting I genuinely cannot claim"],
"estimated_ats_score": 0
"estimated_ats_score": 0,
"is_founding_or_startup_role": false
}
"is_founding_or_startup_role": true ONLY when the hiring company is an early-stage
startup, or the posting explicitly seeks a founding engineer / first engineer /
0-to-1 builder / someone to own a product end-to-end. false for established
companies, enterprises, banks, agencies and government. This controls whether my
CV presents a past role as "Founding Mobile Architect" or "Lead Mobile Engineer" —
identical work, framed for the reader.
CONSISTENCY RULE: when "is_founding_or_startup_role" is false, the words
"Founding" and "Founder" must NOT appear anywhere in "headline" or "summary"
either. Describe the same 0-to-1 ownership as "built and launched from zero" or
"owned end-to-end" instead. A CV that avoids "Founding" in the job title but
keeps it in the summary reads as careless.
RULES FOR "roles":
- Include EVERY role index that exists in MY REAL DATA, in the same order.
- For each role select the 3-4 bullets MOST relevant to this job (fewer for the
@@ -283,9 +297,15 @@ PROMPT;
$contactBlock =
'<div>' . e($id['location']) . ' &nbsp;|&nbsp; ' . e($id['phone'])
. ' &nbsp;|&nbsp; ' . e($id['email']) . '</div>'
. '<div>' . e($id['linkedin']) . ' &nbsp;|&nbsp; ' . e($id['portfolio'])
. '<div>' . e($id['linkedin']) . ' &nbsp;|&nbsp; ' . e($id['github'])
. ' &nbsp;|&nbsp; ' . e($id['portfolio'])
. ' &nbsp;|&nbsp; ' . e($id['productSite']) . '</div>';
// "Founding" reads as an asset at a startup and as flight risk at an
// established company. The model classifies the employer; the facts under
// the title are identical either way.
$isFoundingContext = $integrityClean && !empty($ai['is_founding_or_startup_role']);
$skillsBlock = '';
foreach ($profile['skills'] as $group => $items) {
$skillsBlock .= '<p class="skill-line"><span class="label">' . e($group) . ':</span> '
@@ -305,7 +325,17 @@ PROMPT;
$edu = $profile['education'];
$educationBlock = '<p>' . e($edu['degree']) . ' — ' . e($edu['institution']) . '. ' . e($edu['note']) . '</p>';
$certBlock = '<p>' . e(implode(' · ', $profile['certifications'])) . '</p>';
$certBlock = '<p class="skill-line"><span class="label">Certifications:</span> '
. e(implode(' · ', $profile['certifications'])) . '</p>';
// Package URLs are printed as plain text, not anchor labels — many parsers
// read the visible text rather than the href, and a recruiter needs to be
// able to retype these.
$openSourceBlock = '';
foreach (($profile['openSource'] ?? []) as $pkg) {
$openSourceBlock .= '<p class="skill-line"><span class="label">' . e($pkg['name']) . '</span> — '
. e($pkg['platform']) . ' · ' . e($pkg['url']) . '. ' . e($pkg['description']) . '</p>';
}
$availability = $market === 'amman'
? 'Based in Amman, Jordan. Available immediately for on-site, hybrid and remote roles.'
@@ -329,7 +359,8 @@ PROMPT;
$buildHtml = function (array $d) use (
$profile, $id, $template, $aiRoles, $headline, $summary, $coreSkills,
$contactBlock, $skillsBlock, $educationBlock, $certBlock, $availability
$contactBlock, $skillsBlock, $educationBlock, $certBlock, $availability,
$openSourceBlock, $isFoundingContext
) {
// Headline metrics collapse to a single dense line. As four separate
// bullets they cost four lines to say what one line says.
@@ -351,8 +382,15 @@ PROMPT;
$experienceBlock = '';
foreach ($profile['experience'] as $ri => $role) {
$roleTitle = $role['title'];
if (!empty($role['titleVariants'])) {
$roleTitle = $isFoundingContext
? ($role['titleVariants']['founding'] ?? $roleTitle)
: ($role['titleVariants']['standard'] ?? $roleTitle);
}
$experienceBlock .= '<div class="job">';
$experienceBlock .= '<p class="job-title">' . e($role['title']) . '</p>';
$experienceBlock .= '<p class="job-title">' . e($roleTitle) . '</p>';
$experienceBlock .= '<p class="job-company">' . e($role['company']) . ' — ' . e($role['location']) . '</p>';
$experienceBlock .= '<p class="job-dates">' . e($role['start']) . ' – ' . e($role['end']) . '</p>';
@@ -394,6 +432,7 @@ PROMPT;
'{{DYNAMIC_SKILLS}}' => e($coreSkills),
'{{SKILLS_BLOCK}}' => $skillsBlock,
'{{EXPERIENCE_BLOCK}}' => $experienceBlock,
'{{OPENSOURCE_BLOCK}}' => $openSourceBlock,
'{{EDUCATION_BLOCK}}' => $educationBlock,
'{{CERTIFICATIONS_BLOCK}}' => $certBlock,
'{{LANGUAGES}}' => e($id['languages']),
+37 -18
View File
File diff suppressed because one or more lines are too long