chore: clean up and restructure repository

This commit is contained in:
2026-08-21 11:11:21 +05:30
parent b2e6868824
commit dcf9770ada
106 changed files with 239 additions and 5654 deletions

193
README.md
View File

@@ -2,38 +2,99 @@
AI-powered hiring for event and hospitality staffing — a standalone demo build of KROW Forge.
Runs with no backend, no API keys, and no login. `npm install && npm run dev` and the app is fully
Runs with no backend, no API keys and no real login. `npm install && npm run dev` and the app is fully
populated.
```bash
npm install
npm run dev
npm run dev # http://localhost:5173 — opens on /admin/login
```
## Architecture
## Stack
Vite + React 18, React Router 6, React Query 5, Tailwind + shadcn/ui, Framer Motion, Recharts.
Vite 6 · React 19 · React Router 6 · React Query 5 · Tailwind + shadcn/ui · Framer Motion ·
Recharts + MUI X Charts · react-hot-toast.
## Structure
```
src/
api/ data client — entity store, demo dataset, local AI engine
assets/ brand asset references
main.jsx entry — mounts <App/>, imports index.css
App.jsx providers + the entire route table
index.css design tokens (HSL CSS variables) + utility layers
api/ the backend seam — see below
base44Client.js the contract the production app talks to
store.js in-memory entity store, mirrored to localStorage
aiEngine.js local, deterministic InvokeLLM
seed.js demo dataset
attendanceSeed.js shift/attendance dataset
lib/ domain logic and data hooks
krowHooks.js React Query hooks over the entity store
krowAi.js AI workflows
krowScore.js score engine
AuthContext.jsx auth provider
admin/ admin session, permissions, position insights
skills/ the Owliver skill system (registry, resolver, flows)
agents/ the agent system (registry, runtime, lifecycle)
skills/ *.md skill definitions — loaded by import.meta.glob
agents/ *.md agent definitions — loaded by import.meta.glob
components/
ui/ 50 shadcn primitives (design system)
krow/ domain components
talent/ talent-portal components
proving/ Proving Ground challenge components
hooks/ shared hooks
layouts/ Layout — header, nav pill, control bar, mobile sheet
lib/ data hooks, score engine, AI workflows, auth context, utils
pages/ 18 route components
utils/ helpers
ui/ 23 shadcn primitives
ds/ 30 design-system components (the app's real vocabulary)
admin/ admin page shell + role glyphs
krow/ domain components (+ talent/, proving/)
charts/ MUI X Charts wrappers and theme
agents/ agent configure / canvas / test panel
forge/ KROW Forge skill + challenge components
skills/ skill authoring surfaces
ai-assistant/ Owliver — panel, routing, capabilities, history
layouts/ AdminLayout — header nav, ⌘K search, assistant panel
pages/ route components (admin/ holds the live product)
hooks/ shared hooks
assets/ brand asset references
```
### The backend seam
## Routes
The production app talks to a Base44 backend through `src/api/base44Client.js`. This demo keeps
that module path, export name, and full method contract, and swaps only the transport:
The app opens on **`/admin/login`**. Everything else lives under `/admin/*` behind two guards:
`ProtectedRoute` (auth) and `AdminRoute` (admin session), rendered inside `AdminLayout`.
| Path | Page |
| --- | --- |
| `/admin/login` | Admin sign-in — outside the protected boundary |
| `/admin` | Control Center |
| `/admin/positions`, `positions/new`, `positions/:id` | Positions, Create, Detail |
| `/admin/candidates`, `candidates/:id` | Candidates, Candidate Intelligence profile |
| `/admin/hired` · `/admin/talent-pool` | Hired History, Talent Pool |
| `/admin/university`, `university/:id` | KROW Forge, challenge detail |
| `/admin/analytics` · `/admin/activity` | Analytics, Activity |
| `/admin/profile` · `/admin/settings` | Profile, Settings |
| `/admin/workspace` | Workspace hub |
| `/admin/workspace/agents`, `agents/new`, `agents/:id` | Agent list, agent editor |
| `/admin/workspace/skills`, `skills/new`, `skills/:id` | UI skill list and editor |
| `/admin/workspace/skills/owliver/new`, `owliver/:id` | Owliver skill editor |
| `/admin/workspace/skill-development` | Skill Development |
| `*` | `lib/PageNotFound.jsx` |
Legacy top-level paths (`/overview`, `/positions`, `/candidates`, `/hired`, `/talent-pool`,
`/university`, `/analytics`, `/activity`, `/tracking`) all `Navigate` into their `/admin/*`
equivalent, id preserved. Static route segments are declared before dynamic ones so
`workspace/agents/new` cannot be read as an agent whose id is `"new"`.
> **Note.** `App.jsx` still imports a set of pre-redesign Employer/Talent pages
> (`Overview`, `Apply`, `WorkerProfile`, `KrowIdentity`, `EmployeeDashboard`, `DesignSystem`, …)
> and `layouts/Layout.jsx`. None of them are mounted on a route — they are unreachable at runtime
> and retained pending a decision on whether to re-route or remove them.
## The backend seam
The production app talks to a Base44 backend through `src/api/base44Client.js`. This demo keeps that
module path, export name and full method contract, and swaps only the transport:
| Contract | Demo implementation |
| --- | --- |
@@ -43,56 +104,48 @@ that module path, export name, and full method contract, and swaps only the tran
| `base44.auth.*` | seeded employer/admin user, always signed in |
Because the seam did not move, everything above it — `lib/krowHooks.js`, `lib/krowAi.js`,
`lib/provingGround.js`, `lib/krowScore.js`, every page and component — is unchanged from the
reference implementation.
`lib/krowScore.js`, every page and component — is unchanged from the reference implementation.
### The AI engine
## The AI engine
Every AI workflow in the app funnels through one call, `InvokeLLM({ prompt, response_json_schema })`.
`api/aiEngine.js` reimplements that function locally. It recognizes each workflow by the phrase its
prompt opens with, reads the structured fields the prompt already carries (`Years Experience: 6`,
`Required Certifications: …`, the talent-pool JSON block), and scores them deterministically.
Every AI workflow funnels through one call, `InvokeLLM({ prompt, response_json_schema })`.
`api/aiEngine.js` reimplements it locally: it recognises each workflow by the phrase its prompt opens
with, reads the structured fields the prompt already carries (`Years Experience: 6`,
`Required Certifications: …`, the talent-pool JSON block) and scores them deterministically.
Nine workflows are implemented: candidate screening, job-description generation, résumé building,
interview questions, interview evaluation, talent matching, Owliver's conversation, Career DNA
building, and Proving Ground evaluation.
building and Proving Ground evaluation. Results respond to the data rather than being canned — the
same input always returns the same output.
Results respond to the data rather than being canned — screening a 7-year native-English candidate
and a 1-year candidate against the same posting returns genuinely different scores, breakdowns,
strengths and gaps. The same input always returns the same output.
## Skills and agents
### Owliver
Two registries discover their definitions from markdown at build time:
Two assistants share one visual language:
| Registry | Glob | Files |
| --- | --- | --- |
| `lib/skills/registry.js` | `import.meta.glob('/src/skills/**/*.md')` | 18 Owliver skills, 5 workforce training skills |
| `lib/agents/registry.js` | `import.meta.glob('/src/agents/**/*.md')` | 9 agent definitions |
- **`OwliverAssistant`** — the hiring assistant, mounted on **Overview**, **Candidates** and
**Analytics** only. Answers from the same React Query caches the pages render from, so what it
says and what the dashboard shows can never disagree.
- **`OwliverChatBubble`** — the talent-facing profile builder, mounted in the Talent role.
**These globs are absolute paths.** Moving or renaming `src/skills/` or `src/agents/` makes the
registry silently return nothing — no build error, no import failure, just an empty registry. Add
definitions by dropping a new `.md` file into the right folder; nothing else needs to change.
## Demo data
Seeded in `src/api/seed.js`: 7 positions (5 open), 22 applicants, 9 AI-scored candidates averaging
76, 4 AI interviews, 3 hires, 6 talent-pool profiles, 4 Proving Ground courses, and an activity log.
Seeded in `src/api/seed.js` — positions, applicants, AI-scored candidates, interviews, hires,
talent-pool profiles, Proving Ground courses and an activity log; shift data in
`src/api/attendanceSeed.js`.
Edits persist to `localStorage` — screen candidates, hire someone, create a position, and the
numbers move everywhere. To restore the shipped dataset:
Edits persist to `localStorage`. To restore the shipped dataset:
```js
// in the browser console
localStorage.removeItem('krow_demo_db'); location.reload();
```
Bumping `STORAGE_VERSION` in `src/api/store.js` invalidates saved snapshots automatically, so
changing the seed does not require a manual clear.
## Roles
The header role switcher moves between three surfaces, persisted in `localStorage`:
- **Employer** — Overview, Positions, Candidates, Hired History, Talent Pool, Analytics
- **Admin** — adds Control Center, KROW Forge, Activity
- **Talent** — My Portal, KROW Forge, Opportunities
Bumping `STORAGE_VERSION` in `src/api/store.js` (currently `8`) invalidates saved snapshots
automatically, so changing the seed does not require a manual clear.
## Design system
@@ -109,15 +162,49 @@ Tokens live in `src/index.css` as HSL CSS variables consumed by `tailwind.config
| Headings | Sora |
| Body | Inter |
The page background is `bg-[#F8FAFC]` under the `gradient-mesh` utility — four radial gradients in
blue, yellow and mint. Surfaces use `glass` and `glass-card` (backdrop blur with saturation).
`src/components/ds/` is the vocabulary the app actually writes in — `Surface`, `KpiCard`,
`DataTable`, `PageHeader`, `Modal`, `toast` and the rest, exported through `ds/index.js`.
`src/components/ui/` holds the shadcn primitives those are built on. Surfaces use `glass` and
`glass-card`; the page background is the `gradient-mesh` utility.
Toasts go through `ds/toast` (a wrapper over `react-hot-toast`), rendered by `<HotToaster>` in
`App.jsx`.
## Scripts
| Command | Purpose |
| --- | --- |
| `npm run dev` | Dev server (honors `PORT`) |
| `npm run dev` | Dev server (honors `PORT`, default 5173) |
| `npm run build` | Production build |
| `npm run preview` | Serve the build |
| `npm run lint` | ESLint |
| `npm run lint` | ESLint — currently clean |
| `npm run lint:fix` | ESLint with `--fix` |
| `npm test` | `scripts/skill-check.mjs` — 835 assertions over the skill and agent systems |
| `npm run typecheck` | `tsc -p ./jsconfig.json` with `checkJs` |
### The test harness
`npm test` boots a real Vite dev server in middleware mode and `ssrLoadModule`s the actual
application modules, so it exercises the real `@/` alias and `import.meta.glob` pipeline rather than
mocks. It also diffs Owliver's behaviour across eleven page contexts against a committed snapshot,
`scripts/__baseline__/owliver-baseline.json`; regenerate that deliberately with
`node scripts/owliver-baseline.mjs --write`, never to turn a red check green.
Because it loads modules by absolute path, the harness pins the locations of `src/api/`, `src/lib/`,
`src/lib/skills/`, `src/lib/agents/`, `src/components/ai-assistant/`, `src/App.jsx`,
`src/layouts/AdminLayout.jsx` and a handful of agent files. Move any of them and update
`scripts/owliver-capture.mjs` and `scripts/skill-check.mjs` in the same change.
### Known-failing checks
Two checks fail on a clean checkout and are tracked as separate work, not regressions:
- `npm test` — 834/835 pass; `the seeded overtime climb is found` fails.
- `npm run typecheck` — 59 errors, all pre-existing JSDoc/inference gaps in `lib/krowAi.js`,
`lib/skills/*`, `lib/positionModel.js` and a few components.
## Deployment
`Dockerfile` builds with `node:22-alpine` (capped at 1 GB heap for small hosts) and serves the
static `dist/` from `nginx:alpine` using `nginx.conf` — gzip, immutable `/assets/` caching and an
SPA fallback to `index.html` so client-side routes resolve on refresh.