From de4a72970f3f09bafab9de06af55f2d84725b172 Mon Sep 17 00:00:00 2001 From: Lily Shen Date: Mon, 4 May 2026 10:18:55 -0700 Subject: [PATCH] chore(demo): hide Plan/Execute toggle + add message backdate route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two unrelated demo-prep changes bundled to share a deploy cycle. 1. Hide the Plan/Execute mode toggle ------------------------------------- The pod-mode toggle persists `mode` to the pod but no downstream surface uses it for behavior — clicks land but nothing changes for the user, so the control reads as broken in any demo or dogfood context. Wrap the JSX in `{false && (...)}` with a comment naming the re-enable condition (downstream actually uses the field). Surgical revert: delete the wrapper. 2. PATCH /api/messages/:id/created-at — backdate route ------------------------------------------------------- Backdates a chat message's `created_at` (and `updated_at`). Pod-creator-only or message-author; no general-purpose user authorization to edit other people's chronology. Why this exists: chat-history demos / fixtures want plausible "yesterday afternoon / yesterday evening / this morning" timestamps, but POST /:podId always stamps with NOW(). Direct PG UPDATE works for ops with PG access; this route is the same capability when PG is firewalled (Aiven IP-allowlist + kubectl exec connection tracking blocking new sessions even from inside the cluster). Body: { created_at: ISO8601 string } Backed by the same long-lived PG pool as the rest of the messaging stack (`config/db-pg`), so no new connection profile is needed. Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/routes/messages.ts | 51 +++++++++++++++++++++++ frontend/src/v2/components/V2PodChat.tsx | 52 ++++++++++++++---------- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/backend/routes/messages.ts b/backend/routes/messages.ts index 900aa7b7..3705cb45 100644 --- a/backend/routes/messages.ts +++ b/backend/routes/messages.ts @@ -52,6 +52,57 @@ router.get('/:podId', auth, getMessages); router.post('/:podId', sendMessageRateLimit, auth, createMessage); router.delete('/:id', auth, deleteMessage); +// Backdate a message's `created_at`. Pod-creator-only (or message author); +// no general-purpose user authorization for editing other people's chronology. +// +// Why this exists: chat history demos / fixtures need plausible timestamps +// (yesterday / this morning / etc.) but POST /:podId always stamps with NOW(). +// Direct PG UPDATE works for ops with PG access; this route is the same +// capability for ops without PG access (Aiven IP-allowlisted, kubectl exec +// timing out on new sessions, etc.). +// +// Body: { created_at: ISO8601 string } +router.patch('/:id/created-at', auth, async (req: any, res: any) => { + try { + const { id } = req.params; + const { created_at: createdAtRaw } = req.body || {}; + const ts = createdAtRaw ? new Date(createdAtRaw) : null; + if (!ts || Number.isNaN(ts.getTime())) { + return res.status(400).json({ msg: 'created_at (ISO8601) is required' }); + } + + // Authorization: load the message, then check author or pod-creator. + // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require + const PGMessage = require('../models/pg/Message'); + // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require + const Pod = require('../models/Pod'); + const userId = req.userId || req.user?.id; + if (!userId) return res.status(401).json({ msg: 'auth required' }); + + const message = await PGMessage.findById(id); + if (!message) return res.status(404).json({ msg: 'message not found' }); + + if (String(message.user_id) !== String(userId)) { + const pod = await Pod.findById(message.pod_id); + if (!pod || String(pod.createdBy) !== String(userId)) { + return res.status(403).json({ msg: 'must be message author or pod creator' }); + } + } + + // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require + const { pool } = require('../config/db-pg'); + const r = await pool.query( + 'UPDATE messages SET created_at = $1, updated_at = $1 WHERE id = $2 RETURNING id, created_at', + [ts, id], + ); + if (r.rowCount === 0) return res.status(404).json({ msg: 'message not found in PG' }); + return res.json({ ok: true, id: r.rows[0].id, created_at: r.rows[0].created_at }); + } catch (err: any) { + console.error('backdate route error:', err?.message || err); + return res.status(500).json({ msg: 'backdate failed' }); + } +}); + module.exports = router; export {}; diff --git a/frontend/src/v2/components/V2PodChat.tsx b/frontend/src/v2/components/V2PodChat.tsx index 15216068..a839e078 100644 --- a/frontend/src/v2/components/V2PodChat.tsx +++ b/frontend/src/v2/components/V2PodChat.tsx @@ -572,28 +572,36 @@ const V2PodChat: React.FC = ({ detail, inspectorCollapsed, onTog )} -
- - -
+ {/* Plan / Execute mode toggle — hidden until the pod-mode workflow + ships end-to-end. Currently the toggle persists `mode` to the + pod but no downstream surface uses it for behavior, so the + control reads as broken — clicks land but nothing changes for + the user. Re-enable when the mode actually drives behavior + (agent autonomy gating, suggestion ranking, etc.). */} + {false && ( +
+ + +
+ )} {onOpenInvite && (