roadmap changes
Build Images and Deploy / Update-PROD-Stack (push) Successful in 1m21s

This commit is contained in:
2026-03-18 18:28:50 -04:00
parent e8a5165047
commit b763e011e9
3 changed files with 54 additions and 117 deletions
+40 -103
View File
@@ -329,109 +329,7 @@ The items below are planned improvements roughly ordered by user value. They are
---
### 1. Username Display Names & Password Changes on Profile
**Problem:** Usernames are forced lowercase on registration (some users want "JohnDoe" not "johndoe"). Users also have no self-service way to change their password.
**Plan:**
- Add a `displayUsername` field to `User` — stores the original mixed-case version typed at signup. Lookups/URLs continue using the lowercase `username` for uniqueness and consistency.
- Profile settings page (`/profile/[username]/settings` or a tab on the existing profile) with:
- **Change display name** — updates `displayUsername` only; the canonical `username` remains lowercase and immutable (avoids breaking existing links/positions).
- **Change username** — updates both `username` and `displayUsername`; requires confirming no conflicts; all foreign key relations in Prisma use the DB `id` so no cascade issues.
- **Change password** — classic current-password + new-password + confirm form; server endpoint `PATCH /api/user/me` validating current hash before updating.
- All places that show a username (Navbar, profile page, leaderboard, trade history) should render `displayUsername` if set, falling back to `username`.
---
### 2. Leaderboard
**Problem:** No public way to see who the top players are or browse other users' portfolios.
**Plan:**
- New page `/leaderboard` showing top N players sorted by **net worth** (balance + sum of position value at current prices).
- Table columns: rank, avatar/username link → their public profile, net worth, total trades, biggest single position.
- Public profiles — any user can view `/profile/[username]`; sensitive data (exact balance) optionally hidden from non-owners/non-admins.
- Navbar: show **Leaderboard** link when signed in (replacing or supplementing the current unauthenticated-only links).
- Consider a separate "all-time best trade" leaderboard tab for engagement.
---
### 3. Lucky Dip Lottery
**Problem:** Players who go broke have no recovery mechanic; there is no daily engagement hook beyond trading.
**Plan:**
- New page `/lottery`.
- Once per day (tracked by a `lastLotteryAt` timestamp on `User`), a player who has **$0 or less** can reveal one hidden box from a grid (e.g. 5 × 5 = 25 boxes).
- One box is the winner (selected server-side at draw time, stored encrypted or revealed only on pick to prevent client-side cheating).
- **Prizes** (configurable): e.g. one box pays $100, a few pay $10, the rest pay $0.
- API: `POST /api/lottery/pick` — validates cooldown, selects winner server-side, awards balance, returns outcome.
- Consider allowing players with any balance to play for a small stake (e.g. pay $5 to play, win up to $200) to make it useful beyond the broke scenario.
- Future: admin-configurable prize pool and grid size.
---
### 4. Home Page Nav Changes (Signed-In vs Signed-Out)
**Problem:** Home page shows the same call-to-action links regardless of auth state.
**Plan:**
- When **signed out**: show Sign Up / Sign In CTAs as currently.
- When **signed in**: replace or supplement with quick links to **Leaderboard**, **Lottery**, and the user's own profile.
- Navbar already hides/shows some items; extend that logic to the hero section of the home page.
---
### 5. Related Hashtags
**Problem:** No discovery path from one hashtag to related ones.
**Plan:**
- During price update jobs the worker already fetches up to 200 posts. Parse each post's `tags` array (present in the Mastodon API response) to collect co-occurring hashtags.
- Store co-occurrence counts in a new `RelatedHashtag` table: `(hashtagId, relatedTag, coOccurrences)` — upsert on each price update, incrementing counts.
- On the hashtag detail page, show the top 5 most co-occurring tags as "Related" chips that link to their own pages.
- Only surface related tags that are themselves active (or researchable) — avoid surfacing banned/inactive noise.
- Worker change: `MastodonPost` type already has `content`; add `tags: { name: string }[]` to the interface and parse it in `mastodon.ts`.
---
### 6. Admin: Price Audit Log
**Problem:** Admins have no visibility into the math behind a given price update.
**Plan:**
- The `PriceHistory` table already stores `postsPerHour` alongside `price`. Surface this in two places:
1. **Hashtag detail page** — show the most recent `postsPerHour` reading and the formula result as a tooltip or sub-line under the current price (e.g. _"$1.49 — 5.96 posts/hr at last update"_).
2. **Admin stocks page** — add a "History" drawer/modal per hashtag showing the last N `PriceHistory` rows as a table: `recordedAt | postsPerHour | price | Δ price` so admins can see the full audit trail.
- No schema changes needed — `postsPerHour` is already stored.
---
### 7. Admin: Add Hashtag Manually
**Problem:** Admins cannot bypass the research-point system to seed the exchange with interesting hashtags.
**Plan:**
- "Add hashtag" button on `/admin/stocks` that opens a modal with a tag input.
- API: `POST /api/admin/stocks` — normalizes tag, queries Mastodon immediately (same as research flow), upserts hashtag, queues an initial price-update job. Returns error if Mastodon returns nothing.
- Optionally allow admin to force-add with a manual starting price even if Mastodon has no results (useful for bootstrapping/testing).
---
### 8. Admin: Ban / Block Hashtags
**Problem:** No way to prevent abusive or NSFW hashtags from being researched into the exchange.
**Plan:**
- Add `isBanned: Boolean @default(false)` field to the `Hashtag` model.
- Admin UI: "Ban" button on the stocks page that sets `isBanned = true` and `isActive = false`. Banned hashtags still exist in the DB for record-keeping but are not researchable.
- Research API (`/api/research`): check `isBanned` on any existing matching hashtag — if banned return a `403` with a user-friendly message (e.g. _"This hashtag is not available on HashEx."_) without spending a research point.
- New pre-ban blocklist: a static list (or admin-editable table) of tags that are auto-banned on first research attempt, before any Mastodon query.
- Banned tags should still appear in the admin stocks list with a distinct visual indicator and an "Unban" toggle.
---
### 9. Auto-Derive Display Casing from Mastodon Posts
### 1. Auto-Derive Display Casing from Mastodon Posts
**Problem:** `displayTag` is currently set once at research/creation time from whatever the user typed. In reality Mastodon users have an established "canonical" capitalisation for a tag (e.g. `#StPatricksDay` rather than `#stpatricksday`) and our display tag should reflect that.
@@ -445,6 +343,45 @@ The items below are planned improvements roughly ordered by user value. They are
---
### 2. Home Page Holdings Summary (Signed-In)
**Problem:** Signed-in users land on the home page and see only the generic trending list — there is no personalised hook to show how their portfolio is performing.
**Plan:**
- Add two summary cards above the "Trending now" section, visible only to signed-in users: **Biggest Gain** and **Biggest Loss** (by unrealised P&L across open positions).
- Both cards link to the relevant hashtag page.
- Implemented as a server component addition to `src/app/page.tsx`: query the current user's open positions (joined with current price) and compute unrealised P&L per position to find the top and bottom.
- If the user has no positions, the cards are omitted (no empty-state clutter).
- No schema changes required.
---
### 3. Search Autocomplete
**Problem:** The current search/research input is a plain text field with no discovery aid — users must know or guess full hashtag names.
**Plan:**
- While the user types in the search box, show a dropdown of matching hashtags that are **already tracked** on the exchange (fetched from a new `GET /api/hashtags/search?q=` endpoint).
- The autocomplete only surfaces existing active hashtags; submitting a tag that doesn't appear in the list still proceeds through the normal research flow (no interference with new-hashtag discovery).
- Client-side: debounce the input (~300 ms), cancel in-flight requests on new keystrokes, close dropdown on `Escape` or outside click.
- Endpoint: case-insensitive prefix match on `Hashtag.tag` where `isActive = true` and `isBanned = false`, returning `{ tag, displayTag, currentPrice }` for up to 8 results.
- No schema changes required.
---
### 4. Open Positions Full Page
**Problem:** The profile page shows open positions in a compact list — there is no space for richer per-position data (cost basis, current value, a mini P&L chart).
**Plan:**
- New page `/positions` (auth-protected) showing only the signed-in user's open positions in a more detailed layout.
- Each row / card: hashtag name + link, position type (LONG/SHORT), shares held, average buy price, current price, total cost basis, current value, unrealised P&L and P&L %, a sparkline chart of the hashtag's recent price history.
- Link into this page from the "Open positions" heading on the profile page.
- No new nav item needed — accessed via profile page link.
- No schema changes required.
---
### Other Ideas / Nice-to-Haves
- **Hedge funds**: group of players pool money into a shared portfolio, one designated fund manager places trades.