Api Doc Portfolio
Source: Dev.to
Overview
My hack‑athon goal was to craft a portfolio that stands out while remaining approachable.
I chose an API‑documentation aesthetic (think Swagger / Postman) to reflect my developer identity, yet I kept the experience friendly for non‑technical visitors.
- Single‑source data: All personal information lives in one
data.jsonfile, making updates painless. - Tech stack: React + TypeScript for scalability & type safety, Tailwind CSS for rapid, consistent UI design.
- Tools used:
- Gemini – creative prompt‑engineering assistant.
- Antigravity IDE (Gemini 3 Pro) – senior‑frontend reviewer, refactoring, bug‑fixing, UI/UX feedback.
- Google Cloud Run – deployment platform.
I followed Google scientists’ prompt‑engineering guide, applying one‑shot, step‑back, and tree‑of‑thought techniques. Selected prompts are included below.
Prompt 1 – Refactor Resume Page to Fetch Data from JSON
Context:
We are moving to a data‑driven architecture. All content now lives in data.json.
Task:
Refactor the “Resume/IDE Viewer” page (HTML/JS) so it loads its content dynamically from data.json.
Requirements
-
JSON Structure (exact shape)
{ "resume": { "pdf_path": "/assets/cv.pdf", "filename": "cv_xxx_backend.pdf", "last_updated": "2026-01-12", "raw_data": { "name": "XXX", "role": "Junior Backend Developer", "stack": ["Python", "Django", "Docker"] } } } -
TypeScript Logic (Fetch & DOM Manipulation)
- On page load:
fetch('./data.json'). - Update PDF: Find the
<iframe>(or similar) and set itssrctoresume.pdf_path. - Update “Raw” View: Fill the code block in the “Raw (JSON)” tab with a nicely formatted version of
resume.raw_data. - Update UI Labels: Change the breadcrumb/file‑path label to
resume.filename.
- On page load:
-
HTML Changes
- Remove any hard‑coded
srcfrom the PDF container (leave empty or show a loading spinner). - Add unique IDs for JS targeting, e.g.:
id="pdf-viewer"id="json-code-block"id="file-name-label"
- Remove any hard‑coded
Deliverable
Below are the minimal HTML snippet and the updated JavaScript (TypeScript‑compatible) that satisfy the above.
HTML (excerpt)
<!-- PDF viewer -->
<iframe id="pdf-viewer" src=""></iframe>
<!-- Tabs -->
<button id="preview-tab">Preview</button>
<button id="raw-tab">Raw (JSON)</button>
<!-- JSON code block -->
<pre id="json-code-block"></pre>
<!-- Breadcrumb / filename label -->
<span id="file-name-label"></span>
JavaScript / TypeScript (ES6)
// src/utils/loadResume.ts
interface ResumeRaw {
name: string;
role: string;
stack: string[];
}
interface ResumeData {
pdf_path: string;
filename: string;
last_updated: string;
raw_data: ResumeRaw;
}
interface PortfolioJSON {
resume: ResumeData;
}
/**
* Fetches `data.json`, updates the DOM, and handles errors.
*/
async function initResumeViewer(): Promise<void> {
try {
const response = await fetch('./data.json');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data: PortfolioJSON = await response.json();
const { pdf_path, filename, raw_data } = data.resume;
// ---- Update PDF viewer ----
const pdfViewer = document.getElementById('pdf-viewer') as HTMLIFrameElement;
if (pdfViewer) pdfViewer.src = pdf_path;
// ---- Update filename breadcrumb ----
const fileLabel = document.getElementById('file-name-label');
if (fileLabel) fileLabel.textContent = filename;
// ---- Populate Raw JSON view ----
const jsonBlock = document.getElementById('json-code-block');
if (jsonBlock) {
const pretty = JSON.stringify(raw_data, null, 2);
jsonBlock.textContent = pretty;
}
} catch (err) {
console.error('Failed to load resume data:', err);
// Optional: display a user‑friendly fallback UI
}
}
// Run on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initResumeViewer);
} else {
initResumeViewer();
}
Prompt 2 – UX Audit for Non‑Technical Users (Recruiter Persona)
Role: Senior UX Researcher paired with a Non‑Technical Tech Recruiter (HR Manager).
Context:
The portfolio uses a heavy API‑Documentation / CLI theme: dark mode, monospaced fonts, terminal‑style inputs, JSON code blocks, sidebar navigation (Stripe‑Docs style), and a command palette.
Problem:
The design may be over‑engineered, potentially confusing recruiters who lack coding experience, increasing cognitive load and navigation friction.
Heuristic Evaluation
| Friction Point | Why it fails HR | Thematic Solution |
|---|---|---|
| Bio text inside a JSON string | Hard to read quickly; visual noise from brackets/quotes; recruiters scan for plain text. | Render the bio as normal paragraph text but keep a subtle line‑number gutter on the left (like an IDE) to preserve the “code” feel. |
| Navigation via a terminal‑style command palette | Requires typing or remembering commands; adds unnecessary interaction steps for a simple lookup. | Keep the command palette as an optional shortcut, but provide a prominent, conventional top‑level navigation bar with clearly labeled tabs (About, Projects, Resume). |
| Work Experience displayed as raw JSON objects | Recruiters expect bullet points or cards; JSON format obscures chronology and achievements. | Show each role in a card that mimics a code block (border, monospaced font) while using plain language for dates, titles, and responsibilities. |
| Sidebar mimicking API docs with collapsible sections | Too many nested layers; recruiters may miss the “Resume” link. | Collapse the sidebar to a minimal set of top‑level items and add a sticky “Download Resume” button in the header. |
| Heavy use of dark background with low‑contrast text | Reduces readability for users not accustomed to dark‑mode coding environments. | Increase contrast ratios (e.g., light‑gray text on dark‑gray background) and add a “light mode” toggle for accessibility. |
| “Raw JSON” view of the resume | Provides no value to recruiters; appears technical and intimidating. | Keep the raw view behind an “Advanced” toggle, and surface a clean, printable PDF preview as the primary resume access point. |
| Terminal‑style input prompts for project demos | Requires typing commands to view demos; adds friction for a simple click‑through. | Replace with clickable “Run Demo” buttons that retain a terminal‑style border and cursor animation, giving the illusion of a command line without the typing. |
Breadcrumbs showing file paths (e.g., /cv_xxx_backend.pdf) | May be confusing; recruiters look for clear labels like “Resume”. | Show both: a friendly label (“Resume”) and the technical breadcrumb in a smaller, secondary font. |
Specific Questions Answered
| Question | Recommendation |
|---|---|
| Should I keep the “Terminal Input” as the primary navigation? | No. Keep it as an optional shortcut for power users. Provide a conventional, clearly labeled navigation bar for recruiters. |
| How can I display “Work Experience” so it looks like code but reads like a story? | Use card components styled with a code‑block border and monospaced font, but write the content in natural‑language sentences. Add subtle line numbers on the left to keep the developer vibe. |
| Is the “Raw JSON” view of my resume necessary? | Only as an advanced option. Place it behind an “Advanced / Raw Data” toggle. The default view should be a clean, printable PDF preview with a prominent “Download” button. |
Summary
- Maintain the technical aesthetic (dark theme, code‑like borders, line numbers) while simplifying interactions for non‑technical users.
- Prioritize readability: plain text for bios, bullet points for experience, high‑contrast colors.
- Offer progressive disclosure: advanced JSON or terminal features are hidden behind optional toggles, keeping the primary flow straightforward.
Implementing these bridges will let recruiters find the essential information (Name, Role, Tech Stack, Resume) within the 6‑second scan window while preserving the unique API‑documentation personality of the portfolio.
I’m proud of how this project turned the portfolio itself into an experiment. Instead of focusing only on visuals, I treated it as a system: maintainable, extensible, and driven by data. Designing the entire site around a single JSON source allowed me to iterate quickly and keep the structure clean throughout the hackathon.
I’m also especially proud of how I used AI as a collaborator rather than just a code generator. By refining prompts and applying techniques, I was able to use Gemini and Antigravity Agents as creative and technical reviewers, helping me improve architecture decisions, UI/UX, and overall clarity.