mirror of
https://github.com/hanzoai/chat.git
synced 2026-09-30 20:51:17 +00:00
Four lines on the empty chat: the model picker, the modes and their sources, /agent, and the sidebar. It dims nothing and gates nothing -- the arrival modal was removed by owner call, and this sits beside the product rather than in front of it. `toured` carries no schema default. `false` shows the card, `true` has seen it, and ABSENT is an account older than the card, which never gets one; a default reaches every record that lacks the field, which is every account that already exists. `reconcileUser` writes `false` at creation, so exactly the accounts born from here on qualify. The client tests `=== false` for the same reason, and the spec fails when that is weakened to a falsy check. It rides out on `GET /v1/chat/user`, which already sends the projected document, so there is no second GET to keep in step -- one POST records the dismissal, and the cached user is written on mutate so the card goes on the click rather than a round-trip later. In the flow, under the composer, not floating over it. The composer block is min-h-[280px] at the bottom of that column and its input is capped and centred, leaving ~142px of gutter at 1440 against a card that needs 304 -- measured in Chromium against the built stylesheet: 288x252 at 16px from the column edge, clear of the composer at 1440 and at 390, no sideways scroll, 17.25:1 on the title and 12.82:1 on the lines.
47 lines
1.7 KiB
JavaScript
47 lines
1.7 KiB
JavaScript
const express = require('express');
|
|
const {
|
|
updateUserPluginsController,
|
|
getTermsStatusController,
|
|
acceptTermsController,
|
|
tourController,
|
|
deleteUserController,
|
|
getUserController,
|
|
} = require('~/server/controllers/UserController');
|
|
const {
|
|
configMiddleware,
|
|
canDeleteAccount,
|
|
requireJwtAuth,
|
|
requireGuestOrJwtAuth,
|
|
} = require('~/server/middleware');
|
|
|
|
const settings = require('./settings');
|
|
|
|
const router = express.Router();
|
|
|
|
router.use('/settings', settings);
|
|
router.get('/', requireGuestOrJwtAuth, getUserController);
|
|
router.get('/terms', requireJwtAuth, getTermsStatusController);
|
|
router.post('/terms/accept', requireJwtAuth, acceptTermsController);
|
|
router.post('/tour', requireJwtAuth, tourController);
|
|
router.post('/plugins', requireJwtAuth, updateUserPluginsController);
|
|
router.post('/active-org', requireJwtAuth, (req, res) => {
|
|
// Pin the active org for downstream api.hanzo.ai calls. Fail closed: the org must
|
|
// be in the caller's own membership set (owner + IAM `groups`); the gateway then
|
|
// re-validates X-Org-Id ∈ the verified JWT membership set (HIP-0026).
|
|
const requested = String(req.body?.organization ?? '').trim();
|
|
const allowed = new Set([req.user?.organization, ...(req.user?.groups ?? [])].filter(Boolean));
|
|
if (!requested || !allowed.has(requested)) {
|
|
return res.status(400).json({ error: 'organization not in your memberships' });
|
|
}
|
|
res.cookie('hanzo_active_org', requested, {
|
|
httpOnly: true,
|
|
sameSite: 'lax',
|
|
secure: process.env.NODE_ENV === 'production',
|
|
maxAge: 1000 * 60 * 60 * 24 * 30,
|
|
});
|
|
return res.json({ organization: requested });
|
|
});
|
|
router.delete('/delete', requireJwtAuth, canDeleteAccount, configMiddleware, deleteUserController);
|
|
|
|
module.exports = router;
|