Skip to content

ci: deploy production through GitHub Actions - #80

Merged
imharrisonking merged 2 commits into
devfrom
chore/reliable-preview-cleanup
Sep 22, 2026
Merged

imharrisonking merged 2 commits into
devfrom
chore/reliable-preview-cleanup

Conversation

@imharrisonking

Copy link
Copy Markdown
Contributor

Summary

  • Trigger the existing SST deployment workflow on pushes to both dev and production.
  • Reuse the existing production AWS role, Cloudflare credentials, SST deploy, and database migration steps.

This allows the merged production branch to deploy through GitHub Actions after SST Console autodeploy is disabled.

@imharrisonking
imharrisonking merged commit 951ca23 into dev Sep 22, 2026
2 of 3 checks passed
imharrisonking added a commit that referenced this pull request Sep 23, 2026
* 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 (#77)

* 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 (#78)

* ci: deploy production through GitHub Actions (#80)

* fix: clean preview stages for closed PRs

* ci: deploy production through GitHub Actions
@imharrisonking
imharrisonking deleted the chore/reliable-preview-cleanup branch September 24, 2026 17:20

This branch was successfully deployed

1 active deployment
dev — ae8369b2 Deployed Sep 22, 2026 by imharrisonking via Destroy Preview Environment #19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant