From 609badc4ed6e91eb0af75c8caa1fa60811e8d03a Mon Sep 17 00:00:00 2001 From: puter Date: Thu, 23 Jul 2026 14:09:25 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Projects=20backend=20slice=20=E2=80=94?= =?UTF-8?q?=20auth,=20primitives,=20backend,=20UI=20(#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projects/project-workspace-page.tsx | 298 +++---- apps/web/src/components/user-menu.tsx | 19 +- .../hooks/use-personal-organization.test.ts | 77 -- .../src/hooks/use-personal-organization.ts | 51 +- apps/web/src/hooks/use-project-workspace.ts | 16 +- apps/web/src/routes/_app.tsx | 22 +- apps/web/src/routes/_auth.tsx | 16 +- docs/DESIGN.md | 6 +- docs/PRODUCT.md | 10 +- docs/TECH.md | 4 +- packages/agents/src/agents/zopu.ts | 1 + packages/auth/package.json | 1 - packages/auth/src/server/index.ts | 1 - packages/auth/src/web/auth-provider.tsx | 2 +- packages/auth/src/web/index.ts | 2 + packages/auth/src/web/use-web-auth.ts | 81 ++ packages/backend/convex/artifactModel.ts | 119 ++- packages/backend/convex/auth.ts | 28 +- packages/backend/convex/authz.ts | 42 +- packages/backend/convex/organizations.ts | 6 +- packages/backend/convex/projectArtifacts.ts | 8 +- packages/backend/convex/projectEvents.test.ts | 79 +- packages/backend/convex/projectIssues.ts | 31 +- packages/backend/convex/projectStore.ts | 430 ++++++++++ packages/backend/convex/projects.ts | 352 ++++---- packages/backend/convex/schema.ts | 61 +- packages/backend/convex/signals.test.ts | 44 +- packages/backend/convex/signals.ts | 18 +- packages/backend/package.json | 1 + packages/primitives/package.json | 1 + packages/primitives/src/index.ts | 1 + packages/primitives/src/project.ts | 762 ++++++++++++++++++ 32 files changed, 1926 insertions(+), 664 deletions(-) delete mode 100644 apps/web/src/hooks/use-personal-organization.test.ts delete mode 100644 packages/auth/src/server/index.ts create mode 100644 packages/auth/src/web/use-web-auth.ts create mode 100644 packages/backend/convex/projectStore.ts create mode 100644 packages/primitives/src/project.ts diff --git a/apps/web/src/components/projects/project-workspace-page.tsx b/apps/web/src/components/projects/project-workspace-page.tsx index 8aa7ed7..b171063 100644 --- a/apps/web/src/components/projects/project-workspace-page.tsx +++ b/apps/web/src/components/projects/project-workspace-page.tsx @@ -7,7 +7,6 @@ import { ExternalLink, FileText, GitFork, - GitPullRequest, Play, Plus, } from "lucide-react"; @@ -20,17 +19,16 @@ const statusStyle: Record["status"], string> = { "border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300", failed: "border-destructive/40 bg-destructive/10 text-destructive", "needs-input": - "border-orange-500/40 bg-orange-500/10 text-orange-700 dark:text-orange-300", - open: "border-border text-muted-foreground", - queued: "border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-300", + open: "border-border bg-muted/40 text-muted-foreground", + queued: "border-blue-500/40 bg-blue-500/10 text-blue-700 dark:text-blue-300", working: "border-blue-500/40 bg-blue-500/10 text-blue-700 dark:text-blue-300", }; interface RepositoryFormProps { readonly busy: boolean; readonly onChange: (value: string) => void; - readonly onSubmit: () => Promise; + readonly onSubmit: () => void; readonly value: string; } @@ -41,36 +39,46 @@ const RepositoryForm = ({ value, }: RepositoryFormProps) => (
{ event.preventDefault(); - void onSubmit(); + onSubmit(); }} >
-
onChange(event.target.value)} - placeholder="rivet-dev/rivet" + placeholder="https://github.com/owner/repo" required value={value} /> -
); interface ProjectListProps { - readonly projects: readonly Doc<"projects">[] | undefined; + readonly projects: + | readonly { + readonly id: string; + readonly name: string; + readonly sources: readonly { + readonly host: string; + readonly repositoryPath: string; + readonly url: string; + }[]; + }[] + | undefined; readonly selectedId: Id<"projects"> | null; readonly onSelect: (projectId: Id<"projects">) => void; } @@ -85,7 +93,7 @@ const ProjectList = ({ projects, selectedId, onSelect }: ProjectListProps) => { if (projects.length === 0) { return (

- Connect a repository to create its project artifacts and issue queue. + Import a repository to create its project artifacts and issue queue.

); } @@ -94,19 +102,20 @@ const ProjectList = ({ projects, selectedId, onSelect }: ProjectListProps) => { {projects.map((project) => ( ))} @@ -128,40 +137,34 @@ interface ArtifactGridProps { readonly artifacts: readonly Doc<"projectArtifacts">[] | undefined; } +const renderArtifacts = (artifacts: ArtifactGridProps["artifacts"]) => { + if (artifacts === undefined) { + return

Loading artifacts...

; + } + if (artifacts.length === 0) { + return

No artifacts yet.

; + } + return ( +
+ {artifacts.map((artifact) => ( +
+ +

{artifact.path}

+

+ rev {artifact.revision} +

+
+ ))} +
+ ); +}; + const ArtifactGrid = ({ artifacts }: ArtifactGridProps) => (
-
-

- Project artifacts -

-

- Canonical context staged into every issue workspace. -

-
- {artifacts === undefined ? ( -

Loading artifacts...

- ) : ( -
- {artifacts.map((artifact) => ( -
-
-
- -

- {artifact.path} -

-
- - r{artifact.revision} - -
-

- {artifact.content} -

-
- ))} -
- )} +

+ Project artifacts +

+ {renderArtifacts(artifacts)}
); @@ -169,7 +172,7 @@ interface IssueComposerProps { readonly body: string; readonly busy: boolean; readonly onBodyChange: (value: string) => void; - readonly onSubmit: () => Promise; + readonly onSubmit: () => void; readonly onTitleChange: (value: string) => void; readonly title: string; } @@ -183,47 +186,27 @@ const IssueComposer = ({ title, }: IssueComposerProps) => (
{ event.preventDefault(); - void onSubmit(); + onSubmit(); }} > -
-

Raise an issue

-

- The issue becomes the identity for one Flue agent and AgentOS workspace. -

-
-
- - onTitleChange(event.target.value)} - required - value={title} - /> -
-
- -