fix: resolve 8 review/security issues (SPRINT-016 hotfix)

Security:
- JwtGuard + RoleGuard on all sisters endpoints
- Admin-only access for config/sessions/subagents/activity
- ThrottlerGuard on /auth/refresh
- HttpOnly SameSite cookies + CSRF (replaces localStorage)

Code Quality:
- Per-sister draft input (Record<SisterName, string>)
- crypto.randomUUID for optimistic message ids (dedupe ready)
- Polling disabled while WebSocket connected
- SVG keyboard accessibility (role/tabIndex/onKeyDown)
This commit is contained in:
2026-04-09 08:21:28 +09:00
parent 658d5e7af7
commit 90968810ff
12 changed files with 477 additions and 103 deletions

View File

@@ -353,7 +353,15 @@ export default function OfficePage() {
void fetchAll();
// Polling fallback
// Fix #3: Polling only when socket is not connected
// Socket handles live updates; polling is a disconnected fallback
return () => {};
}, []);
// Polling fallback — only when socket is disconnected
useEffect(() => {
if (connected) return; // socket is live, no polling needed
const interval = setInterval(() => {
fetch(`${API_URL}/api/sisters`)
.then((r) => r.json())
@@ -364,7 +372,7 @@ export default function OfficePage() {
}, POLL_INTERVAL_MS);
return () => clearInterval(interval);
}, []);
}, [connected]);
const hasSisterSnapshot = sisters.length > 0;
const sisterDataMode: 'live' | 'snapshot' | 'fallback' = connected