tju-yxq opened a new issue, #5163:
URL: https://github.com/apache/rocketmq-dashboard/issues/5163

   ## Problem
   
   Custom AI prompt templates are stored under a single global `localStorage` 
key, so every account that signs in through the same browser profile shares the 
same custom template list: after operator A saves a template and signs out, 
operator B signs in on the same browser and immediately sees, applies, and 
deletes A's templates — including any incident-specific wording A considered 
private.
   
   ## What did you do (steps to reproduce)?
   
   1. Sign in to RocketMQ Studio as user `alice` on a shared workstation 
browser (or any browser whose profile outlives the login session).
   2. Open the AI page, click **模板 / Templates** in the composer.
   3. In the save-current section at the bottom, enter a title such as `Orders 
incident`, paste a body with internal context (e.g. broker names, topic names, 
escalation notes), and save. The template is listed with the `custom` tag.
   4. Sign out (`alice` → 登出), then sign in as a different user `bob` in the 
same browser.
   5. Open the AI page → **Templates** again.
   
   ## What did you expect to see?
   
   Only the built-in runbook templates plus `bob`'s own custom templates. 
`alice`'s saved template should not be readable, applicable, or deletable by 
`bob` — the browser profile is shared infrastructure, but a saved prompt is the 
operator's personal snippet tied to their account.
   
   ## What did you see instead?
   
   `alice`'s `Orders incident` template is listed for `bob` with the `custom` 
tag. `bob` can apply it into the composer (the internal context is disclosed in 
full), and delete it — silently removing `alice`'s work. The catalog also 
carries over across every subsequent login, because nothing in the storage 
layout distinguishes one account from another.
   
   ## Root cause
   
   `web/src/pages/ai/promptTemplates.ts` keeps all custom templates under one 
fixed key with no account dimension:
   
   - `web/src/pages/ai/promptTemplates.ts:61` — `export const 
PROMPT_TEMPLATE_STORAGE_KEY = 'rocketmq-studio-ai-prompt-templates';` is a 
single constant;
   - `web/src/pages/ai/promptTemplates.ts:279` — `readCustomPromptTemplates` 
reads exactly that key;
   - `web/src/pages/ai/promptTemplates.ts:310` — `writeCustomPromptTemplates` 
writes exactly that key;
   - `web/src/pages/ai/promptTemplates.ts:371` — delete removes exactly that 
key.
   
   The AI page knows who is signed in (`useAuthStore` exposes `userId` and 
`user`), but the storage layer never receives that information: 
`loadPromptTemplateCatalog`, `saveCustomPromptTemplate`, and 
`deleteCustomPromptTemplate` take no owner argument, and their only caller, 
`web/src/pages/ai/components/PromptTemplateModal.tsx` (lines 127-189 at 
`master@0228dad5`), calls them without any account context. One key + no owner 
= one shared list for every account on the browser profile.
   
   ## Expected behavior
   
   1. Custom templates are stored under an account-scoped key derived from the 
signed-in user (e.g. `rocketmq-studio-ai-prompt-templates:v2:user-id:<id>`), so 
each account reads and writes only its own list.
   2. Built-in templates remain shared and unchanged.
   3. The legacy shared key is handled safely on first read:
      - In unauthenticated single-user mode, the legacy catalog migrates to the 
scoped key (preserving the operator's existing templates).
      - When an authenticated account is signed in, the legacy ownerless 
catalog is **not** assigned to that account — assigning it to whichever account 
opens the page first would preserve exactly the cross-account disclosure this 
change is meant to remove. The legacy key is cleared instead.
   4. Corrupt stored JSON keeps the repair behaviour from #4575 (parse failure 
reads as an empty, writable list) on the scoped keys.
   
   ## Acceptance criteria
   
   - [ ] A regression test that saves a template under one authenticated owner 
and loads the catalog under a second authenticated owner: it must see zero 
custom templates (this test fails on the unfixed source, where both owners 
share one key).
   - [ ] A test that the legacy shared key does not leak into an authenticated 
user's catalog and is removed after the first read.
   - [ ] A test that the legacy shared key still migrates in unauthenticated 
single-user mode.
   - [ ] The corrupt-JSON repair test from #4575 keeps passing against the 
scoped keys.
   - [ ] Save / apply / delete in the template modal operate only on the 
signed-in account's list.
   
   ## Environment
   
   - Branch: `master` @ `0228dad5` (2026-09-29)
   - Files involved: `web/src/pages/ai/promptTemplates.ts`, 
`web/src/pages/ai/components/PromptTemplateModal.tsx`
   - Authenticated session shape: `useAuthStore` → `{ user: string | null, 
userId: number | null }`
   
   ## Other information
   
   The prompt template library was introduced in #4215 (client-side 
`localStorage` design) and its corrupt-storage repair landed in #4575; neither 
change gave the storage an account dimension. This issue is about the sharing 
defect that becomes visible the moment two operators share a browser profile, 
which both of those changes left intact.
   
   ## Duplicate check
   
   Searched open and closed issues/PRs for `"prompt template"` combined with 
`user`, `localStorage`, `account`, `shared`, `scoped`. Only #4215 (the original 
library) and #4575 (corrupt-storage repair) match, and neither addresses 
per-account scoping. No existing issue tracks this defect.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to