docs: add Plan 7 (profiles, skill catalog & AI dispatch context)
This commit is contained in:
@@ -527,7 +527,8 @@ Each plan = one phase, produces working/verifiable software on its own, and is e
|
|||||||
### Plan 7 — Profiles, skill catalog & AI dispatch context
|
### Plan 7 — Profiles, skill catalog & AI dispatch context
|
||||||
- **What:** two-layer profiles (self + company) per person; the self-service User Details page (all roles); the owner Employee/Subcontractor Details view; the org skill catalog; ProCanvas achievements surfaced; `DISPATCH_REPS` mapped to canonical people; dispatch `reasons`/`aiInsight`/`skillMatch` authored to cite real profile facts.
|
- **What:** two-layer profiles (self + company) per person; the self-service User Details page (all roles); the owner Employee/Subcontractor Details view; the org skill catalog; ProCanvas achievements surfaced; `DISPATCH_REPS` mapped to canonical people; dispatch `reasons`/`aiInsight`/`skillMatch` authored to cite real profile facts.
|
||||||
- **Why:** richer structured context yields more believable AI dispatch (investor wow), and profile depth is what a prospect expects from a mature CRM.
|
- **Why:** richer structured context yields more believable AI dispatch (investor wow), and profile depth is what a prospect expects from a mature CRM.
|
||||||
- **How:** add `profile`/`skillCatalog`/`skillScores` to people + dispatch-rep↔person mapping in `mockStore.jsx` (sequential); build the User Details page + owner Details view (new component files → parallel); rewrite the pre-authored `DISPATCH_RECOMMENDATIONS` to reference profile facts. Verify: a recommendation's rationale cites a real skill/equipment value from the cited rep's profile.
|
- **How:** add `profile`/`skillCatalog`/`skillScores` to people + dispatch-rep↔person mapping in `mockStore.jsx` (sequential); build the User Details page + owner Details view (new component files → parallel); rewrite the pre-authored `DISPATCH_RECOMMENDATIONS` to reference profile facts. Verify: a recommendation's rationale cites a real skill/equipment value from the cited rep's profile. (Concretely: the dispatch reps are currently FAKE — REP-01 "Carlos Mendez"/"Nina Patel"/"Derek Walsh", plus fake `canvassedBy` ids and leaderboard names — all remap to canonical people; profiles store a self/company split that Plan 8's ABAC later governs at field level.)
|
||||||
|
- **Plan file:** `docs/superpowers/plans/2026-05-29-plan7-profiles-skills-dispatch.md`.
|
||||||
|
|
||||||
### Plan 8 — ABAC access control + unified routing
|
### Plan 8 — ABAC access control + unified routing
|
||||||
- **What:** an attribute-based policy engine (subject/resource/action/context attributes; ordered permit/deny; deny-wins; default-deny) generalizing the role/override data; `can(action, resource, ctx)` API; a permission-aware route guard; the Option-B unified route scheme (one human-readable route per feature, role landings only); nav hiding + styled Access Restricted page; Org Settings as policy/attribute editor.
|
- **What:** an attribute-based policy engine (subject/resource/action/context attributes; ordered permit/deny; deny-wins; default-deny) generalizing the role/override data; `can(action, resource, ctx)` API; a permission-aware route guard; the Option-B unified route scheme (one human-readable route per feature, role landings only); nav hiding + styled Access Restricted page; Org Settings as policy/attribute editor.
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# Plan 7 — Profiles, Skill Catalog & AI Dispatch Context
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`). Follow the execution protocol (`2026-05-29-execution-protocol.md`) — sequential on shared files, parallel only where lanes are disjoint.
|
||||||
|
|
||||||
|
**Goal:** Give every person a **two-layer profile** (self-edited + company-private), an **org skill catalog** with per-person 0–100 scores, surface **ProCanvas achievements**, and **ground LynkDispatch** — remap the fake `DISPATCH_REPS` to canonical people and rewrite each recommendation's `reasons`/`aiInsight`/`skillMatch` to **cite real profile facts** (equipment + skill scores), so "the AI read their profile" is demonstrably true on screen.
|
||||||
|
|
||||||
|
**Architecture:** Add a `profile` object (`self` / `company` / `achievements`) to the canonical people in `mockStore.jsx`, plus an org-level `SKILL_CATALOG` and per-person `skillScores`, exposed via the store (a `resolveProfile(id)` selector + `updateOwnProfile`/`setSkillScore`/`addCatalogSkill` mutators). Then remap dispatch reps to canonical field agents and rewrite the pre-authored recommendations to reference those people's real profile facts. UI: a self-service **User Details** page (all non-customer roles edit their `self` layer), an owner **Person Details** view (sees `self` + `company` + skill scores + achievements, edits scores/notes), and a **Skill Catalog editor** in Org Settings. Plan 8 (ABAC) later governs who can see the `company` layer; Plan 7 gates it with a simple role check.
|
||||||
|
|
||||||
|
**Tech stack:** React 18, Vite 7, mock React-context store, pnpm. No test harness → verify via `npm run build` + grep + dev-run (a dispatch recommendation's rationale must quote a real skill/equipment value from the cited rep's profile).
|
||||||
|
|
||||||
|
**Spec/master:** `docs/superpowers/2026-05-29-MASTER-PLAN.md` §13 (profiles/skills/AI dispatch), Appendix A.3 (person & profile), A.7 (dispatch), Appendix G Plan 7. Builds on the canonical roster (Plan 1).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current state (verified)
|
||||||
|
|
||||||
|
- **People** split across: `MOCK_USERS` (login; field agents e1–e5 carry `xp`/`streakDays`/`achievements[]`), `MOCK_PERSONNEL` (p1 Jesus, p2 Sarah — `sensitiveData`/`compliance`), `MOCK_SUBCONTRACTORS` (sub_001–005 — `tradeType`/`rating`), `MOCK_OWNERS` (company dashboards). **No `profile`, `skillScores`, `bio`, `equipment`, `pronouns`, `nickname` on anyone; no `SKILL_CATALOG`.**
|
||||||
|
- **Self-edit page:** only `CustomerProfile.jsx` (`/portal/profile`, CUSTOMER only) edits name/email/phone/address via `updateProfile()` in `AuthContext`. **No User Details page for employee/owner/admin/contractor/subcontractor.**
|
||||||
|
- **Owner person view:** `PeopleDirectory.jsx` (`/owner/people`) lists only `personnel` (p1/p2) + `vendors` — **field agents e1–e5 and subs sub_001–005 don't appear**. Detail panel shows email/phone/masked SSN/compliance; "Edit Profile"/"Request Document" are **stubs**. No skill scores / internal notes anywhere. `VendorDirectory.jsx` shows `MOCK_VENDORS` (v1–v6, separate from subs).
|
||||||
|
- **Gamification:** `GamificationContext.jsx` is a single **global** `INITIAL_STATE` (xp 3360, level 12, streak 4 …) — NOT per-person. Field agents' `xp`/`streakDays`/`achievements` in MOCK_USERS are static + disconnected. `LEADERBOARD_MOCK` has fake names (Alex M., Jessica R., …).
|
||||||
|
- **LynkDispatch:** `DISPATCH_REPS` (mockStore ~line 4645) = **REP-01…05 with FAKE names** (Carlos Mendez, Aisha Kumar, Tom Bradley, Nina Patel, Derek Walsh) — **zero link to canonical people**. `DISPATCH_RECOMMENDATIONS` (~4842) have `{repId, score, slotStart/End, distanceMi, factors{proximity,driveTime,calendarFit,weather,skillMatch}, reasons[], stormReasons[], aiInsight, conflictFlag, routePath}` — rendered fully on screen (`DispatchRecommendationDrawer.jsx` shows factor bars + aiInsight + reasons chips). `skillMatch` is a static integer, not derived. `DISPATCH_LEADS_INITIAL` has fake `canvassedBy: {agentId:'U-05', name:'Marcus Webb'}` / `'U-07' Priya Nair`. `DISPATCH_WEEKLY_STATS.repBreakdown` keyed by REP-##.
|
||||||
|
- **Skills:** only `DISPATCH_REPS[].skills = ['insurance_claim','retail_estimate',…]` (plain strings). No catalog, no scores.
|
||||||
|
- **Routes:** no `/profile`/`/settings`/`/user-details` for non-customer roles; room for a universal profile route and a `/owner/people/:personId` detail.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schemas (target — per Appendix A.3)
|
||||||
|
|
||||||
|
Org-level skill catalog (in `mockStore.jsx`):
|
||||||
|
```js
|
||||||
|
export const SKILL_CATALOG = [
|
||||||
|
{ id: 'sk_insurance_claim', name: 'Insurance Claim Handling', description: 'Files & negotiates carrier claims/supplements.' },
|
||||||
|
{ id: 'sk_roof_inspection', name: 'Roof Inspection', description: 'Damage assessment, measurements, documentation.' },
|
||||||
|
{ id: 'sk_emergency_tarp', name: 'Emergency Tarp', description: 'Rapid storm tarp / water mitigation.' },
|
||||||
|
{ id: 'sk_retail_estimate', name: 'Retail Estimate', description: 'Cash/retail bid preparation & close.' },
|
||||||
|
{ id: 'sk_electrical', name: 'Electrical', description: 'Panel/wiring/EV per NEC.' },
|
||||||
|
{ id: 'sk_drone_survey', name: 'Drone Survey', description: 'Aerial roof imaging & measurement.' },
|
||||||
|
{ id: 'sk_customer_comms', name: 'Customer Communication', description: 'Homeowner rapport & expectation-setting.' },
|
||||||
|
];
|
||||||
|
```
|
||||||
|
Per-person `profile` (added to the canonical people):
|
||||||
|
```js
|
||||||
|
profile: {
|
||||||
|
self: { // person edits; owner can view
|
||||||
|
preferredName, photo, phone, altContact, address, emergencyContact,
|
||||||
|
nickname, pronouns, gender, sex, // all optional
|
||||||
|
bio, yearsExperience, languages: [], specialties: [], equipment: [],
|
||||||
|
availability, serviceAreas: [],
|
||||||
|
// subcontractors also:
|
||||||
|
license, insurance: { coi, expiry }, w9Status,
|
||||||
|
},
|
||||||
|
company: { // owner/admin only
|
||||||
|
internalNotes, statusTags: [], // 'preferred' | 'probation' | 'do-not-use' | ...
|
||||||
|
skillScores: [{ skillId, score }], // score = 0..100 or 'N/A'
|
||||||
|
payTerms, hireDate, managerId,
|
||||||
|
},
|
||||||
|
achievements: { level, xp, streak, badges: [], tiers: [] }, // employees; from MOCK_USERS gamification
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lane / ownership map
|
||||||
|
|
||||||
|
| Task | Lane (exclusive files) | Phase |
|
||||||
|
|------|------------------------|-------|
|
||||||
|
| T1 SKILL_CATALOG + profiles + store API | `src/data/mockStore.jsx` | A (seq) |
|
||||||
|
| T2 Dispatch remap + ground recommendations | `src/data/mockStore.jsx` | A (seq, after T1) |
|
||||||
|
| T3 Self-service User Details page | new `src/pages/UserDetailsPage.jsx`, `src/App.jsx` | B (parallel) |
|
||||||
|
| T4 Owner Person Details view | `src/pages/owner/PeopleDirectory.jsx` | B (parallel) |
|
||||||
|
| T5 Skill Catalog editor + leaderboard names | `src/pages/owner/OrgSettings.jsx`, `src/context/GamificationContext.jsx` | B (parallel) |
|
||||||
|
| T6 Verify | (read-only) | C |
|
||||||
|
|
||||||
|
**Phase A (T1, T2) sequential** — both edit `mockStore.jsx` (T2's dispatch grounding cites T1's profile data). **Phase B (T3, T4, T5) parallel** — disjoint files (T3 owns App.jsx + the new page). **T6** last.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: Skill catalog + profiles + store API
|
||||||
|
|
||||||
|
**Files:** `src/data/mockStore.jsx` only.
|
||||||
|
|
||||||
|
- [ ] **Step 1:** Add the `SKILL_CATALOG` constant (above) near the other exported constants. Expose it on the store context value as `skillCatalog`.
|
||||||
|
- [ ] **Step 2:** Add a `profile` object (per the schema above) to each canonical person who needs one — at minimum the **5 field agents (e1–e5)**, the **2 reps (p1, p2)**, and the **5 subcontractors (sub_001–005)**; owners (own_001/002) and admins (a1–a3) get a lighter `self`+`company` (no skillScores required but allowed). Author realistic values: bios, `yearsExperience`, `languages`, `equipment` (e.g. Cody Tatum: `['ladder rack','drone','tarp kit']`; Carlos Mendoza: `['tarp','panel tester','bucket truck']`), `serviceAreas` (Plano zips), and `company.skillScores` referencing `SKILL_CATALOG` ids with 0–100 (or `'N/A'`) — make the scores tell a story (e.g. Cody 92 emergency_tarp + 88 insurance_claim; Maya Patel high roof_inspection). Subs get `license`/`insurance`/`w9Status`. Add `company.statusTags` (most 'preferred'; one 'probation' for variety), `payTerms`, `hireDate`, `managerId`.
|
||||||
|
- [ ] **Step 3:** Populate `profile.achievements` for the field agents from their existing `MOCK_USERS` fields — `{ level: <derive from xp>, xp, streak: streakDays, badges: achievements, tiers: [] }`. (Use the GamificationContext level-title thresholds for a level number, or store xp and let the UI derive.)
|
||||||
|
- [ ] **Step 4 — store API:** add to the context value:
|
||||||
|
- `resolveProfile(personId)` — returns the person's `profile` (merged onto their base identity from `resolvePerson`), or a sensible empty default.
|
||||||
|
- `updateOwnProfile(personId, selfPatch)` — shallow-merges into `profile.self` (used by the self-service page).
|
||||||
|
- `setSkillScore(personId, skillId, score)` — upserts a `company.skillScores` entry.
|
||||||
|
- `addCatalogSkill(skill)` / `updateCatalogSkill(id, patch)` — manage `SKILL_CATALOG` (owner). Follow the existing `updateProject`-style `setX(prev => …)` pattern; store people in a state array if not already (profiles live on the existing people arrays — pick ONE canonical place to store the editable profile, e.g. a `profiles` state map keyed by personId, seeded from the people, so edits don't require mutating four different arrays). Expose `profiles` + the mutators.
|
||||||
|
- [ ] **Step 5 (verify):** `npm run build` → `✓ built`, 0 duplicate-key warnings. `git grep -c "skillScores" -- src/data/mockStore.jsx` ≥ 12; `SKILL_CATALOG` exported; `resolveProfile`/`updateOwnProfile`/`setSkillScore` on the context value.
|
||||||
|
- [ ] **Step 6:** commit `git commit -am "feat(data): add org skill catalog + two-layer person profiles + profile store API"`.
|
||||||
|
|
||||||
|
## Task 2: Remap dispatch reps + ground recommendations in profile facts
|
||||||
|
|
||||||
|
**Files:** `src/data/mockStore.jsx` only. **After T1.**
|
||||||
|
|
||||||
|
- [ ] **Step 1 — remap `DISPATCH_REPS`** to canonical people. For each REP-##, set `personId` to a field agent (REP-01→e1 Cody Tatum, REP-02→e2 Hannah Reyes, REP-03→e3 Travis Boone, REP-04→e4 Shelby Greer, REP-05→e5 Dalton Pruitt) and set `name`/`initials` to that person; replace the `skills: [...]` string array with the catalog skill ids the person scores highest on (from their `profile.company.skillScores`). Keep lat/lng/capacity/rating/closeRate. (Keep `id: 'REP-##'` if changing it is risky, but add `personId`; OR switch `id` to the person id — your call, just make recommendations resolve.)
|
||||||
|
- [ ] **Step 2 — fix other fake ids:** `DISPATCH_LEADS_INITIAL.canvassedBy` (`U-05 Marcus Webb`, `U-07 Priya Nair`) → canonical field agents (e.g. e1 Cody Tatum, e2 Hannah Reyes). `DISPATCH_WEEKLY_STATS.repBreakdown` keys → re-key to the canonical person/rep ids used in Step 1.
|
||||||
|
- [ ] **Step 3 — ground `DISPATCH_RECOMMENDATIONS`:** rewrite each recommendation's `reasons[]`, `stormReasons[]`, `aiInsight`, and `factors.skillMatch` so they **cite the cited rep's real profile facts**:
|
||||||
|
- `factors.skillMatch` = the rep's actual `skillScore` for the skill the lead needs (e.g. an insurance-claim lead → the rep's `sk_insurance_claim` score).
|
||||||
|
- `reasons[]` include a fact-citing chip, e.g. `"Insurance Claim 92/100 — top-rated for carrier work"`, `"Carries a tarp + drone on the truck"` (from `profile.self.equipment`).
|
||||||
|
- `aiInsight` references a concrete fact: e.g. `"Cody scores 92 on Emergency Tarp and carries a tarp kit — best fit for a storm-window job."`
|
||||||
|
Each recommendation must be traceable: the number/equipment it cites must EXIST in the cited rep's profile (this is the acceptance test).
|
||||||
|
- [ ] **Step 4 (verify):** `npm run build` → `✓ built`. `git grep -n "Nina Patel\|Derek Walsh\|Carlos Mendez\|Marcus Webb\|Priya Nair" -- src/data/mockStore.jsx` → **none** (fake names gone). Spot-check 2 recommendations: the skill score / equipment cited matches the rep's profile.
|
||||||
|
- [ ] **Step 5:** commit `git commit -am "feat(dispatch): map dispatch reps to canonical people; ground recommendations in real profile facts"`.
|
||||||
|
|
||||||
|
## Task 3: Self-service User Details page
|
||||||
|
|
||||||
|
**Files:** Create `src/pages/UserDetailsPage.jsx`; edit `src/App.jsx`. **Phase B (parallel).**
|
||||||
|
|
||||||
|
- [ ] **Step 1:** Build `UserDetailsPage.jsx` — the logged-in person (`useAuth().user`) edits THEIR OWN `profile.self`. Pull `resolveProfile(user.id)` + `updateOwnProfile` from the store. Sections (editable): **Identity** (preferredName, nickname, pronouns, gender, sex — all optional, clearly labelled optional; photo as a URL/objectURL upload), **Contact** (phone, altContact, address, emergencyContact), **About** (bio, yearsExperience, languages, specialties, equipment — equipment as add/remove chips), **Availability** (availability, serviceAreas). For subcontractors also show **Credentials** (license, insurance COI + expiry, w9Status). On save, call `updateOwnProfile(user.id, patch)`. Show the **read-only** `achievements` (level/xp/streak/badges) if present. Do NOT show the `company` layer (that's owner-only). Match app dark styling.
|
||||||
|
- [ ] **Step 2 (routes):** import the page; add a universal route `/profile` → `UserDetailsPage`, gated to all internal roles `['OWNER','ADMIN','FIELD_AGENT','CONTRACTOR','SUBCONTRACTOR']` (customers keep `/portal/profile`). Add a nav/menu entry if there's an obvious place (e.g. the user dropdown) — optional.
|
||||||
|
- [ ] **Step 3 (verify):** `npm run build` → `✓ built`. Dev-run as a field agent (login a field agent) → `/profile` shows their profile; editing nickname/equipment and saving persists in session.
|
||||||
|
- [ ] **Step 4:** commit `git commit -am "feat(profile): self-service User Details page for all internal roles"`.
|
||||||
|
|
||||||
|
## Task 4: Owner Person Details view
|
||||||
|
|
||||||
|
**Files:** `src/pages/owner/PeopleDirectory.jsx` only. **Phase B (parallel).**
|
||||||
|
|
||||||
|
- [ ] **Step 1:** Expand the directory's people source to include the **field agents (e1–e5)** and **subcontractors (sub_001–005)** alongside `personnel` — pull from the store (the people arrays / `users`) so the owner sees the whole roster, grouped or filterable by role.
|
||||||
|
- [ ] **Step 2:** Build/extend the detail panel to a full **Person Details** view showing BOTH layers (owner is authorised): the `self` profile (bio, contact, equipment, specialties, availability, achievements badges) AND the `company` layer (internalNotes, statusTags, payTerms, hireDate, manager) AND a **Skill Scores** table — each `SKILL_CATALOG` skill with the person's score (0–100 bar or 'N/A').
|
||||||
|
- [ ] **Step 3 (owner editing):** let the owner **set skill scores** (a number input / slider per catalog skill → `setSkillScore(personId, skillId, value)`) and edit `internalNotes`/`statusTags`. Wire the previously-stub "Edit"/notes affordances. (Skill catalog DEFINITION lives in Org Settings — T5; here the owner just scores people against the catalog.)
|
||||||
|
- [ ] **Step 4 (verify):** `npm run build` → `✓ built`. Dev-run as owner → People shows e1–e5 + subs; opening a person shows self+company+skill scores+achievements; setting a score persists and is reflected (and would feed dispatch).
|
||||||
|
- [ ] **Step 5:** commit `git commit -am "feat(owner): Person Details view — full roster, two-layer profile, skill scoring"`.
|
||||||
|
|
||||||
|
## Task 5: Skill Catalog editor + canonical leaderboard
|
||||||
|
|
||||||
|
**Files:** `src/pages/owner/OrgSettings.jsx`, `src/context/GamificationContext.jsx`. **Phase B (parallel).**
|
||||||
|
|
||||||
|
- [ ] **Step 1 (OrgSettings):** add a **Skill Catalog** section where the owner manages `skillCatalog` — list each skill (name + description), add a new skill (`addCatalogSkill({ id, name, description })`), and edit existing (`updateCatalogSkill`). Match the OrgSettings styling/section pattern.
|
||||||
|
- [ ] **Step 2 (GamificationContext):** replace the fake `LEADERBOARD_MOCK` names (Alex M., Jessica R., …) with the canonical field agents (Cody Tatum, Hannah Reyes, Travis Boone, Shelby Greer, Dalton Pruitt) and plausible XP values consistent with their `MOCK_USERS.xp`. Keep the logged-in-user substitution behavior.
|
||||||
|
- [ ] **Step 3 (verify):** `npm run build` → `✓ built`. Owner can add a skill in Org Settings (appears in the catalog + as a scorable row on Person Details). Leaderboard shows canonical names.
|
||||||
|
- [ ] **Step 4:** commit `git commit -am "feat(skills): org skill-catalog editor; canonicalize ProCanvas leaderboard names"`.
|
||||||
|
|
||||||
|
## Task 6: Verify (read-only)
|
||||||
|
|
||||||
|
- [ ] `npm run build` clean, 0 duplicate-key warnings.
|
||||||
|
- [ ] **No fake people left in dispatch/gamification:** `git grep -nE "Nina Patel|Derek Walsh|Carlos Mendez|Aisha Kumar|Tom Bradley|Marcus Webb|Priya Nair|Alex M\.|Jessica R\." -- src` → none.
|
||||||
|
- [ ] **Dispatch grounded (the headline acceptance):** pick 2 `DISPATCH_RECOMMENDATIONS`; the `skillMatch` value and any skill/equipment named in `reasons`/`aiInsight` EXIST in the cited rep's `profile.company.skillScores` / `profile.self.equipment`. Dev-run: open LynkDispatch → a recommendation card shows a canonical rep + a rationale that quotes a real number ("Emergency Tarp 92/100 · carries a tarp").
|
||||||
|
- [ ] **Profiles:** ≥ 12 people have `profile` with skillScores; `SKILL_CATALOG` exported + editable in Org Settings.
|
||||||
|
- [ ] **Self page:** a field agent can open `/profile`, edit their self layer (nickname/equipment), save, and see it persist; the `company` layer is NOT shown to them.
|
||||||
|
- [ ] **Owner view:** owner Person Details shows self+company+skill scores+achievements for e1–e5 and subs; setting a skill score persists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-review checklist
|
||||||
|
- [ ] `SKILL_CATALOG` + per-person two-layer `profile` (self/company/achievements) added; store API (`resolveProfile`/`updateOwnProfile`/`setSkillScore`/`addCatalogSkill`) exposed.
|
||||||
|
- [ ] Dispatch reps mapped to canonical field agents; recommendations cite real skill scores + equipment; all fake names gone (dispatch, canvassedBy, weekly stats, leaderboard).
|
||||||
|
- [ ] Self-service User Details page (all internal roles) edits the self layer only; achievements read-only; company layer hidden.
|
||||||
|
- [ ] Owner Person Details shows the full roster + both layers + skill scoring; Org Settings edits the catalog.
|
||||||
|
- [ ] Build clean; a dispatch rationale demonstrably quotes a value that exists in the cited rep's profile.
|
||||||
|
|
||||||
|
## Notes for Plan 8
|
||||||
|
Plan 8 (ABAC) replaces the role checks that gate the `company` profile layer + skill scoring with policies (`can(subject, 'view', profile, {field:'company'})`), and the coarse route guards with the policy engine. The `resolveProfile` self/company split here is exactly the field-level visibility ABAC will formalise. Org Settings (skill catalog editor here) becomes the policy/attribute editor too.
|
||||||
Reference in New Issue
Block a user