Skip to content

feat(workspace): workspace domain — schema, store, routes, daemon linking#82

Merged
arek-e merged 3 commits intomainfrom
feat/workspace-domain
Apr 4, 2026
Merged

feat(workspace): workspace domain — schema, store, routes, daemon linking#82
arek-e merged 3 commits intomainfrom
feat/workspace-domain

Conversation

@arek-e
Copy link
Copy Markdown
Owner

@arek-e arek-e commented Apr 4, 2026

Summary

  • New @paws/domain-workspace package — Workspace entity for grouping repos + daemons
    • Zod schemas: WorkspaceSchema, WorkspaceRepoSchema, WorkspaceSettingsSchema
    • In-memory store with full CRUD
    • OpenAPI route definitions (5 endpoints)
    • 21 unit tests for schema validation
  • Daemon domain — added optional workspace field to DaemonSchema for linking daemons to workspaces
  • Supports monorepo (single repo + root dir) and multi-repo (multiple repos with roles)

Workspace schema

{
  name: "paws",           // unique slug
  type: "monorepo",       // or "multi-repo"
  repos: [{
    repo: "arek-e/paws",
    role: "primary",
    rootDir: "/",
    branch: "main"
  }],
  settings: { language: "typescript", packageManager: "bun" }
}

Test plan

  • 21 schema validation tests pass
  • All 31 test tasks pass
  • CI green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added optional workspace association for daemon objects.
    • Introduced a workspace domain with create/list/get/update/delete support, workspace schemas, repository/settings configuration, and REST routes.
    • Added workspace package and TypeScript project reference.
  • Tests

    • Added comprehensive validation tests for workspace schemas.
  • Chores

    • Removed unused imports and dead variables in auth component.

… linking

New domain package `packages/domains/workspace/` with Zod schemas for
workspace entities (monorepo/multi-repo), CRUD routes via @hono/zod-openapi,
in-memory store, and 21 unit tests for schema validation.

Adds optional `workspace` field to daemon domain (CreateDaemonRequestSchema,
DaemonListItemSchema, StoredDaemon) to link daemons to workspaces.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

Warning

Rate limit exceeded

@arek-e has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 33 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 4 minutes and 33 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 966f8f0a-54f5-4dfd-8289-a5bd257455c6

📥 Commits

Reviewing files that changed from the base of the PR and between 4e3f181 and ef779fd.

📒 Files selected for processing (2)
  • apps/dashboard/src/components/AuthGate.tsx
  • packages/domains/workspace/tsconfig.json
📝 Walkthrough

Walkthrough

Adds a new workspace domain package with schemas, store, routes, and tests; extends the daemon domain by adding an optional workspace field to daemon request/response schemas and the persisted StoredDaemon.

Changes

Cohort / File(s) Summary
Daemon workspace field
packages/domains/daemon/src/store.ts, packages/domains/daemon/src/types.ts
Added optional workspace to StoredDaemon, CreateDaemonRequestSchema, and DaemonListItemSchema; store sets workspace from request when creating a daemon.
Workspace package manifest & config
packages/domains/workspace/package.json, packages/domains/workspace/tsconfig.json, packages/domains/workspace/vitest.config.ts
New package manifest and TypeScript/Vitest configs for the workspace domain.
Workspace types and tests
packages/domains/workspace/src/types.ts, packages/domains/workspace/src/types.test.ts
Introduced Zod schemas and TS types for workspace entities, create/update requests, list responses; added comprehensive validation tests.
Workspace store implementation
packages/domains/workspace/src/store.ts
In-memory WorkspaceStore with create/get/getByName/list/update/delete; update merges partials and updates timestamps.
Workspace API routes
packages/domains/workspace/src/routes.ts
Defined OpenAPI-aware route configs for POST/GET/PUT/DELETE workspace endpoints with request/response schemas and error shapes.
Workspace public entrypoint
packages/domains/workspace/src/index.ts
Re-exports schemas, types, store factory, and route handlers as the package API surface.
Monorepo integration
tsconfig.json
Added packages/domains/workspace to root TypeScript project references.
Minor cleanup
apps/dashboard/src/components/AuthGate.tsx
Removed unused import setSessionMode and an unused local variable.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped in with schemas, tidy and spry,
A workspace springing under the sky.
Stores and routes lined up in a row,
Daemons now know where workspaces go.
Hooray for hops in code — off I go! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes a summary of changes, workspace schema details, test plan status, but does not follow the provided template structure with 'What', 'Why', or checklist items. Restructure the description to follow the template: add explicit 'What' and 'Why' sections, include the checklist with status, and link to any related issues.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: introducing a workspace domain with schema, store, routes, and daemon linking.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/workspace-domain

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 4, 2026

Deploying getpaws with  Cloudflare Pages  Cloudflare Pages

Latest commit: ef779fd
Status: ✅  Deploy successful!
Preview URL: https://bc5d688f.getpaws-6m4.pages.dev
Branch Preview URL: https://feat-workspace-domain.getpaws-6m4.pages.dev

View logs

arek-e and others added 2 commits April 4, 2026 12:40
…domains)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/domains/workspace/src/routes.ts (1)

