Phase 0 foundation: canonical schema, ingest pipeline, CRM MCP server
Workstream A–C substrate for the Ten31 agentic system: - A1: docs/crm-overview.md; CLAUDE.md conventions + guardrail #9 - A2: additive/reversible core migration (canonical_entities, entity_links, interaction_log, relationship_edges, soft-delete) + ledgered runner - B1/B3: chunking + deterministic entity resolution (backend/ingest) - B2: dense (bge-m3) + BM25 sparse ingest to Qdrant crm_chunks - C: CRM MCP server (reads, retrieval modes, logged writes) — no outbound tools - docs: redaction/re-hydration, Gmail enablement runbook - synthetic test data; .env.example; housekeeping (.gitignore, untrack crm.db, drop legacy files + start9/0.3.5) Verified end-to-end on synthetic data + live Sparks (hybrid > dense on entity queries). Real backfill runs on Ten31 infra; index holds synthetic data only. Branch snapshot also captures pre-existing working-tree changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { VersionInfo } from '@start9labs/start-sdk'
|
||||
|
||||
// Frontend convenience release: persist auth across page reloads.
|
||||
//
|
||||
// Background: through 0.1.0:40 the auth token + user object were held only
|
||||
// in React state in memory. Any refresh, tab close, or browser restart
|
||||
// dropped the token and forced the user back to the login screen. Since
|
||||
// the JWT is signed with /data/.crm-secret (which already survives sideloads
|
||||
// and container restarts), the underlying token is still valid for its full
|
||||
// 24-hour lifetime — we just weren't keeping it anywhere persistent.
|
||||
//
|
||||
// 0.1.0:41 stores the JWT and user object in localStorage on login (and
|
||||
// rehydrates from there on app mount), so refreshes and reopened tabs stay
|
||||
// signed in until the token expires. The api() helper now also dispatches
|
||||
// a 'crm:unauthorized' event whenever an authenticated request comes back
|
||||
// with a 401, and the AuthProvider listens for that event to clear the
|
||||
// stored auth — so an expired or rejected token immediately bounces the
|
||||
// user back to the login screen instead of leaving the app in a broken
|
||||
// "loaded but every request fails" state.
|
||||
//
|
||||
// Backend is unchanged: the JWT still carries the user's true role and is
|
||||
// re-verified on every request, so a tampered localStorage user object
|
||||
// cannot escalate privileges (the next admin call would just 401/403).
|
||||
//
|
||||
// No data migration is required.
|
||||
export const v_0_1_0_41 = VersionInfo.of({
|
||||
version: '0.1.0:41',
|
||||
releaseNotes: {
|
||||
en_US: [
|
||||
'Logins now persist across page refreshes and tab closures for',
|
||||
'the full 24-hour token lifetime. Previously every reload bounced',
|
||||
'you to the login screen even though the token was still valid.',
|
||||
'If the server later rejects a stored token (expired, secret key',
|
||||
'changed, etc.) the app automatically clears it and shows the',
|
||||
'login screen instead of leaving requests silently failing.',
|
||||
].join(' '),
|
||||
},
|
||||
migrations: {
|
||||
up: async () => {},
|
||||
down: async () => {},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user