# Portal Pro — feature backlog

Ideas discussed but not built. Each notes what it would lean on in the existing codebase and
where the Classic Era API constrains it, so none of that has to be re-derived later.

Ordered roughly by value-for-effort, not priority.

---

## 1. Guild mage coordination

Broadcast a lightweight **claim** when you answer a lead (`CLAIM:<name>`), so a guildmate
running Portal Pro sees "Riverfrost is handling this" and their card greys out instead of
both of you whispering the same customer seconds apart.

Same channel could **pool market observations** — three mages in different cities produce a
far better median than one. Observations already carry name + timestamp, so dedup-on-merge
is trivial.

**Leans on:** `Modules/Comms.lua` (the prefix, registration and throttling already exist).
**Constraint:** Classic addon messages can't reach Trade. Guild/group/say only — it
coordinates your guild, not the server.

---

## 2. Customer queue with position whispers

When four people want ports at once they have no idea you've seen them, so they wander off.
Give each lead a ticket number and auto-whisper *"you're #3, about two minutes"*, updating as
the queue drains.

**Leans on:** the lead queue and whisper templates. Nearly free.

---

## 3. Price experiments

We know what competitors charge. We don't know **what converts for us**. Record the price in
effect when each lead arrives, then report conversion by price point:

> at 10g: 34 leads → 6 paid (18%) · at 8g: 29 leads → 9 paid (31%)

**Leans on:** leads, ledger, timestamps — all already captured.
**Needs:** one new field, the price in effect at lead-creation time.

---

## 4. Rune economics

Two halves:

- **Measured cost** — hook merchant purchases and use the `MoneyWatch` delta to learn what
  you actually paid per rune, replacing the configured guess that currently drives the whole
  cost basis. Makes Net measured rather than partly assumed.
- **Burn rate** — "~40 minutes of stock at tonight's pace", plus a pre-session shopping list.

**Leans on:** `Reagents`, `MoneyWatch`, `Stats`.

---

## 5. Cast guard

A pre-flight line before you open a portal: **this group member hasn't paid** · **they asked
for UC, you're casting SW** · **no rune for this**.

The two expensive mistakes are free portals and wrong cities. Every input is already tracked.

**Constraint:** it can only warn, not block — intercepting a cast needs secure code that
can't be rewritten in combat.

---

## 6. Customer profiles

Extend the ledger's customer index into something the lead card shows: usual destination,
average tip, ports bought, last seen, private notes. Preselect their usual city.

Folds in **deadbeat tracking** — joined the group, took the portal, never traded — as a
reliability score, so `4 ports · 1 unpaid` appears *before* you invite.

---

## 7. Whisper threads

Two panes in the Leads tab: queue left, conversation right. Transcript opens with their
original Trade message, then all whispers both ways. Template strip plus a free-text
composer, because half of every exchange is "which bank?".

**Design decisions already settled:**
- Observes, never intercepts — must not fight WIM. No chat-frame filtering.
- `CHAT_MSG_WHISPER_INFORM` captures replies you type manually, so the thread stays complete.
- Threads outlive their leads: paid leads leave the queue, and the thread must not vanish
  mid-conversation.
- Session-only by default. Persisting other players' private messages to disk should be
  opt-in.
- Unread pips on the queue card.

**Constraints:** no backfill (only whispers received while loaded). At a 720px window a
300px thread pane needs a compact lead-card variant.

---

## 8. Ledger reconciliation

Compare what the ledger *says* you earned this session against what your gold actually did.
`MoneyWatch` already observes every copper change and fires `MONEY_AMBIENT` for anything no
source claimed — an event currently fired with **no subscriber at all**. Accumulate those:

> Ledger says +42g this session. Your gold moved +38g. **4g unaccounted at 20:14.**
> Was that a portal sale? [ Record it → ]

**Why it matters:** this is the feature that would have caught the dropped trade payment by
itself, instead of it being noticed days later by eye. It makes the ledger self-auditing,
which is the difference between numbers you consult and numbers you trust.

**Leans on:** `MoneyWatch` (gives `MONEY_AMBIENT` a purpose), `Ledger`, `Stats`.
**Caveat:** vendors, repairs, loot and mail all move gold, so divergence isn't error. Frame
it as "unattributed", never "missing", and let the user classify it.

---

## 9. Undercut alerts

The Market tab is passive — you have to go and look. Make it reach you instead:

> Riverfrost just advertised **6g**. You're asking 10g.

**Leans on:** the market feed, already live and classified.
**Caveat:** needs hard throttling or it's noise on a busy realm. Once per advertiser per
price change, and only when they go below *you*.

---

## 10. Trade window helper

When a trade opens with someone in the lead queue or customer history, show what they should
be paying, and colour the amount as they put gold up — red until it meets the asking price,
green once it does.

> Shekza · Undercity · **50s expected**

**Why it matters:** stops you accepting a short payment. Right now that's only discoverable
afterwards, from the "under asking by 20s" note on the ledger row.

**Leans on:** `TRADE_SHOW`, `GetTargetTradeMoney` (both already wired in `TradeWatch`).
**Caveat:** it's an overlay anchored to Blizzard's trade frame, so it must attach without
altering the frame's own behaviour.

---

## 11. Per-character attribution

The ledger is account-wide but profiles are per-character, so two mages blur into one set of
figures. Add a `character` field to entries plus a filter.

**Why it matters:** anyone running a mage main and a mage alt currently has per-character
numbers that mean nothing.

**Caveat:** existing entries have no character recorded. Show them as "unknown" rather than
guessing — a ledger that invents attribution is worse than one that admits a gap.

---

## 12. Non-English lead detection

