211 lines
9.4 KiB
Markdown
211 lines
9.4 KiB
Markdown
# KROW Demo
|
|
|
|
AI-powered hiring for event and hospitality staffing — a standalone demo build of KROW Forge.
|
|
|
|
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 # http://localhost:5173 — opens on /admin/login
|
|
```
|
|
|
|
## Stack
|
|
|
|
Vite 6 · React 19 · React Router 6 · React Query 5 · Tailwind + shadcn/ui · Framer Motion ·
|
|
Recharts + MUI X Charts · react-hot-toast.
|
|
|
|
## Structure
|
|
|
|
```
|
|
src/
|
|
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/ 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
|
|
```
|
|
|
|
## Routes
|
|
|
|
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 |
|
|
| --- | --- |
|
|
| `base44.entities.<Name>.list/filter/get/create/update/delete` | `api/store.js` — in-memory records, mirrored to `localStorage` |
|
|
| `base44.integrations.Core.InvokeLLM` | `api/aiEngine.js` — local, deterministic |
|
|
| `base44.integrations.Core.UploadFile` | blob URLs, session-scoped |
|
|
| `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/krowScore.js`, every page and component — is unchanged from the reference implementation.
|
|
|
|
## The AI engine
|
|
|
|
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. Results respond to the data rather than being canned — the
|
|
same input always returns the same output.
|
|
|
|
## Skills and agents
|
|
|
|
Two registries discover their definitions from markdown at build time:
|
|
|
|
| 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 |
|
|
|
|
**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` — 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`. 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` (currently `8`) invalidates saved snapshots
|
|
automatically, so changing the seed does not require a manual clear.
|
|
|
|
## Design system
|
|
|
|
Tokens live in `src/index.css` as HSL CSS variables consumed by `tailwind.config.js`.
|
|
|
|
| Token | Value |
|
|
| --- | --- |
|
|
| Primary — KROW Blue | `#0A39DF` |
|
|
| Accent — KROW Yellow | `#F9E547` |
|
|
| Pale Yellow | `#F8E08E` |
|
|
| Dark Navy | `#333F48` |
|
|
| Mint | `#D1E0D7` |
|
|
| Radius | `0.75rem` |
|
|
| Headings | Sora |
|
|
| Body | Inter |
|
|
|
|
`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`, default 5173) |
|
|
| `npm run build` | Production build |
|
|
| `npm run preview` | Serve the build |
|
|
| `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.
|