A-102 · Case study · Section 02
EngiHire (Engilink)
3-party recruitment platform for the Japanese market
30-second card
- Role
- Fullstack — monorepo FE architecture + REST API endpoints & JWT auth on BE
- Surfaces
- Agency portal · Manager portal · Visitor portal
- Period
- ≈ 2025–2026 · about 1 year
- Stack
- Vue 3 · TypeScript · Feature-Sliced Design · Pinia · TanStack Query · Turborepo · pnpm workspaces · Element Plus · Vite · NestJS · MongoDB · JWT · REST API
- Links
- Manager site ↗Visitor site ↗Agency site ↗
Problem
A three-party recruitment platform for the Japanese market: agencies, companies and candidates each need a dedicated portal on the same product.
Constraints
- Three role-specific portals — agency, manager and visitor
- Frontend architecture and backend endpoints owned in one role
- Token-based authentication with access and refresh tokens
Section 02 · decisions in place
- D1
One monorepo for three portals
Portals and shared packages live in a single Turborepo + pnpm workspace.
Trade-off One workspace means one build pipeline to keep fast, and shared packages every portal depends on. In exchange, a fix in a shared package reaches the agency, manager and visitor portals together, without copying code.
- D2
Feature-Sliced Design
One layering convention for every portal's codebase.
Trade-off Feature-Sliced Design asks for discipline about layers and imports, which takes time to learn. In exchange, the three portals share one structure, so a developer moving between them finds code in the same place.
- D3
REST endpoints in NestJS
Built and maintained API endpoints with NestJS and MongoDB.
Trade-off NestJS adds structure — modules, providers, decorators — that a minimal server would not need. In exchange, every endpoint follows one pattern, in the same TypeScript as the portals.
- D4
Access / refresh token auth
JWT authentication flows implemented on the backend.
Trade-off Short-lived access tokens mean the portals must refresh sessions quietly and handle expiry. In exchange, a leaked access token is useful only briefly, and users stay signed in.