The scoring rules are English-only. EU realms are full of German, French, Russian and
Spanish speakers asking for portals, and Portal Pro is deaf to all of them.

**Leans on:** the `Locales/` system, and the rules are already a plain data table.
**Caveat:** needs native speakers. Machine-translated keywords will misfire in both
directions, so this wants to be a community-contributable table, not a guess.

---

## 13. Margin guard

We know the rune cost and the asking price. Warn when a price sits below cost — selling at
15s with a 20s rune loses money on every cast and nothing currently says so. Show margin per
portal beside each price in Settings.

**Leans on:** `Reagents:UnitCost()` and `Dest:Price()`. Cheap, and prevents a real mistake.

---

## 14. Custom detection rules

The scoring engine is a data table — 19 positive patterns, 14 negative. Expose it, with the
`/pp test` scorer built into the same screen so a new rule can be tried before it's kept.
Realm slang varies ("pls prt", "tp to sw", "port pl0x").

**Caveat:** a malformed user pattern would throw inside the chat handler. Each custom rule
needs its own `pcall`, and a rule that errors should disable itself and say so.

---

## 15. Guild auto-advertising

We documented early on that `SAY`, `YELL` and `CHANNEL` need a hardware event — and then
built the entire Broadcaster around that constraint. But **`GUILD` and `OFFICER` are not
gated.** A guild advert can genuinely go out on a timer while you're AFK, legally, with no
button and no arm mode.

That asymmetry has been sitting unused since day one. Guilds are where repeat customers and
word-of-mouth actually come from, and guildmates are the people most likely to pay without
haggling.

**Leans on:** `Broadcaster` (templates, throttle and validation already exist — it only
needs a non-gated send path and a timer).
**Caveat:** etiquette. Opt-in, off by default, minimum interval of ~15 minutes, and a hard
stop if anyone objects. An addon that spams guild chat gets the *player* disliked, not just
the addon.

---

## 16. Lead source attribution

Every lead already records the channel it came from. Nothing reports on it:

> Trade: 68 leads → 8 paid (12%) · LFG: 12 leads → 5 paid (42%) · Say: 9 → 4 (44%)

**Why it matters:** it tells you where to spend your broadcast cooldown. If LFG converts at
three times Trade, that's a different evening. Distinct from the demand-by-destination idea
— that's *which city*, this is *which channel*.

**Leans on:** `lead.channel` and the ledger. The data is already captured; only the report is
missing.

---

## 17. Ad A/B testing

Price experiments measure what price converts. This measures what *wording* converts.
Ads already rotate, and leads can already be attributed to whichever ad was live.

> "Portals 8g, inv for group" - 31% · "{rt1} Ports to any city {rt1}" - 12%

**Leans on:** ad rotation, lead timestamps, the ledger.
**Caveat:** needs enough volume per ad to mean anything. Show the sample size next to the
percentage and stay quiet below ~20 leads, or it's just noise presented as insight.

---

## 18. First-run setup

Right now a new user lands in a dark window with seven tabs and no idea which of them
matters. Four questions would fix it: what do you charge, which cities can you reach, which
channels should I watch, and do you want auto-whisper on?

**Why it matters:** this is the single biggest lever on CurseForge reviews. Most people who
uninstall an addon do it in the first two minutes, and never because of a missing feature.

**Leans on:** the existing widget kit; it's a layout over settings that already exist.

---

## 19. Colourblind-safe palette

The entire status language is red / green / amber — the exact combination red-green
colourblindness flattens. Positive and negative ledger rows, the market verdict, the
cooldown bar, the "not logging" badge: all of it collapses for roughly 1 in 12 men.

**Leans on:** `UI/Theme.lua`. Every colour in the addon already resolves through tokens, so
this is genuinely one alternative palette table plus a setting — the groundwork is done.
**Caveat:** colour can't be the *only* signal. Pair it with the sign already present on
figures (`+`/`-`) and the existing text labels, so the palette is a refinement rather than
the fix.

---

## 20. Vendor restock prompt

`MERCHANT_SHOW` plus the rune count you already track:

> You're at a reagent vendor with 6 Runes of Portals. Tonight's pace burns ~14/hour.

**Why it matters:** the moment you're standing at the vendor is the only moment this is
actionable, and it's exactly when nobody thinks about it. Pairs with the rune-economics idea
— that one works out the burn rate, this one puts it in front of you at the right second.

**Caveat:** only when the vendor actually stocks runes, or it fires at every merchant.

---

## 21. Whisper rate awareness

Blizzard squelches accounts that whisper too many strangers too fast. Portal Pro throttles
per-recipient (3s) but has no view of the total rate, and a busy evening with auto-whisper
on could quietly walk into a mute.

Track sends per minute, warn as it climbs, and make the ceiling configurable.

**Why it matters:** the addon already takes a clear position on spam and conservative
defaults. Protecting the account is the logical completion of that, not an extra.

---

## Smaller ideas

- **AFK auto-responder** — whisper "back in 5" while you're away from the bank.
- **Settings export string** — share ad templates and pricing with guildmates, reusing the
  copy popup already built for the About tab links.
- **Demand by destination** — which cities people actually ask for, versus what you charge
  for them. Distinct from price experiments: that measures conversion, this measures volume.

---

## Earlier ideas, still open

- **Batch fulfilment** — group leads by destination so one rune serves several customers
  heading to the same city. Three 10g sales for one 20s rune instead of three.
- **Earning heatmap** — when and where to sit. Needs the zone recorded at lead time.
- **One-click "serve next"** — cast the right portal for the front customer, announce, arm
  cleanup. Needs a `SecureActionButtonTemplate`; macro text can only be rewritten out of
  combat, so it's reliable while parked at a bank but can't retarget mid-fight.
