Task 9 — product-expert-ff-agent (PR 10)
Gate: Phase 0 merged
Vuex module: frontend/src/store/modules/product/expert/ff-agent/index.js
New file: frontend/src/stores/product-expert-ff-agent.js
Persistence: context, sessionId → localStorage (cleared on logout)
No external dependencies — this is a leaf store.
9.1 — Create the Pinia store
// frontend/src/stores/product-expert-ff-agent.js
import { defineStore } from 'pinia'
import { markRaw } from 'vue'
export const useProductExpertFfAgentStore = defineStore('product-expert-ff-agent', {
state: () => ({
context: null,
sessionId: null,
messages: [],
sessionStartTime: null,
sessionWarningShown: false,
sessionExpiredShown: false,
sessionCheckTimer: null
}),
actions: {
reset () {
if (this.sessionCheckTimer) clearInterval(this.sessionCheckTimer)
Object.assign(this, {
context: null, sessionId: null, messages: [],
sessionStartTime: null, sessionWarningShown: false,
sessionExpiredShown: false, sessionCheckTimer: null
})
},
setSessionCheckTimer (timer) {
this.sessionCheckTimer = markRaw(timer)
}
},
persist: {
pick: ['context', 'sessionId'],
storage: localStorage
}
})
Note on sessionCheckTimer: This is a setInterval reference. Use markRaw() to prevent Vue from proxying it. The setSessionCheckTimer action handles this. The parent product-expert store is the only caller.
9.2 — No component consumers
This store is only accessed by the parent product-expert store. No component updates needed.
9.3 — Do not delete the Vuex module yet
The parent product/expert Vuex module still references this as a nested module. Delete both in PR 12 when product-expert ships.
Logout bridge: uncomment useProductExpertFfAgentStore().$reset() in the Vuex logout action (Task 0.7).
9.4 — Write store tests
// frontend/src/tests/stores/product-expert-ff-agent.spec.js
import { setActivePinia, createPinia } from 'pinia'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { useProductExpertFfAgentStore } from '@/stores/product-expert-ff-agent.js'
describe('product-expert-ff-agent store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
it('initializes with null session and empty messages', () => {
const store = useProductExpertFfAgentStore()
expect(store.sessionId).toBeNull()
expect(store.messages).toEqual([])
})
it('reset clears interval and resets all state', () => {
const store = useProductExpertFfAgentStore()
const fakeTimer = setInterval(() => {}, 9999)
const clearSpy = vi.spyOn(globalThis, 'clearInterval')
store.setSessionCheckTimer(fakeTimer)
store.sessionId = 'sess-abc'
store.reset()
expect(clearSpy).toHaveBeenCalledWith(fakeTimer)
expect(store.sessionId).toBeNull()
expect(store.messages).toEqual([])
clearInterval(fakeTimer)
})
it('setSessionCheckTimer stores the timer reference', () => {
const store = useProductExpertFfAgentStore()
const fakeTimer = setInterval(() => {}, 9999)
store.setSessionCheckTimer(fakeTimer)
expect(store.sessionCheckTimer).toBe(fakeTimer)
clearInterval(fakeTimer)
})
})
9.5 — Export from stores index
export { useProductExpertFfAgentStore } from './product-expert-ff-agent.js'
Task 9 —
product-expert-ff-agent(PR 10)Gate: Phase 0 merged
Vuex module:
frontend/src/store/modules/product/expert/ff-agent/index.jsNew file:
frontend/src/stores/product-expert-ff-agent.jsPersistence:
context,sessionId→ localStorage (cleared on logout)No external dependencies — this is a leaf store.
9.1 — Create the Pinia store
Note on
sessionCheckTimer: This is asetIntervalreference. UsemarkRaw()to prevent Vue from proxying it. ThesetSessionCheckTimeraction handles this. The parentproduct-expertstore is the only caller.9.2 — No component consumers
This store is only accessed by the parent
product-expertstore. No component updates needed.9.3 — Do not delete the Vuex module yet
The parent
product/expertVuex module still references this as a nested module. Delete both in PR 12 whenproduct-expertships.Logout bridge: uncomment
useProductExpertFfAgentStore().$reset()in the Vuex logout action (Task 0.7).9.4 — Write store tests
9.5 — Export from stores index