Fixup machine endpoints

This commit is contained in:
Dejvino 2026-07-27 19:58:29 +02:00
parent 4cb4b645ef
commit 86b20b2ce5
3 changed files with 89 additions and 26 deletions

View File

@ -31,6 +31,9 @@ RewriteRule ^domains/[^/]+/(.+[^/])$ /$1/ [R]
RewriteCond %{REQUEST_FILENAME} -d RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^subdom/[^/]+/(.+[^/])$ /$1/ [R] RewriteRule ^subdom/[^/]+/(.+[^/])$ /$1/ [R]
# Route /api/data.json and /llms.txt to index.php for machine-readable data
RewriteRule ^(api/data\.json|llms\.txt)$ index.php [L,QSA]
# Route /cv to index.php for CV view # Route /cv to index.php for CV view
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d

View File

@ -9,7 +9,7 @@
"contact_links": { "contact_links": {
"Website": "https://www.dejvino.cz", "Website": "https://www.dejvino.cz",
"Email": "mailto:explosive@dejvino.cz", "Email": "mailto:explosive@dejvino.cz",
"Resume": "https://dejvino.cz/cv" "Resume": "https://www.dejvino.cz/cv"
}, },
"about": [ "about": [
"Principal Software Engineer at Oracle NetSuite, focusing on AI-assisted developer enablement, UI platform architecture, performance, and observability for 40k+ enterprise customers." "Principal Software Engineer at Oracle NetSuite, focusing on AI-assisted developer enablement, UI platform architecture, performance, and observability for 40k+ enterprise customers."
@ -153,33 +153,27 @@
"interests": [ "interests": [
{ {
"name": "Mandolin", "name": "Mandolin",
"caption": "Octave mandolin is my instrument of choice. Wide range of tones, pleasant sound. Great way to relax your mind, explore melodies and harmonies.", "caption": "Octave mandolin is my instrument of choice. Wide range of tones, pleasant sound. Great way to relax your mind, explore melodies and harmonies."
"image": null
}, },
{ {
"name": "Electronics tinkering", "name": "Electronics tinkering",
"caption": "Building a useful device from scratch. Retrofitting modern brains into a broken vintage shell. Electronics is the magic that makes things alive.", "caption": "Building a useful device from scratch. Retrofitting modern brains into a broken vintage shell. Electronics is the magic that makes things alive."
"image": null
}, },
{ {
"name": "Synthwave", "name": "Synthwave",
"caption": "Neon-filled nostalgia. Fun to create, relaxing to listen to it.", "caption": "Neon-filled nostalgia. Fun to create, relaxing to listen to it.",
"image": "interests/synthwave.png"
}, },
{ {
"name": "3D Printing & Design", "name": "3D Printing & Design",
"caption": "Designing and printing custom parts that serve a purpose. Unique designs, useful accessories, toys or just repairs.", "caption": "Designing and printing custom parts that serve a purpose. Unique designs, useful accessories, toys or just repairs."
"image": null
}, },
{ {
"name": "Mountain Biking", "name": "Mountain Biking",
"caption": "Going places under your own power. Exploring forests, trails and nature where cars aren't allowed.", "caption": "Going places under your own power. Exploring forests, trails and nature where cars aren't allowed."
"image": null
}, },
{ {
"name": "RC Cars", "name": "RC Cars",
"caption": "Rock crawlers, construction trucks, military vehicles. Building a custom offroad course in the garden to trial them all.", "caption": "Rock crawlers, construction trucks, military vehicles. Building a custom offroad course in the garden to trial them all."
"image": null
} }
] ]
} }

View File

