SkillGraph
DashboardJobsSkillsGraph
About

About SkillGraph

What this app does, why it exists, and how it's built.

The Assignment
Wexa AI CognoDB take-home

SkillGraph was built for Wexa AI's CognoDB take-home assignment: build a small, complete application backed by a graph database, using CognoDB (a managed graph database speaking openCypher over the Bolt protocol) as the data layer.

The brief left the use case entirely open, with the evaluation focused on data modeling judgment, engineering architecture, and UI/UX polish rather than any specific feature list.

What SkillGraph Does
Developer skill and job matching

Developers typically have several skills, and jobs typically require several skills — the relationship between the two is naturally many-to-many, and it doesn't stop there: jobs belong to companies, companies post many jobs, and jobs and developers both relate to locations.

SkillGraph represents all of that as a graph and lets a developer:

  • See which jobs best match their current skills, and by how much.
  • Understand exactly why a job matches — which required skills they have, and which they're missing.
  • Explore similar jobs based on shared required skills.
  • Browse skills to see which jobs and companies need them, and which skills tend to co-occur.
  • Visually explore the underlying graph of developers, skills, jobs, companies, and locations.
Why a Graph Database?
Every core feature here is a traversal, not a lookup

The primary matching query walks a 3-hop pattern: Developer -[HAS_SKILL]-> Skill <-[REQUIRES]- Job <-[POSTS]- Company. In Cypher that's one pattern match. In SQL it's four tables, three join conditions, and a GROUP BY to get the matching-skill count back out.

The skill explorer's co-occurrence query (which other skills tend to appear alongside a given skill) is a self-join of a junction table against itself in SQL — in Cypher it's the same one-line pattern, and each additional hop is just one more relationship segment.

"Similar jobs" (jobs sharing required skills) is the same story: a job-to-job similarity signal that only exists because two jobs point at the same skill nodes. The graph makes that connection a first-class thing you can pattern-match on.

In short: the relationships are the product here, not incidental foreign keys. The UI's "why does this job match" explanation, the graph explorer, and the skill explorer are all direct renderings of graph traversals — there's no translation layer between how the data is stored and how the feature is explained.

Data Model
5 node types, 5 relationship types
DeveloperSkillJobCompanyLocation
(:Developer)-[:HAS_SKILL]->(:Skill)
(:Job)-[:REQUIRES]->(:Skill)
(:Company)-[:POSTS]->(:Job)
(:Job)-[:LOCATED_IN]->(:Location)
(:Developer)-[:PREFERS]->(:Location)
Tech Stack & Architecture
  • Frontend — Next.js 16 (App Router), TypeScript, Tailwind CSS, shadcn/ui, React Flow for the Graph Explorer.
  • API layer — Next.js Route Handlers under app/api/, running entirely server-side, with input validation and generic error messages (no raw driver errors ever reach the client).
  • Database layer — a singleton neo4j-driver instance in lib/cognodb.ts, with parameterized queries throughout (no string-concatenated Cypher) and automatic unwrapping of Neo4j's 64-bit integer types.
  • Database — CognoDB, a hosted graph database speaking openCypher over Bolt, accessed with the official JavaScript Neo4j driver.