diff --git a/.htaccess b/.htaccess index 720af4d..5448097 100644 --- a/.htaccess +++ b/.htaccess @@ -31,6 +31,9 @@ RewriteRule ^domains/[^/]+/(.+[^/])$ /$1/ [R] RewriteCond %{REQUEST_FILENAME} -d 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 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d diff --git a/data.json b/data.json index 397ee7a..66fd74b 100644 --- a/data.json +++ b/data.json @@ -9,7 +9,7 @@ "contact_links": { "Website": "https://www.dejvino.cz", "Email": "mailto:explosive@dejvino.cz", - "Resume": "https://dejvino.cz/cv" + "Resume": "https://www.dejvino.cz/cv" }, "about": [ "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": [ { "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.", - "image": null + "caption": "Octave mandolin is my instrument of choice. Wide range of tones, pleasant sound. Great way to relax your mind, explore melodies and harmonies." }, { "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.", - "image": null + "caption": "Building a useful device from scratch. Retrofitting modern brains into a broken vintage shell. Electronics is the magic that makes things alive." }, { "name": "Synthwave", "caption": "Neon-filled nostalgia. Fun to create, relaxing to listen to it.", - "image": "interests/synthwave.png" }, { "name": "3D Printing & Design", - "caption": "Designing and printing custom parts that serve a purpose. Unique designs, useful accessories, toys or just repairs.", - "image": null + "caption": "Designing and printing custom parts that serve a purpose. Unique designs, useful accessories, toys or just repairs." }, { "name": "Mountain Biking", - "caption": "Going places under your own power. Exploring forests, trails and nature where cars aren't allowed.", - "image": null + "caption": "Going places under your own power. Exploring forests, trails and nature where cars aren't allowed." }, { "name": "RC Cars", - "caption": "Rock crawlers, construction trucks, military vehicles. Building a custom offroad course in the garden to trial them all.", - "image": null + "caption": "Rock crawlers, construction trucks, military vehicles. Building a custom offroad course in the garden to trial them all." } ] } \ No newline at end of file diff --git a/index.php b/index.php index daff932..bcc68eb 100644 --- a/index.php +++ b/index.php @@ -40,13 +40,6 @@ $site_url = "https://www.dejvino.cz/"; $site_title = $name; $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'] ?? []; /** @@ -65,6 +58,39 @@ $pill_icons = [ '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) */ @@ -142,6 +168,51 @@ $cv_education = array_map(function ($e) { // Keep skills categories as provided $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: * - clean and simple, human-maintainable @@ -166,6 +237,8 @@ $cv_skills = $cvData['cv']['skills'] ?? []; + +