@ -40,13 +40,6 @@ $site_url = "https://www.dejvino.cz/";
$site_title = $name; $site_title = $name;
$site_desc = "$name - $headline"; $site_desc = "$name - $headline";
$mailto_link = $cvData['contact_links']['Email'] ?? '';
if (preg_match('/mailto:([^@]+)/', $mailto_link, $m)) {
$email_user = $m[1];
} else {
$email_user = $cvData['email'] ?? '';
}
$extra_contact_links = $cvData['contact_links'] ?? []; $extra_contact_links = $cvData['contact_links'] ?? [];
/** /**
@ -65,6 +58,39 @@ $pill_icons = [
'GitHub' => '🐙', 'GitHub' => '🐙',
]; ];
/** MACHINE READABLE ENDPOINTS */
$parsedUrl = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if (in_array($parsedUrl, ['/api/data.json', '/api/data.json/'], true)) {
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
readfile(__DIR__ . '/data.json');
exit;
}
if (in_array($parsedUrl, ['/llms.txt', '/llms.txt/'], true)) {
header('Content-Type: text/plain; charset=utf-8');
echo '# ' . $site_url . PHP_EOL;
echo '> ' . $name . ' — ' . $headline . PHP_EOL;
echo PHP_EOL;
echo $summary . PHP_EOL;
echo PHP_EOL;
echo '## Machine-readable data' . PHP_EOL;
echo '- JSON: ' . $site_url . 'api/data.json' . PHP_EOL;
echo PHP_EOL;
echo '## Links' . PHP_EOL;
foreach ($nav_links as $label => $href) {
echo '- ' . $label . ': ' . $href . PHP_EOL;
}
if (!empty($cvData['contact_links'])) {
echo PHP_EOL;
echo '## Contact' . PHP_EOL;
foreach ($cvData['contact_links'] as $label => $href) {
echo '- ' . $label . ': ' . $href . PHP_EOL;
}
}
exit;
}
/** END OF MACHINE READABLE ENDPOINTS */
/** /**
* Extract a readable URL from a href (strip protocol, trailing slash) * Extract a readable URL from a href (strip protocol, trailing slash)
*/ */
@ -142,6 +168,51 @@ $cv_education = array_map(function ($e) {
// Keep skills categories as provided // Keep skills categories as provided
$cv_skills = $cvData['cv']['skills'] ?? []; $cv_skills = $cvData['cv']['skills'] ?? [];
// JSON-LD structured data for machine readability (AI crawlers, schema.org)
$jsonLd = [
'@context' => 'https://schema.org',
'@type' => 'Person',
'name' => $name,
'jobTitle' => $headline,
'description' => $summary,
'url' => $site_url,
'email' => $cvData['email'] ?? '',
'telephone' => $cvData['phone'] ?? '',
'image' => $site_url . $photo_file,
'address' => [
'@type' => 'PostalAddress',
'addressLocality' => $location,
],
'sameAs' => array_values($nav_links),
'knowsAbout' => [],
'alumniOf' => [],
'worksFor' => [],
];
foreach ($cvData['cv']['skills'] ?? [] as $category => $skills) {
$jsonLd['knowsAbout'] = array_merge($jsonLd['knowsAbout'], $skills);
}
foreach ($cvData['interests'] ?? [] as $interest) {
$jsonLd['knowsAbout'][] = $interest['name'] ?? '';
}
$firstExp = $cvData['cv']['experience'][0] ?? null;
if ($firstExp) {
$jsonLd['worksFor'] = [
'@type' => 'Organization',
'name' => str_replace('|', ' / ', $firstExp['company'] ?? ''),
'description' => $firstExp['title'] ?? '',
];
} else {
unset($jsonLd['worksFor']);
}
foreach ($cvData['cv']['education'] ?? [] as $edu) {
$jsonLd['alumniOf'][] = [
'@type' => 'CollegeOrUniversity',
'name' => $edu['institution'] ?? '',
'description' => ($edu['degree'] ?? '') . ($edu['field'] ? ' in ' . $edu['field'] : ''),
];
}
$jsonLdEncoded = json_encode($jsonLd, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
/** /**
* Page design: * Page design:
* - clean and simple, human-maintainable * - clean and simple, human-maintainable
@ -166,6 +237,8 @@ $cv_skills = $cvData['cv']['skills'] ?? [];
<meta property="og:title" content="<?= $name ?>"> <meta property="og:title" content="<?= $name ?>">
<meta property="og:description" content="<?= $headline ?>"> <meta property="og:description" content="<?= $headline ?>">
<script type="application/ld+json"><?= $jsonLdEncoded ?></script>
<style> <style>
<?php <?php
include 'style.css'; include 'style.css';
@ -322,13 +395,6 @@ $cv_skills = $cvData['cv']['skills'] ?? [];
<?php endif; ?> <?php endif; ?>
</main> </main>
<script>
((u, d, t) => {
const addr = (atob(u) + '@' + d + '.' + t).trim();
const el = document.getElementById("contact-mail");
if (el) el.innerHTML = `<a href="mailto:${addr}">${addr}</a>`;
})('<?= base64_encode($email_user) ?>', 'dejvino', 'cz');
</script>
<!-- Cloudflare Web Analytics --> <!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "90827cb740cd4b1db611be059f64daa9"}'></script><!-- End Cloudflare Web Analytics --> <script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "90827cb740cd4b1db611be059f64daa9"}'></script><!-- End Cloudflare Web Analytics -->
<?php $file_mod_time = filemtime(__FILE__); ?> <?php $file_mod_time = filemtime(__FILE__); ?>