SkillLink: The Interview Prep App That Turns an LLM Into a Structured Career Engine

It reads a resume, a self-description, and a job post, then turns them into questions, skill gaps, and a study plan the backend can actually trust.

7 to 8 min read • View on GitHub • More from HiteshXG

A wide editorial scene shows three paper inputs feeding a single machine on a clean desk. One page is a resume, one is a handwritten self-description, and one is a clipped job posting, and the machine outputs a tidy prep dossier with cards, a score dial, and a calendar sheet. The image explains how SkillLink converts scattered job-search material into one structured artifact.
SkillLink is less a chatbot than a document factory for interview prep.
Key Takeaways

The app does not help you prep. It manufactures a prep artifact

Most interview tools promise guidance. SkillLink does something more specific: it produces a report. That report includes a match score, technical and behavioral questions, skill gaps, and a preparation plan that can be revisited later instead of regenerated from scratch.

That distinction matters. A chatty coach disappears after the session. A structured report becomes a reusable object, which is much closer to how serious product systems work.

Three inputs, one profile

SkillLink does not trust a single source of truth. It reads a resume PDF, asks the candidate to describe themselves, and takes in a target job description. Each one answers a different question: what you have done, how you frame yourself, and what the role actually wants.

SkillLink’s core move is to collapse three different signals into one durable report object.

InputWhat it contributesWhy it matters
Resume PDFPast experience and credentialsGrounds the analysis in evidence
Self-descriptionPersonal framing and confidenceShows how the candidate positions themselves
Job descriptionRole requirements and prioritiesDefines the target the report should optimize for

The real trick is schema-enforced AI

The technical center of the repo is `Backend/src/services/ai.service.js`. Instead of asking Gemini for a blob of text and hoping for the best, the app defines the expected shape with Zod, converts that schema with `zod-to-json-schema`, and pushes the model toward valid JSON output.

const interviewReportSchema = z.object({
  matchScore: z.number(),
  technicalQuestions: z.array(z.string()),
  behavioralQuestions: z.array(z.string()),
  skillGaps: z.array(z.string()),
  preparationPlan: z.array(z.string())
});

const jsonSchema = zodToJsonSchema(interviewReportSchema);

const response = await model.generateContent({
  contents: prompt,
  generationConfig: {
    responseMimeType: 'application/json',
    responseSchema: jsonSchema
  }
});

That is the real product decision. SkillLink does not merely use an LLM. It constrains the model so the output can be parsed, stored, and reused as application data.

A close-up shows an unruly stream of text trying to pour out of an AI engine on the left, then passing through a rigid JSON stencil and Zod-shaped frame in the center, and finally emerging on the right as a database record and a printed PDF page. The scene explains how schema enforcement turns freeform model output into dependable product data.
The app’s reliability comes from forcing the model through a contract before anything reaches storage or print.
ApproachOutput shapeReliabilityReuse
Freeform chatUnstructured proseLowPoor
Schema-enforced AIValidated JSON objectHighStrong
Template-only generationStatic document layoutMediumLimited

Skill gaps are the product, not the byproduct

This is where the app becomes genuinely useful. A generic assistant can tell you what you know. SkillLink tries to tell you what you are missing relative to a specific role, which is a much better fit for interview prep.

That directional logic changes the product from assessment to planning. The candidate is not just getting scored. They are getting an agenda.

QuestionGeneric AI coachSkillLink
What did I do well?Usually yesYes, but inside a larger report
What am I missing?Often vagueExplicit skill-gap output
What should I do next?Informal adviceDay-by-day preparation plan
Can I save it?Usually noYes, as a durable record

Why the frontend stays calm

The frontend uses React Context and custom hooks inside `Frontend/src/features/interview/` to keep the feature self-contained. That matters because interview generation is a stateful workflow, and feature-local state is easier to reason about than a global app-wide tangle.

const { generateReport, reports, loading } = useInterview();

const handleSubmit = async (event) => {
  event.preventDefault();
  await generateReport(formData);
};

The pattern is not flashy. It is pragmatic. API calls, loading state, and interview-specific UI all live close together, which keeps the rest of the app cleaner.

The document pipeline is clever, and a little dangerous at scale

SkillLink also uses AI as a designer. In the resume-generation path, the model writes HTML, Puppeteer renders it, and the browser becomes a print engine. That is elegant because it removes an extra template layer and lets the model own the document layout directly.

It is also expensive. Puppeteer is a heavy tool for synchronous request flow, so this part of the system would probably want a background job or worker if traffic grew beyond prototype scale.

PipelineStrengthRisk
AI writes HTML, Puppeteer prints PDFFast to prototype, flexible layoutResource-heavy under load
Template engine renders PDFPredictable and cheapLess expressive
Background worker handles print jobsSafer at scaleAdds queue and ops complexity

What SkillLink gets right, and what it would need next

SkillLink’s strongest decision is the one that shapes everything else: it treats LLM output as structured product data. That unlocks persistence, reuse, and cleaner UI flows, which is a better foundation than a thin wrapper around a chat box.

Its next step is obvious. Move the expensive PDF work off the request path, and the architecture starts to look less like a clever demo and more like a system that can survive real usage.