feat: add workspaces with isolated channels, members, and invite system#193
feat: add workspaces with isolated channels, members, and invite system#193
Conversation
Introduce workspace support with path-based routing (/w/:slug/...), per-workspace admin roles, invite links with 1-hour expiration, and one Durable Object per workspace for WebSocket connections. Existing data auto-migrates into a seeded 'default' workspace. Migration uses PRAGMA defer_foreign_keys to handle the channels table rebuild safely on D1.
There was a problem hiding this comment.
Pull request overview
Adds first-class workspace support across the app, including workspace-scoped routing (/w/:slug/...), isolated data access, admin/member roles, and invite-based onboarding.
Changes:
- Introduces
workspaces,workspace_members, andworkspace_invitestables plus a migration to backfill existing data into a seededdefaultworkspace. - Updates channel/message/WS routes and client-side API calls to be workspace-scoped under
/w/:slug/.... - Adds workspace UI (workspace list page) and admin endpoints for invite/member management, plus updated tests.
Show a summary per file
| File | Description |
|---|---|
| hono/types.ts | Adds workspace-related types and context variables. |
| hono/static/ChatPage.ts | Scopes REST API calls under /w/:slug/api. |
| hono/routes/ws.ts | Moves WS endpoint to /w/:slug/ws and namespaces Durable Object by workspace slug. |
| hono/routes/ws.test.ts | Updates WS route tests for workspace-scoped paths and DO name. |
| hono/routes/workspaces.ts | Adds endpoints to list/create workspaces. |
| hono/routes/workspaceInvite.ts | Adds invite acceptance flow for joining a workspace. |
| hono/routes/workspaceAdmin.ts | Adds admin endpoints for invites and member role management. |
| hono/routes/messages.ts | Scopes messages endpoint under workspace and validates channel belongs to workspace. |
| hono/routes/messages.test.ts | Updates tests for workspace-scoped messages endpoint. |
| hono/routes/index.tsx | Adds workspace selection/redirect logic and /w/:slug chat page rendering. |
| hono/routes/index.test.tsx | Updates/extends tests for workspace redirect and workspace chat route behavior. |
| hono/routes/channels.ts | Scopes channel endpoints under workspace and enforces workspace isolation. |
| hono/routes/channels.test.ts | Updates tests for workspace-scoped channel endpoints. |
| hono/deployment.test.ts | Ensures new routes/components can be imported for deployment compatibility. |
| hono/db/seed.sql | Seeds default workspace and workspace-scoped general channel. |
| hono/db/schema.ts | Adds new workspace tables and rebuilds channels with workspace_id + scoped uniqueness. |
| hono/db/migrations/meta/0002_snapshot.json | Drizzle snapshot for the new schema/migration. |
| hono/db/migrations/meta/_journal.json | Registers migration 0002_add_workspaces. |
| hono/db/migrations/0002_add_workspaces.sql | Creates new tables, seeds default, rebuilds/migrates channels, backfills workspace members. |
| hono/components/WorkspacesPage.tsx | Adds server-rendered workspace list page. |
| hono/components/WorkspacesPage.css | Styling for the workspace list UI. |
| hono/components/ChatPage.tsx | Adds workspace context (title/header + data attributes) to chat page. |
| hono/components/ChatPage.test.ts | Updates/extends tests for workspace-scoped ChatPage rendering. |
| hono/auth/requireWorkspaceMember.ts | Adds middleware to enforce workspace membership and load workspace context. |
| hono/auth/requireWorkspaceAdmin.ts | Adds middleware to enforce admin role within a workspace. |
| hono/app.tsx | Registers new routes and applies workspace membership middleware to /w/:slug/.... |
| e2e/app.spec.ts | Updates title assertion for workspace-scoped chat page. |
Copilot's findings
- Files reviewed: 27/27 changed files
- Comments generated: 7
| workspace: Workspace; | ||
| workspaceMember: WorkspaceMember; |
There was a problem hiding this comment.
Variables marks workspace and workspaceMember as always present, but they’re only set by requireWorkspaceMember for /w/:slug... routes. On routes like /api/workspaces (which only uses requireUser) these values will be undefined at runtime while TypeScript treats them as defined, which can lead to unsafe c.get("workspace") usage. Make these variables optional (or split Env types for workspace-scoped vs global routes) so the typing matches reality.
| workspace: Workspace; | |
| workspaceMember: WorkspaceMember; | |
| workspace?: Workspace; | |
| workspaceMember?: WorkspaceMember; |
| await db.insert(workspaceMembers).values({ | ||
| workspaceId: defaultWorkspace.id, | ||
| userEmail: user.email, | ||
| role: "member", |
There was a problem hiding this comment.
New users with zero workspace memberships are inserted into the default workspace with role member. On a fresh install there may be no existing workspace admins (migration only promotes an existing member during upgrade), which means nobody can create invites or new workspaces and the system can’t be bootstrapped. Consider making the first member of the default workspace an admin when no members exist yet (or relax the workspace-creation restriction).
| await db.insert(workspaceMembers).values({ | |
| workspaceId: defaultWorkspace.id, | |
| userEmail: user.email, | |
| role: "member", | |
| const existingDefaultWorkspaceMembers = await db | |
| .select({ userEmail: workspaceMembers.userEmail }) | |
| .from(workspaceMembers) | |
| .where(eq(workspaceMembers.workspaceId, defaultWorkspace.id)); | |
| const initialRole = existingDefaultWorkspaceMembers.length === 0 ? "admin" : "member"; | |
| await db.insert(workspaceMembers).values({ | |
| workspaceId: defaultWorkspace.id, | |
| userEmail: user.email, | |
| role: initialRole, |
| const user = session.get("user") as User | undefined; | ||
|
|
||
| if (!user) { | ||
| return c.redirect("/auth/login"); | ||
| } | ||
|
|
There was a problem hiding this comment.
Because requireWorkspaceMember is applied to /w/:slug in app.tsx, unauthenticated requests to /w/:slug will return a JSON 401 from the middleware, so this handler’s redirect-to-login branch is unreachable and the behavior for page routes is inconsistent with / (which redirects). Either remove the redundant session check here or adjust the middleware/page routing so unauthenticated users get an HTML redirect instead of JSON.
| const user = session.get("user") as User | undefined; | |
| if (!user) { | |
| return c.redirect("/auth/login"); | |
| } | |
| const user = session.get("user") as User; |
| const workspaceIds = memberships.map((m) => m.workspaceId); | ||
| const allWorkspaces = await db.select().from(workspaces); | ||
| const userWorkspaces = allWorkspaces | ||
| .filter((w) => workspaceIds.includes(w.id)) | ||
| .map((w) => { |
There was a problem hiding this comment.
This endpoint loads all workspaces and filters them in JS. That does unnecessary DB work and won’t scale as workspace count grows. Prefer selecting only the user’s workspaces in SQL (e.g., where inArray(workspaces.id, workspaceIds) or a join from workspace_members to workspaces).
| @@ -1 +1,2 @@ | |||
| INSERT INTO channels (name, created_by_email) VALUES ('general', 'system'); | |||
| INSERT OR IGNORE INTO workspaces (name, slug, created_by_email) VALUES ('Default', 'default', 'system'); | |||
| INSERT OR IGNORE INTO channels (name, workspace_id, created_by_email) VALUES ('general', 1, 'system'); | |||
There was a problem hiding this comment.
seed.sql hard-codes workspace_id = 1 when inserting the general channel. If the default workspace’s id isn’t 1 (e.g., if data already exists or autoincrement has advanced), this will create a channel pointing at the wrong/non-existent workspace. Use a subquery to look up the workspace id by slug (or insert the workspace with an explicit id).
| INSERT OR IGNORE INTO channels (name, workspace_id, created_by_email) VALUES ('general', 1, 'system'); | |
| INSERT OR IGNORE INTO channels (name, workspace_id, created_by_email) | |
| SELECT 'general', id, 'system' | |
| FROM workspaces | |
| WHERE slug = 'default'; |
| <ul className="workspace-list"> | ||
| {workspaceList.map((w) => ( | ||
| <li className="workspace-item"> | ||
| <a href={`/w/${w.slug}`} className="workspace-link"> | ||
| <span className="workspace-name">{w.name}</span> | ||
| <span className="workspace-slug">/{w.slug}</span> | ||
| {w.role === "admin" && <span className="workspace-badge admin">Admin</span>} | ||
| </a> | ||
| </li> |
There was a problem hiding this comment.
The list rendering is missing a stable key on the <li> (or the <a>) element. This produces React/JSX warnings and can cause incorrect DOM diffing if the list changes. Add a key (e.g., w.id or w.slug) to the mapped element.
| workspaceInviteRoute.get("/w/:slug/invite/:code", requireUser, async (c) => { | ||
| try { | ||
| const db = getDb(c.env.DB); | ||
| const user = c.get("user"); | ||
| const slug = c.req.param("slug"); |
There was a problem hiding this comment.
Invite acceptance is implemented as a GET that mutates server state (inserts workspace/channel membership). This can be triggered unintentionally by link prefetching/crawlers and also enables “forced join” if a logged-in user is induced to load the URL. Consider serving a confirmation page on GET and performing the mutation on POST (with CSRF), or otherwise ensuring idempotent/non-mutating GET behavior.
…vite security - Make workspace/workspaceMember optional in Variables type to match runtime - First user auto-joining default workspace now becomes admin (bootstrap fix) - Remove unreachable auth check in /w/:slug (middleware already handles it) - Replace select-all-then-filter with SQL inner join for workspace queries - Use subquery in seed.sql instead of hardcoded workspace_id=1 - Convert invite acceptance from mutating GET to GET confirmation + POST
…194) * feat: add deployment tagging, GitHub Releases, and PR template Add a post-deploy step to deploy.yml that creates a git tag (deploy-YYYY-MM-DD-SHA) and a GitHub Release with auto-generated notes after each successful production deployment. This provides a clear history of which commits were deployed and when. Add a default PR template with a pre-deploy checklist covering CI status, migration review, secrets, and Durable Objects state. * Update .github/workflows/deploy.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: scope contents:write permission to deploy job only Agent-Logs-Url: https://github.com/mahata/mlack/sessions/b28d6893-dc36-48da-a24d-589cb4ad8e05 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * deps-dev(deps-dev): bump @cloudflare/workers-types (#164) Bumps [@cloudflare/workers-types](https://github.com/cloudflare/workerd) from 4.20260317.1 to 4.20260329.1. - [Release notes](https://github.com/cloudflare/workerd/releases) - [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md) - [Commits](https://github.com/cloudflare/workerd/commits) --- updated-dependencies: - dependency-name: "@cloudflare/workers-types" dependency-version: 4.20260329.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: add conventional-commit skill for Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * deps(deps): bump hono in the production-dependencies group (#168) Bumps the production-dependencies group with 1 update: [hono](https://github.com/honojs/hono). Updates `hono` from 4.12.9 to 4.12.11 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](honojs/hono@v4.12.9...v4.12.11) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump the development-dependencies group with 11 updates (#169) Bumps the development-dependencies group with 11 updates: | Package | From | To | | --- | --- | --- | | [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@playwright/test](https://github.com/microsoft/playwright) | `1.58.2` | `1.59.1` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `24.12.0` | `24.12.2` | | [@biomejs/cli-darwin-arm64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-darwin-x64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-linux-arm64-musl](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-linux-arm64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-linux-x64-musl](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-linux-x64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-win32-arm64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | | [@biomejs/cli-win32-x64](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.9` | `2.4.10` | Updates `@biomejs/biome` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@playwright/test` from 1.58.2 to 1.59.1 - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](microsoft/playwright@v1.58.2...v1.59.1) Updates `@types/node` from 24.12.0 to 24.12.2 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@biomejs/cli-darwin-arm64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-darwin-x64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-linux-arm64-musl` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-linux-arm64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-linux-x64-musl` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-linux-x64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-win32-arm64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) Updates `@biomejs/cli-win32-x64` from 2.4.9 to 2.4.10 - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.10/packages/@biomejs/biome) --- updated-dependencies: - dependency-name: "@biomejs/biome" dependency-version: 2.4.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@playwright/test" dependency-version: 1.59.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: "@types/node" dependency-version: 24.12.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-darwin-arm64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-darwin-x64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-linux-arm64-musl" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-linux-arm64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-linux-x64-musl" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-linux-x64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-win32-arm64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@biomejs/cli-win32-x64" dependency-version: 2.4.10 dependency-type: indirect update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump tinyglobby from 0.2.14 to 0.2.15 (#170) Bumps [tinyglobby](https://github.com/SuperchupuDev/tinyglobby) from 0.2.14 to 0.2.15. - [Release notes](https://github.com/SuperchupuDev/tinyglobby/releases) - [Changelog](https://github.com/SuperchupuDev/tinyglobby/blob/main/CHANGELOG.md) - [Commits](SuperchupuDev/tinyglobby@0.2.14...0.2.15) --- updated-dependencies: - dependency-name: tinyglobby dependency-version: 0.2.15 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump @emnapi/runtime from 1.9.1 to 1.9.2 (#172) Bumps [@emnapi/runtime](https://github.com/toyobayashi/emnapi) from 1.9.1 to 1.9.2. - [Release notes](https://github.com/toyobayashi/emnapi/releases) - [Commits](toyobayashi/emnapi@v1.9.1...v1.9.2) --- updated-dependencies: - dependency-name: "@emnapi/runtime" dependency-version: 1.9.2 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump vite from 7.0.5 to 7.3.1 (#171) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.0.5 to 7.3.1. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.1/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.1 dependency-type: indirect update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump tinyspy from 4.0.3 to 4.0.4 (#173) Bumps [tinyspy](https://github.com/tinylibs/tinyspy) from 4.0.3 to 4.0.4. - [Release notes](https://github.com/tinylibs/tinyspy/releases) - [Commits](tinylibs/tinyspy@v4.0.3...v4.0.4) --- updated-dependencies: - dependency-name: tinyspy dependency-version: 4.0.4 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * deps-dev(deps-dev): bump @cloudflare/workers-types (#174) Bumps [@cloudflare/workers-types](https://github.com/cloudflare/workerd) from 4.20260329.1 to 4.20260405.1. - [Release notes](https://github.com/cloudflare/workerd/releases) - [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md) - [Commits](https://github.com/cloudflare/workerd/commits) --- updated-dependencies: - dependency-name: "@cloudflare/workers-types" dependency-version: 4.20260405.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps-dev(deps-dev): bump wrangler from 4.77.0 to 4.79.0 (#178) Bumps [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler) from 4.77.0 to 4.79.0. - [Release notes](https://github.com/cloudflare/workers-sdk/releases) - [Commits](https://github.com/cloudflare/workers-sdk/commits/wrangler@4.79.0/packages/wrangler) --- updated-dependencies: - dependency-name: wrangler dependency-version: 4.79.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * deps(deps): bump drizzle-orm from 0.45.1 to 0.45.2 (#165) Bumps [drizzle-orm](https://github.com/drizzle-team/drizzle-orm) from 0.45.1 to 0.45.2. - [Release notes](https://github.com/drizzle-team/drizzle-orm/releases) - [Commits](drizzle-team/drizzle-orm@0.45.1...0.45.2) --- updated-dependencies: - dependency-name: drizzle-orm dependency-version: 0.45.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: resolve duplicate @types/node@24.12.2 in pnpm-lock.yaml (#175) * deps(deps): bump expect-type from 1.2.2 to 1.3.0 Bumps [expect-type](https://github.com/mmkal/expect-type) from 1.2.2 to 1.3.0. - [Release notes](https://github.com/mmkal/expect-type/releases) - [Commits](mmkal/expect-type@v1.2.2...v1.3.0) --- updated-dependencies: - dependency-name: expect-type dependency-version: 1.3.0 dependency-type: indirect update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * fix: resolve duplicate @types/node@24.12.2 in pnpm-lock.yaml by updating @types/node to ^24.12.2 Agent-Logs-Url: https://github.com/mahata/mlack/sessions/75387082-98f8-4f32-a101-e17460603972 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * chore: merge main into branch, resolve @playwright/test version conflict Agent-Logs-Url: https://github.com/mahata/mlack/sessions/93366234-814a-46ee-b2fd-3d5296eeaa11 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * feat: add mlack.uk custom domain route to production * fix: resolve duplicate @types/node@24.12.2 in pnpm-lock.yaml (#176) * deps(deps): bump postcss from 8.5.6 to 8.5.8 Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.6...8.5.8) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.8 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * fix: resolve duplicate @types/node@24.12.2 in pnpm-lock.yaml after merging main Agent-Logs-Url: https://github.com/mahata/mlack/sessions/ee849a11-8ea0-46b7-8001-8e30404fc116 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * deps(deps): bump vite from 7.0.5 to 7.3.2 (#183) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.0.5 to 7.3.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: add Electron desktop client (#184) * feat: add Electron desktop client with notifications and system tray Add an Electron wrapper that loads the existing mlack web app in a native desktop window. Includes: - System tray icon with show/quit context menu - Native OS notifications for new messages when window is unfocused - WebSocket message interception via injected script - Persistent cookie sessions across app restarts - electron-builder config for macOS, Windows, and Linux packaging - Workspace integration with root-level electron:dev/build/package scripts * Update electron/src/notifications.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update electron/src/tray.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update electron/src/preload.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: disable electron-builder publish to prevent channel crash (#186) * deps-dev(deps-dev): bump electron from 35.7.5 to 39.8.5 (#185) Bumps [electron](https://github.com/electron/electron) from 35.7.5 to 39.8.5. - [Release notes](https://github.com/electron/electron/releases) - [Commits](electron/electron@v35.7.5...v39.8.5) --- updated-dependencies: - dependency-name: electron dependency-version: 39.8.5 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: clarify Copilot CLI review command path usage (#187) * chore: replace security-auditor agent with Copilot CLI reviews Remove the dedicated security-auditor OpenCode agent and add a Copilot CLI review step to AGENTS.md instead. This gives multi-model review coverage (Opus 4.6 writes, GPT-5.4 reviews) and runs per-task rather than per-file to keep the workflow efficient. * docs: clarify copilot CLI file path placeholder Agent-Logs-Url: https://github.com/mahata/mlack/sessions/8cef0ef9-23e7-4daf-9bc5-6af13accf40c Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * deps(deps): bump hono from 4.12.11 to 4.12.12 (#189) Bumps [hono](https://github.com/honojs/hono) from 4.12.11 to 4.12.12. - [Release notes](https://github.com/honojs/hono/releases) - [Commits](honojs/hono@v4.12.11...v4.12.12) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.12 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: enforce existing Git tag guard in electron release workflow (#188) * feat: add GitHub Actions workflow for Electron desktop releases Add a manual-dispatch workflow that builds MLack Desktop binaries for macOS (.dmg), Windows (.nsis), and Linux (.AppImage) in parallel, then creates a GitHub Release with all artifacts attached. Includes version validation, duplicate release check, branch guard (main only), scoped permissions, and concurrency protection. * fix: validate existing git tags in electron release workflow Agent-Logs-Url: https://github.com/mahata/mlack/sessions/9f1592bd-764d-4005-8c02-81a5c88659a2 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * fix: check existing release tags with git ls-remote Agent-Logs-Url: https://github.com/mahata/mlack/sessions/9f1592bd-764d-4005-8c02-81a5c88659a2 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * fix: resolve Electron release build failures (#190) * fix: resolve Electron release build failures - Replace 16x16 placeholder icon with 512x512 PNG and generate .icns (macOS) and .ico (Windows) files to meet electron-builder requirements - Move version update step after dependency install so npm is available from the project's Node.js version rather than the runner default * Update .github/workflows/electron-release.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: write explicit newline when updating Electron package version in release workflow (#191) * fix: avoid lifecycle scripts when updating electron package version Replace pnpm version with a direct JSON file write to prevent Electron from launching during the version update step, which fails on Linux CI due to SUID sandbox configuration. * fix: use explicit newline char when writing electron package version Agent-Logs-Url: https://github.com/mahata/mlack/sessions/b04db865-e846-4b04-8b58-959693015c66 Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * docs: align README Node.js prerequisite with Node 24 upgrade (#192) * chore: upgrade Node.js to 24 and remove corepack Node.js 24 no longer bundles corepack, so remove the corepack enable steps from all CI workflows and drop the packageManager field from package.json. Update .node-version and AGENTS.md to reflect Node 24. * fix: install pnpm via pnpm/action-setup in CI workflows Node.js 24 no longer bundles corepack, so pnpm must be installed explicitly. Add pnpm/action-setup@v4 before actions/setup-node in every CI job. * docs: update README Node.js prerequisite to v24 Agent-Logs-Url: https://github.com/mahata/mlack/sessions/21f73092-2de8-4e30-b7eb-4dd8f51484dc Co-authored-by: mahata <23497+mahata@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> * feat: add workspaces with isolated channels, members, and invite system (#193) * feat: add workspaces with isolated channels, members, and invite system Introduce workspace support with path-based routing (/w/:slug/...), per-workspace admin roles, invite links with 1-hour expiration, and one Durable Object per workspace for WebSocket connections. Existing data auto-migrates into a seeded 'default' workspace. Migration uses PRAGMA defer_foreign_keys to handle the channels table rebuild safely on D1. * fix: address PR review feedback — type safety, SQL efficiency, and invite security - Make workspace/workspaceMember optional in Variables type to match runtime - First user auto-joining default workspace now becomes admin (bootstrap fix) - Remove unreachable auth check in /w/:slug (middleware already handles it) - Replace select-all-then-filter with SQL inner join for workspace queries - Use subquery in seed.sql instead of hardcoded workspace_id=1 - Convert invite acceptance from mutating GET to GET confirmation + POST --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mahata <23497+mahata@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
/w/:slug/...), per-workspace admin roles, invite links (1-hour expiry, multi-use), and one Durable Object per workspace for WebSocket connectionsdefaultworkspace; new users with no workspaces auto-joindefaultDatabase changes
workspaces,workspace_members,workspace_inviteschannelstable rebuilt withworkspace_idNOT NULL column (unique index now scoped to(workspace_id, name))PRAGMA defer_foreign_keysto safely handle the table rebuild on D1New files
hono/auth/requireWorkspaceMember.ts/requireWorkspaceAdmin.ts— middlewarehono/routes/workspaces.ts— workspace CRUDhono/routes/workspaceAdmin.ts— admin routes (invites, members)hono/routes/workspaceInvite.ts— invite acceptancehono/components/WorkspacesPage.tsx+ CSS — workspace list UIModified files
hono/app.tsx— new route registrations and workspace middlewarehono/routes/channels.ts,messages.ts,ws.ts— scoped under/w/:slug/hono/routes/index.tsx— workspace redirect logichono/components/ChatPage.tsx— workspace context in UIhono/static/ChatPage.ts— workspace-scoped API URLshono/db/schema.ts— 3 new tables, modified channelse2e/app.spec.ts— updated page title assertionTesting
mlack.uk)