# Rank Interactive feature prioritization tool for `rank.friborg.uk`. ## Product definition Rank is a fast intake and prioritization board for product ideas from Jimmi and agents. Core loop: `Capture idea → score impact/effort/confidence/urgency → drag into milestone → revisit top-ranked work` Chosen subdomain: `rank.friborg.uk` — short, memorable, and honest about the job. ## UX principles - One-screen capture, no modal ceremony. - Keyboard-first: `/` focuses capture, Enter saves. - Plain sharp visual system: zero rounded corners, dark space/glass, high contrast. - Milestones are customizable lanes, not a rigid roadmap prison. - Agents can post ideas through the same API endpoint as the UI. ## Architecture - Node/Express app on port `3045` - Static SPA in `public/` - Appwrite TablesDB persistence - Docker deploy on Unraid - Gitea remote repo - Nginx Proxy Manager routes `rank.friborg.uk` → `192.168.30.100:3045` ## Appwrite schema Database: `priority_rank` Tables: - `ideas` — title, description, source, sourceName, milestoneId, impact, effort, confidence, urgency, score, rank, labels, notes, archived - `milestones` — name, description, horizon, color, position, active - `activity` — small append-only UX feed ## Scattermind → Ranker bridge Ranker's continuation job is narrow: `Snapshot / Concept Map → candidate feature/action set → Rank-ready build order` `POST /api/rank-feedback` accepts a `prioritix-feature-set-v1`-style payload from Scattermind and returns ranked items plus `buildOrder.doFirst / validateNext / defer / park`. It accepts candidate arrays as `features`, `actions`, `nextMoves`, or `candidates` either at the top level or under `featureSet`, and it can consume a nested Concept Map directly, so Scattermind can hand off `conceptMap.nextActions / nextMoves` without renaming them into fake software features. Sectioned Concept Maps may also include `validateNext`, `deferred`, and `parkingLot`; Ranker combines those sections into one build-order pass while preserving `sourceSection` and treating deferred/parked sections as lane hints. Empty wrapper arrays are ignored rather than allowed to shadow a real nested Concept Map action set, and non-empty normalized wrappers are merged with Concept Map validation/deferred/parking sections rather than dropping that context. That keeps partially-normalized Scattermind exports rankable without losing the source lane contract. It also returns a `brief` with source, next-48-hour actions, carried-forward assumptions/constraints/non-goals, and `whatWouldChangeRanking` checks, plus a `handoff` object (`rank-feedback-result-v1`) with source provenance, item trace rows, and contract warnings for missing artifact IDs, source sections, original prompt provenance, or evidence on active items. Keep this contract action-first; do not use it as a reason to add generic dashboard, auth, billing, or workspace layers before the bridge has proof. Candidate items may include optional 1–10 `rankerHints` (`value`, `effort`, `confidence`, `urgency`, `revenue`, `novelty`, `risk`). Ranker blends those explicit Scattermind hints with text heuristics; `effort` is inverted into feasibility. Hints improve the defended order, but `recommendedLane: "defer"` or `"park"` remains a safety rail so dashboard-swamp items do not get promoted by flashy wording. For clean bridge handoff, Scattermind should send `sourceSection` and `evidenceNeeded` on each active next move. Scattermind can also send `targetAudience`, `constraints`, `assumptions`, and `nonGoals` / `avoid` at the top level, in `featureSet`, or inside `conceptMap.context`; Ranker returns that decision context in `input.decisionContext` and `handoff.decisionContext`, and penalizes candidates that conflict with source non-goals (for example saved workspaces/auth/billing before the continuation proof). If Scattermind sends duplicate candidate IDs, Ranker keeps the first ID, suffixes later duplicates (`preview-2`), and reports the normalization in `handoff.warnings` / `handoff.itemTrace` so downstream build-order references remain addressable. Recommended payload shape: ```json { "schema": "prioritix-feature-set-v1", "sourceName": "Scattermind", "artifactId": "snapshot_or_concept_map_id", "snapshotTitle": "Plain idea title", "conceptMapId": "optional_concept_map_id", "originalPrompt": "The user's starting prompt, trimmed for provenance", "idea": "What Scattermind clarified", "context": "Important constraints: solo builder, non-AI-native user, avoid dashboard swamp, etc.", "mode": "mvp", "featureSet": { "features": [ { "id": "build-order-preview", "title": "Build order preview", "description": "Show do first, validate next, defer, and park with reasons.", "userValue": "A tired builder sees the next move without opening a dashboard.", "evidenceNeeded": "Can 3 non-AI-native users understand the first recommended action?", "proofSteps": ["Show a static result screen to 3 people"], "rankerHints": { "value": 8, "effort": 3, "confidence": 7, "urgency": 6, "revenue": 4, "novelty": 5, "risk": 3 }, "dependencies": [], "risk": "May become generic roadmap UI if the source context is lost.", "recommendedLane": "validate-next", "sourceSection": "concept-map.nextMoves" } ] } } ``` ## Commands ```bash npm run setup:appwrite npm run check PORT=3045 node server.js npm run smoke ``` Agent idea post: ```bash curl -X POST https://rank.friborg.uk/api/ideas \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $RANK_AGENT_TOKEN" \ -d '{"title":"Add public roadmap export","source":"agent","sourceName":"Rook","impact":8,"effort":3,"confidence":7,"urgency":5}' ```