ci: enable GitHub Actions production deployment - #81
Merged
Merged
Conversation
…(iss-014) and TanStack AI stack (iss-013)
…proxy, server-loaded history, gpt-5.6-luna
…document-flow (#72) * docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle * docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018 * feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017) Three switchable layout variants (rail / breadcrumb-menu / document-flow) for the chat sessions chrome, driven by an in-memory mock of the locked Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search param and a floating switcher. - add assistant-ui registry components (thread, thread-list, markdown, tools, suggestions, attachments); keep Structa primitives; drop the composer stop button (Q7) and gate sending while a run is in-flight - add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/ extractText), engine (immutable session store, retry-as-new-run Q6), adapter (ExternalStoreAdapter with inline thread list), use-mock-chat - add pure-logic unit tests for fold + scripts - fix repo-level gate breakage blocking preview deploys: restore react-dropzone dep (removed with app-example), sync its accept prop to v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes out of the @theme block in app.css * feat(web): move prototype chat sessions into sidebar Recent chats - AppSidebar adopts the mock chat while /app/prototype-chat is active: 'New chat' now creates a session, 'Recent chats' lists the mock sessions (active highlight, running dot, delete action) - NavMockChats: mock sessions rendered as a sidebar group wired to the mock engine - NavMain: items can render as buttons (onClick) instead of links - ChatRail: drop the sessions aside (now in the sidebar); full-width thread baseline for the variant comparison - thread.tsx: message content uses text-base (14px) to match the app base size instead of inheriting the 16px browser default * fix(web): show suggestions in prototype new-chat welcome view The composer.isEmpty gate never fired with the external-store runtime, so welcome-state suggestions were dropped on empty threads. Gate on the new-chat view alone; suggestions stay visible while composing. * fix(web): render welcome-state suggestions from thread suggestions ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which external-store runtimes never populate (fallback is an empty resource), so welcome-state suggestion pills never rendered on empty threads. Render them directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which takes the prompt and works with our adapter. * feat(web): add chat previews to prototype sidebar * feat(web): use chat previews as sidebar labels * fix(web): use modal chat rename and normalize markdown text * fix(web): normalize user message paragraph size * feat(web): enable prototype chat attachments * feat(web): wire prototype attachment uploads * fix(web): keep prototype switcher clear of composer
* docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle * docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018 * feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017) Three switchable layout variants (rail / breadcrumb-menu / document-flow) for the chat sessions chrome, driven by an in-memory mock of the locked Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search param and a floating switcher. - add assistant-ui registry components (thread, thread-list, markdown, tools, suggestions, attachments); keep Structa primitives; drop the composer stop button (Q7) and gate sending while a run is in-flight - add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/ extractText), engine (immutable session store, retry-as-new-run Q6), adapter (ExternalStoreAdapter with inline thread list), use-mock-chat - add pure-logic unit tests for fold + scripts - fix repo-level gate breakage blocking preview deploys: restore react-dropzone dep (removed with app-example), sync its accept prop to v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes out of the @theme block in app.css * feat(web): move prototype chat sessions into sidebar Recent chats - AppSidebar adopts the mock chat while /app/prototype-chat is active: 'New chat' now creates a session, 'Recent chats' lists the mock sessions (active highlight, running dot, delete action) - NavMockChats: mock sessions rendered as a sidebar group wired to the mock engine - NavMain: items can render as buttons (onClick) instead of links - ChatRail: drop the sessions aside (now in the sidebar); full-width thread baseline for the variant comparison - thread.tsx: message content uses text-base (14px) to match the app base size instead of inheriting the 16px browser default * fix(web): show suggestions in prototype new-chat welcome view The composer.isEmpty gate never fired with the external-store runtime, so welcome-state suggestions were dropped on empty threads. Gate on the new-chat view alone; suggestions stay visible while composing. * fix(web): render welcome-state suggestions from thread suggestions ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which external-store runtimes never populate (fallback is an empty resource), so welcome-state suggestion pills never rendered on empty threads. Render them directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which takes the prompt and works with our adapter. * feat(web): add chat previews to prototype sidebar * feat(web): use chat previews as sidebar labels * fix(web): use modal chat rename and normalize markdown text * fix(web): normalize user message paragraph size * feat(web): enable prototype chat attachments * feat(web): wire prototype attachment uploads * fix(web): keep prototype switcher clear of composer * fix(ci): make PR environment cleanup recoverable
* docs: map production chat workspace execution
* feat(chat): add persisted conversation foundation
* feat(chat): add Clerk run contract foundation
* feat(chat): wire Clerk provider run persistence
* fix(ci): allow providerless PR chat previews
* fix(deploy): keep previews providerless and resolve core drizzle
* feat(chat): promote production workspace into app
* feat(chat): persist new conversations on first send
* perf(preview): use generated URLs for PR environments
* fix(chat): include project context in run requests
* docs(ci): clarify generated preview URLs
* fix(ci): publish actual preview resource URLs
* fix(ci): resolve preview URLs from SST resources
* fix(ci): expose actual SST preview endpoints
* fix(ci): use stack Web and Api outputs
* feat(chat): switch Clerk provider to OpenRouter
* feat(ci): allow OpenRouter credentials in preview deploys
* fix(ci): use SST OpenRouter fallback in previews
* fix(infra): rename OpenRouter SST secret
* feat(chat): add durable production conversation runtime
* feat(chat): improve conversation navigation and actions
* chore(dev): add Caddy HTTP2 development proxy
* docs(architecture): map durable automation platform
* style(marketing): normalize navigation typography
* feat(chat): seal Cloudflare env, harden data service materialize
- Remove Cloudflare `environment` block; DB URL, DataServiceToken and
OpenRouter key now flow only via SST link -> secret_text bindings
(previously readable as plain_text through the Workers settings API)
- env.ts: parse `SST_RESOURCE_*` link bindings (Database/DataServiceToken/
OpenRouterApiKey) with per-secret getters and OPENROUTER_MODEL fallback
- materialize: skip gracefully when the chat_sessions row is missing (direct
Worker calls without a backend-created session must not flip a run to error)
- run materialize after the run-complete broadcast, wrapped in its own
try/catch so a Neon failure can never change the run outcome
- core package.json: exact exports keys for ./conversation/chat.sql and
./conversation/conversation.sql (double-wildcard keys are invalid)
- infra api/web: use dataService.url instead of dataService.properties.url
- fix unused handleWebSocket param (biome)
* test(functions): add data service E2E verification scripts
Repeatable E2E suites for the Cloudflare data service:
- e2e-data-service.mjs: 15 checks — auth, tickets, run lifecycle, WS
stream, DO SQLite persistence, event replay (service-auth path)
- e2e-materialize.mjs: 8 checks — Neon materialization happy path
(assistant message, run complete, last_message_at bump, relative
baseline compare to stay timezone-robust)
Usage: DATA_SERVICE_TOKEN=$TOKEN node scripts/e2e-data-service.mjs [base-url]
DATA_SERVICE_TOKEN=$TOKEN DATABASE_URL=$URL node scripts/e2e-materialize.mjs [base-url]
* chore(functions): add npm scripts for data service E2E suites
* feat(chat): ship persisted conversation foundation to production (#75) * ci: add --print-logs to PR Cleanup SST commands for diagnostics * docs: reorganize docs/ into space-based structure * docs: remove old docs/ structure (migrated to docs/core/) * docs: migrate issues to .issues/ with template * docs: migrate specs to .plan/ and remove dormant artifacts * docs: update all references to new doc paths * feat: add GitHub issue sync, agent skills setup, and chat wayfinder map * docs: resolve chat wayfinder decisions — durable stream architecture (iss-014) and TanStack AI stack (iss-013) * docs: resolve chat run endpoint & transport decision (iss-015) — web proxy, server-loaded history, gpt-5.6-luna * feat: Removes app-example package, no longer needed as a reference * feat: Removes marketing-site-example package, not longer needed as a reference * feat: Updates app.css and styling of components in components/ui * feat(web): prototype chat UX layouts (iss-017) — rail / breadcrumb / document-flow (#72) * docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle * docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018 * feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017) Three switchable layout variants (rail / breadcrumb-menu / document-flow) for the chat sessions chrome, driven by an in-memory mock of the locked Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search param and a floating switcher. - add assistant-ui registry components (thread, thread-list, markdown, tools, suggestions, attachments); keep Structa primitives; drop the composer stop button (Q7) and gate sending while a run is in-flight - add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/ extractText), engine (immutable session store, retry-as-new-run Q6), adapter (ExternalStoreAdapter with inline thread list), use-mock-chat - add pure-logic unit tests for fold + scripts - fix repo-level gate breakage blocking preview deploys: restore react-dropzone dep (removed with app-example), sync its accept prop to v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes out of the @theme block in app.css * feat(web): move prototype chat sessions into sidebar Recent chats - AppSidebar adopts the mock chat while /app/prototype-chat is active: 'New chat' now creates a session, 'Recent chats' lists the mock sessions (active highlight, running dot, delete action) - NavMockChats: mock sessions rendered as a sidebar group wired to the mock engine - NavMain: items can render as buttons (onClick) instead of links - ChatRail: drop the sessions aside (now in the sidebar); full-width thread baseline for the variant comparison - thread.tsx: message content uses text-base (14px) to match the app base size instead of inheriting the 16px browser default * fix(web): show suggestions in prototype new-chat welcome view The composer.isEmpty gate never fired with the external-store runtime, so welcome-state suggestions were dropped on empty threads. Gate on the new-chat view alone; suggestions stay visible while composing. * fix(web): render welcome-state suggestions from thread suggestions ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which external-store runtimes never populate (fallback is an empty resource), so welcome-state suggestion pills never rendered on empty threads. Render them directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which takes the prompt and works with our adapter. * feat(web): add chat previews to prototype sidebar * feat(web): use chat previews as sidebar labels * fix(web): use modal chat rename and normalize markdown text * fix(web): normalize user message paragraph size * feat(web): enable prototype chat attachments * feat(web): wire prototype attachment uploads * fix(web): keep prototype switcher clear of composer * fix(ci): make PR environment cleanup recoverable (#73) * docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle * docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018 * feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017) Three switchable layout variants (rail / breadcrumb-menu / document-flow) for the chat sessions chrome, driven by an in-memory mock of the locked Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search param and a floating switcher. - add assistant-ui registry components (thread, thread-list, markdown, tools, suggestions, attachments); keep Structa primitives; drop the composer stop button (Q7) and gate sending while a run is in-flight - add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/ extractText), engine (immutable session store, retry-as-new-run Q6), adapter (ExternalStoreAdapter with inline thread list), use-mock-chat - add pure-logic unit tests for fold + scripts - fix repo-level gate breakage blocking preview deploys: restore react-dropzone dep (removed with app-example), sync its accept prop to v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes out of the @theme block in app.css * feat(web): move prototype chat sessions into sidebar Recent chats - AppSidebar adopts the mock chat while /app/prototype-chat is active: 'New chat' now creates a session, 'Recent chats' lists the mock sessions (active highlight, running dot, delete action) - NavMockChats: mock sessions rendered as a sidebar group wired to the mock engine - NavMain: items can render as buttons (onClick) instead of links - ChatRail: drop the sessions aside (now in the sidebar); full-width thread baseline for the variant comparison - thread.tsx: message content uses text-base (14px) to match the app base size instead of inheriting the 16px browser default * fix(web): show suggestions in prototype new-chat welcome view The composer.isEmpty gate never fired with the external-store runtime, so welcome-state suggestions were dropped on empty threads. Gate on the new-chat view alone; suggestions stay visible while composing. * fix(web): render welcome-state suggestions from thread suggestions ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which external-store runtimes never populate (fallback is an empty resource), so welcome-state suggestion pills never rendered on empty threads. Render them directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which takes the prompt and works with our adapter. * feat(web): add chat previews to prototype sidebar * feat(web): use chat previews as sidebar labels * fix(web): use modal chat rename and normalize markdown text * fix(web): normalize user message paragraph size * feat(web): enable prototype chat attachments * feat(web): wire prototype attachment uploads * fix(web): keep prototype switcher clear of composer * fix(ci): make PR environment cleanup recoverable * feat(chat): add persisted conversation foundation (#74) * docs: map production chat workspace execution * feat(chat): add persisted conversation foundation * feat(chat): add Clerk run contract foundation * feat(chat): wire Clerk provider run persistence * fix(ci): allow providerless PR chat previews * fix(deploy): keep previews providerless and resolve core drizzle * feat(chat): promote production workspace into app * feat(chat): persist new conversations on first send * perf(preview): use generated URLs for PR environments * fix(chat): include project context in run requests * docs(ci): clarify generated preview URLs * fix(ci): publish actual preview resource URLs * fix(ci): resolve preview URLs from SST resources * fix(ci): expose actual SST preview endpoints * fix(ci): use stack Web and Api outputs * feat(chat): switch Clerk provider to OpenRouter * feat(ci): allow OpenRouter credentials in preview deploys * fix(ci): use SST OpenRouter fallback in previews * fix(infra): rename OpenRouter SST secret * feat(chat): add durable production conversation runtime * feat(chat): improve conversation navigation and actions * chore(dev): add Caddy HTTP2 development proxy * docs(architecture): map durable automation platform * style(marketing): normalize navigation typography * feat(chat): seal Cloudflare env, harden data service materialize - Remove Cloudflare `environment` block; DB URL, DataServiceToken and OpenRouter key now flow only via SST link -> secret_text bindings (previously readable as plain_text through the Workers settings API) - env.ts: parse `SST_RESOURCE_*` link bindings (Database/DataServiceToken/ OpenRouterApiKey) with per-secret getters and OPENROUTER_MODEL fallback - materialize: skip gracefully when the chat_sessions row is missing (direct Worker calls without a backend-created session must not flip a run to error) - run materialize after the run-complete broadcast, wrapped in its own try/catch so a Neon failure can never change the run outcome - core package.json: exact exports keys for ./conversation/chat.sql and ./conversation/conversation.sql (double-wildcard keys are invalid) - infra api/web: use dataService.url instead of dataService.properties.url - fix unused handleWebSocket param (biome) * test(functions): add data service E2E verification scripts Repeatable E2E suites for the Cloudflare data service: - e2e-data-service.mjs: 15 checks — auth, tickets, run lifecycle, WS stream, DO SQLite persistence, event replay (service-auth path) - e2e-materialize.mjs: 8 checks — Neon materialization happy path (assistant message, run complete, last_message_at bump, relative baseline compare to stay timezone-robust) Usage: DATA_SERVICE_TOKEN=$TOKEN node scripts/e2e-data-service.mjs [base-url] DATA_SERVICE_TOKEN=$TOKEN DATABASE_URL=$URL node scripts/e2e-materialize.mjs [base-url] * chore(functions): add npm scripts for data service E2E suites * chore: decommission Electric Cloud infrastructure * fix: normalize user dates before collection sync * fix: settle user updates in collection state * fix: make browser Buffer compatible with collection hashing * fix: let query collection reconcile user updates * fix: broadcast running chat runs for live streaming * fix: navigate and refresh new chat sessions * fix: normalize chat collection timestamps * fix: keep optimistic user messages in chat order * fix: preserve user before assistant run order * chore: remove legacy chat event table
* fix: clean preview stages for closed PRs * ci: deploy production through GitHub Actions
imharrisonking
had a problem deploying
to
dev
September 23, 2026 10:48 — with
GitHub Actions
Failure
imharrisonking
had a problem deploying
to
dev
September 23, 2026 10:56 — with
GitHub Actions
Failure
imharrisonking
had a problem deploying
to
dev
September 23, 2026 10:56 — with
GitHub Actions
Failure
Preview Environment
Quality checks passed
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Promotes the latest
devchanges to production, including the GitHub Actions deployment trigger for pushes toproduction.After this PR merges, the existing
deploy.ymlworkflow will run the production SST deployment and database migration automatically.SST Console autodeploy should remain disabled after confirming the GitHub production deployment succeeds.