70-83: Use PATCH for partial updates (or make PUT body full-replacement).

Line 71 declares put, but the body schema is partial-update shaped. Prefer patch to match API semantics and client expectations.

Proposed adjustment
 export const updateWorkspaceRoute = createRoute({
-  method: 'put',
+  method: 'patch',
   path: '/v1/workspaces/{id}',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/domains/workspace/src/routes.ts` around lines 70 - 83, The route
definition updateWorkspaceRoute currently uses method 'put' but validates
against a partial-update schema (UpdateWorkspaceRequestSchema); change the HTTP
method to 'patch' in the createRoute call so the route semantics match the
partial body schema (or alternatively replace UpdateWorkspaceRequestSchema with
a full-replacement schema if you intend PUT semantics); ensure the method string
in createRoute and any related route docs/tags remain consistent with the chosen
behavior.
packages/domains/workspace/src/types.ts (1)

5-5: Tighten repo validation to match the documented owner/repo shape.

Line 5 currently accepts any non-empty string, so malformed repository identifiers pass validation.

Proposed fix
-  repo: z.string().min(1), // "owner/repo"
+  repo: z
+    .string()
+    .regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/, 'Expected "owner/repo"'),

As per coding guidelines, "Use Zod for all external data validation: API requests, config files, and environment variables via @t3-oss/env-core."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/domains/workspace/src/types.ts` at line 5, The current zod schema
for the repo field accepts any non-empty string; change the repo validator in
types.ts to enforce the "owner/repo" shape by replacing repo: z.string().min(1)
with a z.string() that uses a regex check for a single slash-separated owner and
repo (e.g., allowed characters like alphanumerics, hyphen, underscore, dot) and
a custom error message; reference the repo symbol in the schema to locate and
update this validator so malformed identifiers fail validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/domains/daemon/src/store.ts`:
- Line 13: StoredDaemon in the control-plane store is missing the workspace
field so workspace is dropped; update the StoredDaemon interface to include
workspace?: string | undefined, modify the in-memory store create()
implementation to set workspace: request.workspace when building the stored
object in the create() method, and update the SQLite store insert statement to
include the workspace column and bind request.workspace in the values for the
insert (adjust the INSERT SQL and parameter list in the SQLite store
implementation accordingly).

In `@packages/domains/workspace/src/types.ts`:
- Around line 67-69: The refine on UpdateWorkspaceRequestSchema currently only
checks Object.keys(data).length, allowing objects like { name: undefined } to
pass; change the predicate used in the .refine call to verify at least one value
is not undefined (e.g., use Object.values(data).some(value => value !==
undefined)) so that payloads with only undefined fields are rejected and the
existing error message remains accurate.

In `@packages/domains/workspace/tsconfig.json`:
- Line 7: Remove the package-level compilerOptions.types entry from the
tsconfig: locate the tsconfig JSON (where "types": [] is present) and delete the
"types" property entirely so the package no longer overrides global type
inclusion; ensure no other per-package tsconfig files set compilerOptions.types
either and keep the rest of the compilerOptions intact.

---

Nitpick comments:
In `@packages/domains/workspace/src/routes.ts`:
- Around line 70-83: The route definition updateWorkspaceRoute currently uses
method 'put' but validates against a partial-update schema
(UpdateWorkspaceRequestSchema); change the HTTP method to 'patch' in the
createRoute call so the route semantics match the partial body schema (or
alternatively replace UpdateWorkspaceRequestSchema with a full-replacement
schema if you intend PUT semantics); ensure the method string in createRoute and
any related route docs/tags remain consistent with the chosen behavior.

In `@packages/domains/workspace/src/types.ts`:
- Line 5: The current zod schema for the repo field accepts any non-empty
string; change the repo validator in types.ts to enforce the "owner/repo" shape
by replacing repo: z.string().min(1) with a z.string() that uses a regex check
for a single slash-separated owner and repo (e.g., allowed characters like
alphanumerics, hyphen, underscore, dot) and a custom error message; reference
the repo symbol in the schema to locate and update this validator so malformed
identifiers fail validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cd950ab4-55d2-46eb-9cd0-80046544aee0

📥 Commits

Reviewing files that changed from the base of the PR and between 3b0b668 and 4e3f181.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • packages/domains/daemon/src/store.ts
  • packages/domains/daemon/src/types.ts
  • packages/domains/workspace/package.json
  • packages/domains/workspace/src/index.ts
  • packages/domains/workspace/src/routes.ts
  • packages/domains/workspace/src/store.ts
  • packages/domains/workspace/src/types.test.ts
  • packages/domains/workspace/src/types.ts
  • packages/domains/workspace/tsconfig.json
  • packages/domains/workspace/vitest.config.ts
  • tsconfig.json

status: DaemonStatus;
snapshot: string;
trigger: Trigger;
workspace?: string | undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the interface mismatch in control-plane store

echo "=== StoredDaemon interface in control-plane ==="
rg -n -A 20 'export interface StoredDaemon' apps/control-plane/src/store/daemons.ts

echo ""
echo "=== createDaemonStore create method ==="
rg -n -A 25 'create\(request\)' apps/control-plane/src/store/daemons.ts

echo ""
echo "=== Check if workspace exists anywhere in control-plane daemons store ==="
rg -n 'workspace' apps/control-plane/src/store/daemons.ts

Repository: arek-e/paws

Length of output: 2553


Control-plane store implementations are missing the workspace field.

The workspace field is correctly added to StoredDaemon and the create() method here (line 50), but the control-plane has a separate StoredDaemon interface and store implementations in apps/control-plane/src/store/daemons.ts that don't include this field.

Update required:

  • Add workspace?: string | undefined to the StoredDaemon interface (line 12)
  • Add workspace: request.workspace to the in-memory store's create() method (line 48)
  • Add workspace to the SQLite store's insert statement (line 150-163)

Without these changes, the workspace value will be silently dropped when daemons are created through the control-plane.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/domains/daemon/src/store.ts` at line 13, StoredDaemon in the
control-plane store is missing the workspace field so workspace is dropped;
update the StoredDaemon interface to include workspace?: string | undefined,
modify the in-memory store create() implementation to set workspace:
request.workspace when building the stored object in the create() method, and
update the SQLite store insert statement to include the workspace column and
bind request.workspace in the values for the insert (adjust the INSERT SQL and
parameter list in the SQLite store implementation accordingly).

Comment on lines +67 to +69
.refine((data) => Object.keys(data).length > 0, {
message: 'At least one field must be provided',
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "types.ts" | grep -E "workspace|domains" | head -20

Repository: arek-e/paws

Length of output: 491


🏁 Script executed:

cat -n packages/domains/workspace/src/types.ts | head -100

Repository: arek-e/paws

Length of output: 3123


🏁 Script executed:

# Search for tests or usage of UpdateWorkspaceRequestSchema
rg "UpdateWorkspaceRequestSchema" --type ts --type tsx -B 2 -A 5

Repository: arek-e/paws

Length of output: 82


🏁 Script executed:

# Look for test files related to workspace types
find . -type f -name "*.test.ts" -o -name "*.spec.ts" | grep -i workspace

Repository: arek-e/paws

Length of output: 101


🏁 Script executed:

rg "UpdateWorkspaceRequestSchema" --type ts -B 2 -A 5

Repository: arek-e/paws

Length of output: 4686


🏁 Script executed:

cat -n packages/domains/workspace/src/types.test.ts

Repository: arek-e/paws

Length of output: 6565


UpdateWorkspaceRequestSchema accepts payloads with only undefined fields.

The refine check counts object keys only; { name: undefined } passes validation even though no actual update is provided. Fix by checking if at least one value is not undefined:

Fix
-  .refine((data) => Object.keys(data).length > 0, {
+  .refine((data) => Object.values(data).some((v) => v !== undefined), {
     message: 'At least one field must be provided',
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.refine((data) => Object.keys(data).length > 0, {
message: 'At least one field must be provided',
});
.refine((data) => Object.values(data).some((v) => v !== undefined), {
message: 'At least one field must be provided',
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/domains/workspace/src/types.ts` around lines 67 - 69, The refine on
UpdateWorkspaceRequestSchema currently only checks Object.keys(data).length,
allowing objects like { name: undefined } to pass; change the predicate used in
the .refine call to verify at least one value is not undefined (e.g., use
Object.values(data).some(value => value !== undefined)) so that payloads with
only undefined fields are rejected and the existing error message remains
accurate.

Comment thread packages/domains/workspace/tsconfig.json
@arek-e arek-e merged commit f11746a into main Apr 4, 2026
2 checks passed
arek-e added a commit that referenced this pull request Apr 4, 2026
Proxy (#77):
- Add missing audit log fields (statusCode, durationMs, credentialsInjected,
  protocol) to blocked-request log entry for schema consistency
- Add missing statusCode: 502 to upstream-failure log entry
- Fix httpsPort log condition: check caCert && caKey, not just caCert

Workspace (#82):
- Add workspace field to control-plane StoredDaemon interface and both
  in-memory and SQLite store implementations (was silently dropped)
- Add workspace column to daemons DB schema
- Fix UpdateWorkspaceRequestSchema refinement: use Object.values().some()
  instead of Object.keys().length to reject all-undefined payloads
- Remove "types": [] from workspace tsconfig.json (violates repo policy)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
arek-e added a commit that referenced this pull request Apr 4, 2026
Proxy (#77):
- Add missing audit log fields (statusCode, durationMs, credentialsInjected,
  protocol) to blocked-request log entry for schema consistency
- Add missing statusCode: 502 to upstream-failure log entry
- Fix httpsPort log condition: check caCert && caKey, not just caCert

Workspace (#82):
- Add workspace field to control-plane StoredDaemon interface and both
  in-memory and SQLite store implementations (was silently dropped)
- Add workspace column to daemons DB schema
- Fix UpdateWorkspaceRequestSchema refinement: use Object.values().some()
  instead of Object.keys().length to reject all-undefined payloads
- Remove "types": [] from workspace tsconfig.json (violates repo policy)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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