From c199a29b53e3520c2c1cc29325108a28bc6d2698 Mon Sep 17 00:00:00 2001 From: Che <30403707+Che-Zhu@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:28:55 +0800 Subject: [PATCH] docs: add generated project wiki --- docs/wiki/_meta/manifest.json | 232 ++++++++++++ docs/wiki/api/auth-and-github.md | 138 ++++++++ docs/wiki/api/index.md | 51 +++ docs/wiki/api/projects-and-runtime.md | 450 ++++++++++++++++++++++++ docs/wiki/api/user-config.md | 283 +++++++++++++++ docs/wiki/architecture.md | 136 +++++++ docs/wiki/auth-and-state.md | 87 +++++ docs/wiki/background-jobs.md | 130 +++++++ docs/wiki/config-and-env.md | 105 ++++++ docs/wiki/data-models.md | 171 +++++++++ docs/wiki/features/auth-and-identity.md | 37 ++ docs/wiki/features/github-and-import.md | 42 +++ docs/wiki/features/global-skills.md | 40 +++ docs/wiki/features/project-workspace.md | 52 +++ docs/wiki/features/user-settings.md | 40 +++ docs/wiki/index.md | 47 +++ docs/wiki/integrations.md | 101 ++++++ docs/wiki/rendering-and-data-flow.md | 117 ++++++ docs/wiki/routing.md | 149 ++++++++ docs/wiki/todo.md | 29 ++ 20 files changed, 2437 insertions(+) create mode 100644 docs/wiki/_meta/manifest.json create mode 100644 docs/wiki/api/auth-and-github.md create mode 100644 docs/wiki/api/index.md create mode 100644 docs/wiki/api/projects-and-runtime.md create mode 100644 docs/wiki/api/user-config.md create mode 100644 docs/wiki/architecture.md create mode 100644 docs/wiki/auth-and-state.md create mode 100644 docs/wiki/background-jobs.md create mode 100644 docs/wiki/config-and-env.md create mode 100644 docs/wiki/data-models.md create mode 100644 docs/wiki/features/auth-and-identity.md create mode 100644 docs/wiki/features/github-and-import.md create mode 100644 docs/wiki/features/global-skills.md create mode 100644 docs/wiki/features/project-workspace.md create mode 100644 docs/wiki/features/user-settings.md create mode 100644 docs/wiki/index.md create mode 100644 docs/wiki/integrations.md create mode 100644 docs/wiki/rendering-and-data-flow.md create mode 100644 docs/wiki/routing.md create mode 100644 docs/wiki/todo.md diff --git a/docs/wiki/_meta/manifest.json b/docs/wiki/_meta/manifest.json new file mode 100644 index 0000000..79568dc --- /dev/null +++ b/docs/wiki/_meta/manifest.json @@ -0,0 +1,232 @@ +{ + "generated_at": "2026-04-02T02:16:55Z", + "wiki_root": "docs/wiki", + "router_mode": "app", + "pages": [ + { + "path": "docs/wiki/index.md", + "sources": [ + "package.json", + "app", + "lib/platform/readme.md", + "prisma/schema.prisma" + ] + }, + { + "path": "docs/wiki/architecture.md", + "sources": [ + "app/layout.tsx", + "instrumentation.ts", + "lib/startup/index.ts", + "lib/platform/readme.md", + "lib/platform/control/readme.md", + "lib/platform/control/commands/readme.md", + "lib/actions", + "lib/repo", + "lib/jobs", + "lib/events" + ] + }, + { + "path": "docs/wiki/routing.md", + "sources": [ + "app", + "components/sidebar.tsx", + "components/sidebars/project-sidebar.tsx", + "components/layout/project-content-wrapper.tsx", + "app/(dashboard)/settings/_components/settings-sidebar.tsx" + ] + }, + { + "path": "docs/wiki/rendering-and-data-flow.md", + "sources": [ + "app/layout.tsx", + "app/(landing)/page.tsx", + "provider/providers.tsx", + "hooks/use-project.ts", + "hooks/use-environment-variables.ts", + "components/layout/project-content-wrapper.tsx", + "lib/fetch-client.ts", + "lib/data/project.ts" + ] + }, + { + "path": "docs/wiki/auth-and-state.md", + "sources": [ + "lib/auth.ts", + "lib/api-auth.ts", + "provider/sealos.tsx", + "lib/actions/sealos-auth.ts", + "app/(auth)/login/page.tsx" + ] + }, + { + "path": "docs/wiki/config-and-env.md", + "sources": [ + "next.config.ts", + "package.json", + "lib/env.ts", + "instrumentation.ts", + "lib/startup/index.ts", + "lib/const.ts" + ] + }, + { + "path": "docs/wiki/data-models.md", + "sources": [ + "prisma/schema.prisma", + "lib/repo/project.ts" + ] + }, + { + "path": "docs/wiki/integrations.md", + "sources": [ + "lib/k8s/k8s-service-helper.ts", + "lib/services/github-app.ts", + "lib/services/aiproxy.ts", + "lib/util/ttyd-context.ts", + "provider/sealos.tsx", + "lib/platform/integrations/README.md" + ] + }, + { + "path": "docs/wiki/background-jobs.md", + "sources": [ + "instrumentation.ts", + "lib/startup/index.ts", + "lib/jobs/sandbox/sandboxReconcile.ts", + "lib/jobs/database/databaseReconcile.ts", + "lib/jobs/project-task/projectTaskReconcile.ts", + "lib/events/sandbox/sandboxListener.ts", + "lib/events/database/databaseListener.ts" + ] + }, + { + "path": "docs/wiki/todo.md", + "sources": [ + "components/sidebar.tsx", + "app/(dashboard)/settings/_components/settings-sidebar.tsx", + "app/(dashboard)/projects/(list)/_components/project-actions-menu.tsx", + "app/(dashboard)/projects/[id]/exec-test/page.tsx", + "lib/actions/sandbox.ts", + "lib/platform/readme.md", + "app/api" + ] + }, + { + "path": "docs/wiki/api/index.md", + "sources": [ + "app/api", + "lib/api-auth.ts" + ] + }, + { + "path": "docs/wiki/api/auth-and-github.md", + "sources": [ + "app/api/auth/[...nextauth]/route.ts", + "app/api/github/app/callback/route.ts", + "app/api/github/app/webhook/route.ts", + "lib/auth.ts", + "lib/services/github-app.ts", + "app/github/app/callback/page.tsx" + ] + }, + { + "path": "docs/wiki/api/projects-and-runtime.md", + "sources": [ + "app/api/projects/[id]/route.ts", + "app/api/projects/[id]/start/route.ts", + "app/api/projects/[id]/stop/route.ts", + "app/api/projects/[id]/delete/route.ts", + "app/api/projects/[id]/environment/route.ts", + "app/api/projects/[id]/environment/[envId]/route.ts", + "app/api/sandbox/[id]/cwd/route.ts", + "app/api/sandbox/[id]/exec/route.ts", + "app/api/sandbox/[id]/app-status/route.ts", + "hooks/use-project.ts", + "hooks/use-project-operations.ts", + "hooks/use-environment-variables.ts", + "hooks/use-app-runner.ts", + "components/terminal/xterm-terminal.tsx" + ] + }, + { + "path": "docs/wiki/api/user-config.md", + "sources": [ + "app/api/user/config/route.ts", + "app/api/user/config/anthropic/route.ts", + "app/api/user/config/kc/route.ts", + "app/api/user/config/system-prompt/route.ts", + "components/dialog/settings-dialog.tsx", + "lib/k8s/k8s-service-helper.ts" + ] + }, + { + "path": "docs/wiki/features/auth-and-identity.md", + "sources": [ + "app/(auth)/login/page.tsx", + "app/(auth)/auth-error/page.tsx", + "app/github/app/callback/page.tsx", + "lib/auth.ts", + "provider/sealos.tsx", + "lib/actions/sealos-auth.ts" + ] + }, + { + "path": "docs/wiki/features/project-workspace.md", + "sources": [ + "app/(dashboard)/projects/(list)/page.tsx", + "app/(dashboard)/projects/[id]/layout.tsx", + "app/(dashboard)/projects/[id]/database/page.tsx", + "app/(dashboard)/projects/[id]/environment/page.tsx", + "app/(dashboard)/projects/[id]/secrets/page.tsx", + "app/(dashboard)/projects/[id]/auth/page.tsx", + "app/(dashboard)/projects/[id]/payment/page.tsx", + "components/layout/project-content-wrapper.tsx", + "hooks/use-project.ts", + "hooks/use-project-operations.ts", + "hooks/use-environment-variables.ts", + "lib/actions/project.ts", + "lib/actions/database.ts" + ] + }, + { + "path": "docs/wiki/features/github-and-import.md", + "sources": [ + "app/(dashboard)/projects/_components/import-github-dialog.tsx", + "app/(dashboard)/projects/[id]/github/page.tsx", + "app/github/app/callback/page.tsx", + "lib/actions/github.ts", + "lib/actions/project.ts", + "lib/services/github-app.ts", + "lib/services/repoService.ts", + "lib/platform/control/commands/project/create-project-from-github.ts", + "lib/jobs/project-task/executors/clone-repository.ts" + ] + }, + { + "path": "docs/wiki/features/user-settings.md", + "sources": [ + "app/(dashboard)/settings/page.tsx", + "app/(dashboard)/settings/integrations/page.tsx", + "app/(dashboard)/settings/_components/github-status-card.tsx", + "app/(dashboard)/settings/_components/settings-sidebar.tsx", + "components/dialog/settings-dialog.tsx", + "provider/sealos.tsx" + ] + }, + { + "path": "docs/wiki/features/global-skills.md", + "sources": [ + "app/(dashboard)/skills/page.tsx", + "app/(dashboard)/skills/_components/skills-library.tsx", + "lib/actions/skill.ts", + "lib/skills/catalog.ts", + "lib/platform/control/commands/skill/enable-global-skill.ts", + "lib/platform/control/commands/skill/uninstall-global-skill.ts", + "lib/jobs/project-task/executors/install-skill.ts", + "lib/jobs/project-task/executors/uninstall-skill.ts" + ] + } + ] +} diff --git a/docs/wiki/api/auth-and-github.md b/docs/wiki/api/auth-and-github.md new file mode 100644 index 0000000..e2811f7 --- /dev/null +++ b/docs/wiki/api/auth-and-github.md @@ -0,0 +1,138 @@ +# Auth and GitHub API + +## Domain Summary + +This domain covers identity exchange, GitHub App installation binding, and GitHub webhook lifecycle updates. + +## Public Endpoints + +### `GET | POST /api/auth/[...nextauth]` + +Type: `public` + +Source: + +- `app/api/auth/[...nextauth]/route.ts` - route entry +- `lib/auth.ts` - provider and callback configuration + +Auth: + +- Owned by NextAuth +- Provider-specific auth happens inside the NextAuth handler + +Request: + +- Params: dynamic catch-all segment used by NextAuth +- Query: NextAuth-managed +- Body: provider-specific, including credentials or OAuth callback payloads +- Headers: browser session and CSRF cookies as required by NextAuth + +Response: + +- Success: NextAuth-managed redirects, session cookies, or JSON depending on the auth sub-route +- Failure: NextAuth error responses or redirect to `/auth-error` + +Side effects: + +- creates or updates `User` +- creates or updates `UserIdentity` +- stores JWT-backed session state +- sets cross-site-friendly auth cookies + +Main callers: + +- `app/(auth)/login/page.tsx` - credentials and GitHub sign-in UI +- `lib/actions/sealos-auth.ts` - Sealos server-side sign-in helper + +### `GET /api/github/app/callback` + +Type: `public` + +Source: + +- `app/api/github/app/callback/route.ts` - route entry +- `lib/services/github-app.ts` - OAuth exchange and installation lookup +- `lib/repo/github.ts` - installation persistence + +Auth: + +- Requires an authenticated Fulling session +- Verifies installation ownership unless OAuth exchange already established that link + +Request: + +- Params: none +- Query: + - `installation_id` required + - `setup_action` optional + - `code` optional +- Body: none +- Headers: session cookies + +Response: + +- Success: small HTML page that posts a success message to the opener and closes itself +- Failure: JSON error for missing auth or invalid install context, or failure HTML page + +Side effects: + +- may exchange GitHub OAuth code for user tokens +- upserts `GITHUB` `UserIdentity` +- creates or updates `GitHubAppInstallation` + +Main callers: + +- `app/github/app/callback/page.tsx` - popup completion page that forwards query params here +- GitHub App installation redirect flow + +### `POST /api/github/app/webhook` + +Type: `public` + +Source: + +- `app/api/github/app/webhook/route.ts` - route entry +- `lib/services/github-app.ts` - webhook signature verification +- `lib/repo/github.ts` - installation status updates + +Auth: + +- No session auth +- Requires valid `x-hub-signature-256` verification + +Request: + +- Params: none +- Query: none +- Body: GitHub webhook JSON payload +- Headers: + - `x-hub-signature-256` + - `x-github-event` + +Response: + +- Success: `{ "ok": true }` +- Failure: `401` for invalid signature, `500` for processing failures + +Side effects: + +- updates GitHub installation status for `deleted`, `suspend`, and `unsuspend` + +Main callers: + +- GitHub webhook delivery + +## Shared Dependencies + +- `lib/auth.ts` +- `lib/services/github-app.ts` +- `lib/repo/github.ts` +- Prisma models `UserIdentity` and `GitHubAppInstallation` + +## Main Callers + +- login page +- Sealos auth server action +- popup callback page +- GitHub App install popup flows from settings and import dialogs + diff --git a/docs/wiki/api/index.md b/docs/wiki/api/index.md new file mode 100644 index 0000000..d959fb2 --- /dev/null +++ b/docs/wiki/api/index.md @@ -0,0 +1,51 @@ +# API Index + +## API Overview + +The repository exposes internal application APIs rather than a broad external developer platform. + +Main route families: + +- auth and GitHub lifecycle +- projects and runtime control +- user-scoped configuration + +All authenticated internal routes use App Router route handlers under `app/api/`. + +## Public Interfaces + +Public-facing route surfaces are limited to: + +- `GET | POST /api/auth/[...nextauth]` +- `GET /api/github/app/callback` +- `POST /api/github/app/webhook` + +Notes: + +- The auth route is public because NextAuth owns its exchange protocol. +- The GitHub callback is reachable from an external install flow, but still requires an authenticated Fulling session to bind the installation to a user. +- The webhook is public but guarded by GitHub signature verification. + +## Internal Interfaces + +Internal route surfaces cover: + +- project polling and lifecycle status changes +- project environment variable CRUD +- sandbox execution helpers +- user config storage and validation + +These routes are primarily consumed by in-repo hooks and dialogs rather than third-party clients. + +## Domain Index + +- [Auth and GitHub](./auth-and-github.md) +- [Projects and Runtime](./projects-and-runtime.md) +- [User Config](./user-config.md) + +## Notable Auth Gates + +- `withAuth` in `lib/api-auth.ts` is the standard API wrapper. +- Ownership checks are performed per project or sandbox. +- No API-wide middleware layer was found. + diff --git a/docs/wiki/api/projects-and-runtime.md b/docs/wiki/api/projects-and-runtime.md new file mode 100644 index 0000000..47cf5e7 --- /dev/null +++ b/docs/wiki/api/projects-and-runtime.md @@ -0,0 +1,450 @@ +# Projects and Runtime API + +## Domain Summary + +This domain covers live project reads, project lifecycle intent, project environment variables, and low-level sandbox helpers. + +Everything here is app-internal and owner-scoped. + +## Internal Endpoints + +### `GET /api/projects/[id]` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/route.ts` - route entry + +Auth: + +- `withAuth` +- project row filtered by `userId` + +Request: + +- Params: `id` project ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: project with ordered sandboxes, databases, environments, and tasks +- Failure: `404` when the project is not owned by the user, `500` on read failure + +Side effects: + +- none + +Main callers: + +- `hooks/use-project.ts` +- `app/(dashboard)/projects/_components/import-github-dialog.tsx` + +### `POST /api/projects/[id]/start` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/start/route.ts` +- `lib/repo/project.ts` +- `lib/util/action.ts` + +Auth: + +- `withAuth` +- project row filtered by `userId` + +Request: + +- Params: `id` project ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: message plus updated project status +- Failure: `404` when missing, `400` when current state does not allow start + +Side effects: + +- updates databases and sandboxes to `STARTING` +- updates project status to `STARTING` + +Main callers: + +- `hooks/use-project-operations.ts` + +### `POST /api/projects/[id]/stop` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/stop/route.ts` +- `lib/repo/project.ts` +- `lib/util/action.ts` + +Auth: + +- `withAuth` +- project row filtered by `userId` + +Request: + +- Params: `id` project ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: message plus updated project status +- Failure: `404` when missing, `400` when current state does not allow stop + +Side effects: + +- updates databases and sandboxes to `STOPPING` +- updates project status to `STOPPING` + +Main callers: + +- `hooks/use-project-operations.ts` + +### `POST /api/projects/[id]/delete` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/delete/route.ts` +- `lib/repo/project.ts` +- `lib/util/action.ts` + +Auth: + +- `withAuth` +- project row filtered by `userId` + +Request: + +- Params: `id` project ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: message plus updated project status +- Failure: `404` when missing, `400` when current state does not allow delete + +Side effects: + +- updates databases and sandboxes to `TERMINATING` +- eventually leads to hard deletion of runtime rows and the project row after reconcile + +Main callers: + +- `hooks/use-project-operations.ts` + +### `GET /api/projects/[id]/environment` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/environment/route.ts` + +Auth: + +- `withAuth` +- `verifyProjectAccess` + +Request: + +- Params: `id` project ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: grouped environment variables by category +- Failure: `500` on lookup failure + +Side effects: + +- none + +Main callers: + +- `hooks/use-environment-variables.ts` + +### `POST /api/projects/[id]/environment` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/environment/route.ts` + +Auth: + +- `withAuth` +- `verifyProjectAccess` + +Request: + +- Params: `id` project ID +- Query: none +- Body: + - single variable `{ key, value, category?, isSecret? }`, or + - batch `{ variables: [...] }` +- Headers: session cookies + +Response: + +- Success: created variable or `{ success: true, count }` +- Failure: + - `400` for invalid body or project not fully running + - `404` when project is missing + - `500` on write failure + +Side effects: + +- creates or replaces environment rows +- marks running sandboxes as `UPDATING` + +Main callers: + +- `hooks/use-environment-variables.ts` + +### `PUT /api/projects/[id]/environment/[envId]` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/environment/[envId]/route.ts` + +Auth: + +- `withAuth` +- `verifyProjectAccess` + +Request: + +- Params: + - `id` project ID + - `envId` environment row ID +- Query: none +- Body: `{ value }` +- Headers: session cookies + +Response: + +- Success: updated environment row +- Failure: + - `400` for missing value or non-running project + - `404` when the env row is not in that project + - `500` on write failure + +Side effects: + +- updates one env row +- marks running sandboxes as `UPDATING` + +Main callers: + +- `hooks/use-environment-variables.ts` + +### `DELETE /api/projects/[id]/environment/[envId]` + +Type: `internal` + +Source: + +- `app/api/projects/[id]/environment/[envId]/route.ts` + +Auth: + +- `withAuth` +- `verifyProjectAccess` + +Request: + +- Params: + - `id` project ID + - `envId` environment row ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ success: true }` +- Failure: + - `400` when the project is not fully running + - `404` when the env row is not in that project + - `500` on delete failure + +Side effects: + +- deletes one env row +- marks running sandboxes as `UPDATING` + +Main callers: + +- `hooks/use-environment-variables.ts` + +### `GET /api/sandbox/[id]/cwd` + +Type: `internal` + +Source: + +- `app/api/sandbox/[id]/cwd/route.ts` +- `lib/k8s/k8s-service-helper.ts` + +Auth: + +- `withAuth` +- sandbox ownership resolved from the parent project + +Request: + +- Params: `id` sandbox ID +- Query: `sessionId` required +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ cwd, homeDir, isInHome }` +- Failure: `400` for missing query param, `500` for runtime errors + +Side effects: + +- none + +Main callers: + +- `components/terminal/xterm-terminal.tsx` + +### `POST /api/sandbox/[id]/exec` + +Type: `internal` + +Source: + +- `app/api/sandbox/[id]/exec/route.ts` +- `lib/k8s/k8s-service-helper.ts` + +Auth: + +- `withAuth` +- sandbox ownership resolved from the parent project + +Request: + +- Params: `id` sandbox ID +- Query: none +- Body: `{ command, workdir? }` +- Headers: session cookies + +Response: + +- Success: `{ success: true, pid }` +- Failure: `400` for missing command, `500` for execution failure + +Side effects: + +- starts a background process in the sandbox + +Main callers: + +- `hooks/use-app-runner.ts` + +### `GET /api/sandbox/[id]/app-status` + +Type: `internal` + +Source: + +- `app/api/sandbox/[id]/app-status/route.ts` + +Auth: + +- `withAuth` +- sandbox ownership resolved from the parent project + +Request: + +- Params: `id` sandbox ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ running: boolean }` +- Failure: returns `{ running: false }` on handler error + +Side effects: + +- none + +Main callers: + +- no direct in-repo caller was found + +### `DELETE /api/sandbox/[id]/app-status` + +Type: `internal` + +Source: + +- `app/api/sandbox/[id]/app-status/route.ts` + +Auth: + +- `withAuth` +- sandbox ownership resolved from the parent project + +Request: + +- Params: `id` sandbox ID +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ success: true }` or `{ success: false, error }` +- Failure: `500` when the stop operation itself throws + +Side effects: + +- kills the process listening on sandbox port `3000` + +Main callers: + +- no direct in-repo caller was found + +## Shared Dependencies + +- `lib/api-auth.ts` +- `lib/repo/project.ts` +- `lib/k8s/k8s-service-helper.ts` +- `lib/util/action.ts` + +## Main Callers + +- `hooks/use-project.ts` +- `hooks/use-project-operations.ts` +- `hooks/use-environment-variables.ts` +- terminal components and sandbox execution hooks + diff --git a/docs/wiki/api/user-config.md b/docs/wiki/api/user-config.md new file mode 100644 index 0000000..b2ec8fe --- /dev/null +++ b/docs/wiki/api/user-config.md @@ -0,0 +1,283 @@ +# User Config API + +## Domain Summary + +This domain stores user-scoped configuration rather than project-scoped runtime state. It backs the settings dialog and parts of the integrations page. + +## Internal Endpoints + +### `GET /api/user/config` + +Type: `internal` + +Source: + +- `app/api/user/config/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: `keys=KEY1,KEY2` required +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ configs: { KEY: value } }` +- Failure: `400` when keys are missing, `500` on lookup failure + +Side effects: + +- none + +Main callers: + +- generic settings fetch usage + +### `POST /api/user/config` + +Type: `internal` + +Source: + +- `app/api/user/config/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: `{ configs: [{ key, value, category?, isSecret? }] }` +- Headers: session cookies + +Response: + +- Success: `{ success: true, configs: [...] }` +- Failure: `400` for invalid bodies, `500` on write failure + +Side effects: + +- upserts one or more `UserConfig` rows + +Main callers: + +- generic settings save usage + +### `GET /api/user/config/anthropic` + +Type: `internal` + +Source: + +- `app/api/user/config/anthropic/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ apiKey, apiBaseUrl, model, smallFastModel }` +- Failure: `500` on lookup failure + +Side effects: + +- none + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +### `POST /api/user/config/anthropic` + +Type: `internal` + +Source: + +- `app/api/user/config/anthropic/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: + - `apiBaseUrl` required + - `apiKey` required + - `model` optional + - `smallFastModel` optional +- Headers: session cookies + +Response: + +- Success: `{ success: true, message }` +- Failure: `400` for missing or invalid values, `500` on write failure + +Side effects: + +- upserts or deletes Anthropic-related `UserConfig` rows in a transaction + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +### `GET /api/user/config/kc` + +Type: `internal` + +Source: + +- `app/api/user/config/kc/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ kubeconfig, namespace }` +- Failure: `404` when kubeconfig is absent, `500` on lookup failure + +Side effects: + +- none + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +### `POST /api/user/config/kc` + +Type: `internal` + +Source: + +- `app/api/user/config/kc/route.ts` +- `lib/k8s/k8s-service-helper.ts` +- `lib/k8s/kubernetes-utils.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: `{ kubeconfig }` +- Headers: session cookies + +Response: + +- Success: `{ success: true, namespace, message }` +- Failure: `400` for missing or invalid kubeconfig, `500` on write failure + +Side effects: + +- validates kubeconfig +- upserts `KUBECONFIG` +- clears the cached per-user Kubernetes service instance + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +### `GET /api/user/config/system-prompt` + +Type: `internal` + +Source: + +- `app/api/user/config/system-prompt/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: none +- Headers: session cookies + +Response: + +- Success: `{ systemPrompt }` +- Failure: `500` on lookup failure + +Side effects: + +- none + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +### `POST /api/user/config/system-prompt` + +Type: `internal` + +Source: + +- `app/api/user/config/system-prompt/route.ts` + +Auth: + +- `withAuth` + +Request: + +- Params: none +- Query: none +- Body: `{ systemPrompt }` +- Headers: session cookies + +Response: + +- Success: `{ success: true, message }` +- Failure: `400` for missing prompt, `500` on write failure + +Side effects: + +- upserts `SYSTEM_PROMPT` in `UserConfig` + +Main callers: + +- `components/dialog/settings-dialog.tsx` + +## Shared Dependencies + +- `lib/api-auth.ts` +- Prisma `UserConfig` +- `components/dialog/settings-dialog.tsx` + +## Main Callers + +- settings dialog +- user settings flows + diff --git a/docs/wiki/architecture.md b/docs/wiki/architecture.md new file mode 100644 index 0000000..4f895ba --- /dev/null +++ b/docs/wiki/architecture.md @@ -0,0 +1,136 @@ +# Architecture + +## Overview + +Fulling splits responsibility between a Next.js interaction layer and a database-backed control plane. + +At a high level: + +1. App Router pages and client components collect user intent. +2. Internal APIs or server actions persist that intent in PostgreSQL through Prisma. +3. Reconcile jobs poll for records in transition states. +4. Event listeners call user-scoped Kubernetes or GitHub integrations. +5. Repository records are updated with the latest status, URLs, credentials, or task results. + +## Repository Shape + +- `app/` + - App Router pages, route handlers, layouts, and route-local components. +- `components/`, `hooks/`, `provider/` + - Client UI primitives, React Query hooks, session/theme/Sealos providers. +- `lib/actions/` + - Server actions used by client components for project, database, GitHub, sandbox, and skill operations. +- `lib/data/` + - Server-side read helpers for Server Components. +- `lib/api-auth.ts` + - Shared API authorization and ownership checks. +- `lib/repo/` + - Persistence helpers, lock acquisition, status reconciliation, and ownership-aware updates. +- `lib/events/` and `lib/jobs/` + - In-process event buses and cron-driven reconciliation. +- `lib/platform/` + - Newer control-plane layers: control, persistence, integrations, executors, and orchestrator scaffolding. +- `lib/k8s/` and `lib/services/` + - Provider-facing runtime logic for Kubernetes, GitHub App, ttyd, and Anthropic proxy support. + +## Runtime Boundaries + +### UI Layer + +The UI is App Router only. Server components gate authenticated routes and fetch initial data. Client components then handle interactive state, polling, forms, dialogs, and terminal UX. + +Key modules: + +- `app/layout.tsx` - root providers and global metadata +- `app/(dashboard)/projects/[id]/layout.tsx` - project ownership gate and persistent workspace shell +- `components/layout/project-content-wrapper.tsx` - persistent terminal panel plus route-driven content panel +- `components/dialog/settings-dialog.tsx` - user-scoped settings surface + +### Server Layer + +The server layer is split between internal API routes and server actions. + +- Internal API routes are used for authenticated app behavior such as project polling, environment variable writes, sandbox command execution, and user config persistence. +- Server actions are used where the UI wants a direct write-side entrypoint without modeling a public route shape. + +Key modules: + +- `app/api/**/route.ts` +- `lib/actions/project.ts` +- `lib/actions/database.ts` +- `lib/actions/skill.ts` +- `lib/actions/github.ts` + +### Control Plane + +The control plane is responsible for durable intent, not immediate infrastructure effects. + +- `lib/platform/control/commands/` accepts validated intent. +- `lib/platform/persistence/` creates the rows and queued task records needed to represent that intent. +- `lib/repo/` handles lower-level updates, row locking, and status aggregation. + +Notable examples: + +- `createProjectCommand` creates a project, sandbox metadata, and initial skill install tasks. +- `createProjectFromGitHubCommand` verifies repository access, creates the project, and queues a clone task. +- `createDatabaseCommand` creates the database control-plane row but does not create the database immediately. + +### Reconcile and Event Layer + +Background jobs poll for state transitions and emit typed events. + +- `lib/jobs/sandbox/sandboxReconcile.ts` +- `lib/jobs/database/databaseReconcile.ts` +- `lib/jobs/project-task/projectTaskReconcile.ts` +- `lib/events/sandbox/sandboxListener.ts` +- `lib/events/database/databaseListener.ts` + +This is the clearest expression of the repository's asynchronous reconciliation pattern. + +## Core Request Paths + +### Blank Project Creation + +1. The create project dialog calls `createProject` in `lib/actions/project.ts`. +2. `createProjectCommand` validates the name, resolves the user's default namespace, and creates project and sandbox rows. +3. The sandbox starts in a transition state. +4. The sandbox reconcile job locks that row and emits sandbox lifecycle events. +5. The sandbox listener calls the user-scoped Kubernetes service and updates URLs and status. + +### GitHub Import + +1. The import dialog reads GitHub App installations and repositories through server actions. +2. `createProjectFromGitHubCommand` creates project and sandbox rows, then queues `CLONE_REPOSITORY`. +3. The task reconcile job waits for the sandbox to reach `RUNNING`. +4. The clone executor uses a GitHub App installation token and ttyd command execution to clone the repository inside the sandbox. + +### Environment Variable Update + +1. Project config pages use `useEnvironmentVariables` and `useBatchUpdateEnvironmentVariables`. +2. Internal API routes persist environment rows only when the project is already running. +3. Successful writes mark sandboxes as `UPDATING`. +4. Sandbox reconcile then reloads project and Anthropic env vars and pushes them into Kubernetes. + +## Shared Libraries and Cross-Cutting Concerns + +- Prisma is the only persistence layer in active use. +- `react` cache is used in `lib/data/` to deduplicate request-scoped reads. +- React Query is the main client cache for live project state. +- `lib/fetch-client.ts` wraps browser fetch with timeout and automatic `401` redirect handling. +- `instrumentation.ts` and `lib/startup/index.ts` ensure listeners and jobs are only initialized once per server process. + +## External Dependencies + +- PostgreSQL via Prisma +- Kubernetes through user-provided kubeconfig +- Sealos desktop SDK for iframe-aware bootstrap +- GitHub App OAuth, installation APIs, and webhook verification +- ttyd for remote shell execution inside sandboxes +- Anthropic-compatible proxy settings stored in user config and projected into sandboxes + +## Constraints + +- The control plane is mid-transition: `lib/platform/` introduces a cleaner layered structure, but legacy `lib/repo/`, `lib/services/`, and `lib/actions/` modules are still heavily used. +- The schema allows multiple sandboxes and databases per project, but the current UI usually treats the first sandbox and first database as the primary runtime surfaces. +- Some navigation targets exist in sidebars without implemented routes; see [Routing](./routing.md). + diff --git a/docs/wiki/auth-and-state.md b/docs/wiki/auth-and-state.md new file mode 100644 index 0000000..38eb32f --- /dev/null +++ b/docs/wiki/auth-and-state.md @@ -0,0 +1,87 @@ +# Auth and State + +## Auth Providers + +Authentication is configured centrally in `lib/auth.ts` through NextAuth v5. + +Provider availability is environment-driven: + +- password credentials +- Sealos credentials +- GitHub App OAuth + +### Password Flow + +The credentials provider doubles as sign-in and registration. + +- if the password identity exists, the password hash is verified +- if it does not exist, the user is created automatically with a new password hash + +### Sealos Flow + +Sealos auth is exposed through the `sealos` credentials provider. + +It: + +- validates the JWT +- extracts the Sealos user ID +- stores kubeconfig on the matching `UserIdentity` +- updates `UserConfig.KUBECONFIG` +- can bootstrap Anthropic proxy credentials for the user + +### GitHub Flow + +GitHub App OAuth uses a custom provider wrapper and a `signIn` callback that: + +- creates or updates a `GITHUB` `UserIdentity` +- persists access and refresh tokens +- maps the GitHub identity to a Fulling user + +## Session and Cookies + +- session strategy: `jwt` +- session payload is minimal and stores `user.id` and `user.name` +- cookies are configured with `sameSite: 'none'` and `secure: true` + +The cookie configuration is intentionally cross-site friendly for Sealos iframe embedding. + +## Authorization Checks + +The repository does not rely on middleware for authorization. + +Instead, checks happen close to the resource: + +- Server Components call `auth()` and redirect unauthenticated users +- API routes wrap handlers with `withAuth` +- project ownership checks use helpers such as `verifyProjectAccess` +- sandbox ownership checks resolve through the parent project relationship + +This produces an owner-scoped model rather than a role-based permission model. + +## Shared Client State + +The main shared state containers are: + +- `SessionProvider` +- `QueryClientProvider` +- `SealosProvider` +- `ThemeProvider` + +`SealosProvider` detects whether the app is running inside a Sealos iframe and, when applicable, loads the Sealos session and kubeconfig. + +## Form and Mutation State + +The UI mostly uses local React state for forms and tabs. Network state is layered on top through: + +- `useTransition` +- React Query mutations +- `toast` notifications + +This keeps state localized instead of centralizing all writes in a global store. + +## Constraints + +- Provider availability depends on environment flags, so deployment configuration can materially change the visible auth surface. +- GitHub App callback handling is partly public-facing but still expects an authenticated Fulling session to bind the installation to the correct user. +- The repository currently models ownership and identity, not granular roles or team permissions. + diff --git a/docs/wiki/background-jobs.md b/docs/wiki/background-jobs.md new file mode 100644 index 0000000..d6de4b7 --- /dev/null +++ b/docs/wiki/background-jobs.md @@ -0,0 +1,130 @@ +# Background Jobs + +## Overview + +Fulling uses cron-driven reconcile loops instead of blocking user requests on infrastructure work. + +Startup wiring happens in: + +- `instrumentation.ts` +- `lib/startup/index.ts` + +On startup the app: + +1. registers sandbox and database event listeners +2. starts reconcile jobs for sandboxes, databases, and project tasks + +## Sandbox Reconcile + +Source: `lib/jobs/sandbox/sandboxReconcile.ts` + +Default behavior: + +- interval: every 7 seconds +- batch size: 10 rows +- lock window: 5 seconds by default, with jitter + +Eligible statuses: + +- `CREATING` +- `STARTING` +- `STOPPING` +- `TERMINATING` +- `UPDATING` + +The job atomically locks rows with `FOR UPDATE SKIP LOCKED`, then emits sandbox lifecycle events. + +## Database Reconcile + +Source: `lib/jobs/database/databaseReconcile.ts` + +Default behavior: + +- interval: every 11 seconds +- batch size: 10 rows +- lock window: 5 seconds by default, with jitter + +Eligible statuses: + +- `CREATING` +- `STARTING` +- `STOPPING` +- `TERMINATING` + +The database listener performs Kubernetes cluster operations and backfills connection credentials when the database becomes ready. + +## Project Task Reconcile + +Source: `lib/jobs/project-task/projectTaskReconcile.ts` + +Default behavior: + +- interval: every 13 seconds +- batch size: 10 rows +- reconcile lock window: 5 seconds by default +- execution lock window: 300 seconds by default + +Task orchestration logic includes: + +- prerequisite checks +- state transitions into `WAITING_FOR_PREREQUISITES` +- attempt counting and retry behavior +- special handling for superseded skill installs and clone prerequisites + +## Event Listener Behavior + +### Sandbox Events + +`lib/events/sandbox/sandboxListener.ts` handles: + +- create +- start +- stop +- delete +- update + +It also: + +- merges project env and Anthropic env before sandbox create or update +- updates sandbox URLs after creation +- triggers runnable project tasks when a sandbox reaches `RUNNING` + +### Database Events + +`lib/events/database/databaseListener.ts` handles: + +- create +- start +- stop +- delete + +It also: + +- fetches generated credentials once the cluster is ready +- updates project aggregate status after each transition + +## Task Executors + +Current executors under `lib/jobs/project-task/executors/` include: + +- clone repository +- install skill +- uninstall skill + +These executors use ttyd command execution inside the sandbox rather than direct Kubernetes file APIs. + +## Why This Matters + +This job model explains several user-visible behaviors: + +- project start and stop requests return before Kubernetes work finishes +- imported projects can exist before the repository has actually been cloned +- environment variable writes set the runtime to `UPDATING` and settle later +- global skill changes fan out across projects asynchronously + +## Constraints + +- All jobs run in-process inside the Next.js server process, so initialization correctness matters. +- The model assumes eventual convergence rather than immediate completion. +- Locks and polling avoid thundering herd behavior, but the user experience still depends on repeated status refreshes. + diff --git a/docs/wiki/config-and-env.md b/docs/wiki/config-and-env.md new file mode 100644 index 0000000..d22679f --- /dev/null +++ b/docs/wiki/config-and-env.md @@ -0,0 +1,105 @@ +# Config and Env + +## Configuration Files + +### `next.config.ts` + +The Next.js runtime is configured with: + +- `reactStrictMode: true` +- `output: 'standalone'` +- image allowlist for `avatars.githubusercontent.com` +- `serverExternalPackages: ['pino']` + +### `instrumentation.ts` + +The instrumentation hook initializes the application on server startup and calls `initializeApp()` from `lib/startup/index.ts`. + +That startup path registers listeners and starts background jobs once per process. + +### `package.json` + +Runtime assumptions: + +- Next.js 16 +- React 19 +- Node `>=22.12.0` +- pnpm `10.20.0` + +## Environment Variables + +### Platform-Level Variables + +Validated in `lib/env.ts`: + +- `DATABASE_URL` +- `RUNTIME_IMAGE` +- `ENABLE_PASSWORD_AUTH` +- `ENABLE_GITHUB_AUTH` +- `ENABLE_SEALOS_AUTH` +- `GITHUB_CLIENT_ID` +- `GITHUB_CLIENT_SECRET` +- `GITHUB_APP_ID` +- `GITHUB_APP_PRIVATE_KEY` +- `GITHUB_APP_WEBHOOK_SECRET` +- `GITHUB_APP_CLIENT_ID` +- `GITHUB_APP_CLIENT_SECRET` +- `ANTHROPIC_BASE_URL` +- `AIPROXY_ENDPOINT` +- `ANTHROPIC_MODEL` +- `ANTHROPIC_SMALL_FAST_MODEL` + +Client-exposed variables: + +- `NEXT_PUBLIC_GITHUB_APP_ID` +- `NEXT_PUBLIC_GITHUB_APP_NAME` + +### User-Scoped Runtime Config + +Stored in `UserConfig` and managed through settings APIs: + +- `KUBECONFIG` +- `ANTHROPIC_API_KEY` +- `ANTHROPIC_API` +- `ANTHROPIC_MODEL` +- `ANTHROPIC_SMALL_FAST_MODEL` +- `SYSTEM_PROMPT` + +Kubeconfig writes also clear the cached Kubernetes service instance for that user. + +### Project-Scoped Runtime Config + +Stored in the `Environment` table and managed per project. + +Known categories from `EnvironmentCategory`: + +- `auth` +- `payment` +- `ttyd` +- `file_browser` +- `general` +- `secret` + +Project configuration pages currently surface `auth`, `payment`, `general`, and `secret`. + +## Build-Time and Runtime Assumptions + +- The dev server and production server run on `0.0.0.0:3000`. +- Secure cookie behavior changes with `NODE_ENV`. +- Startup expects a Node.js runtime and does not initialize jobs in non-node runtimes. +- Reconcile behavior is interval-based and controlled by environment variables for lock duration and batch size. + +## Runtime Integrations + +Environment configuration directly influences: + +- auth provider availability +- GitHub App identity and webhook handling +- Kubernetes namespace and service access +- sandbox runtime image and projected env vars +- Anthropic-compatible proxy configuration inside sandboxes + +## Constraints + +- The repository includes `.env.template` and `yaml/.env.template`, but `lib/env.ts` remains the authoritative schema for validated platform env requirements. +- User config and project env are separate concerns. Global settings such as kubeconfig and Anthropic credentials do not live in project env rows. diff --git a/docs/wiki/data-models.md b/docs/wiki/data-models.md new file mode 100644 index 0000000..d3137e6 --- /dev/null +++ b/docs/wiki/data-models.md @@ -0,0 +1,171 @@ +# Data Models + +## Overview + +Prisma models in `prisma/schema.prisma` describe both user identity and control-plane state. The main design split is: + +- user-scoped identity and configuration +- project-scoped runtime resources +- queued asynchronous task state + +## Identity and User Config + +### `User` + +Top-level owner for: + +- identities +- projects +- user config +- global skills +- GitHub App installations + +### `UserIdentity` + +Represents external auth identities and sensitive metadata. + +Current providers: + +- `PASSWORD` +- `GITHUB` +- `SEALOS` + +Metadata stores provider-specific details such as password hashes, OAuth tokens, or Sealos kubeconfig. + +### `UserConfig` + +Stores user-scoped settings such as: + +- kubeconfig +- Anthropic proxy values +- system prompt + +The model includes `category` and `isSecret` so the UI can group and mask values. + +## GitHub Integration + +### `GitHubAppInstallation` + +Tracks GitHub App installation ownership and status. + +Important fields: + +- `installationId` +- account metadata +- repository selection mode +- permissions and subscribed events +- lifecycle status: `ACTIVE`, `SUSPENDED`, `DELETED` + +Projects can reference a selected installation. + +## Project and Runtime Resources + +### `Project` + +The top-level application object. + +Important fields: + +- display metadata +- legacy `githubRepo` +- newer GitHub App-backed repository metadata +- aggregated `status` + +Relations: + +- environments +- databases +- sandboxes +- project tasks + +### `Environment` + +Per-project key/value configuration rows. These are not independent runtime resources and have no lifecycle status. + +### `Sandbox` + +Represents the runtime workspace. + +Important fields: + +- Kubernetes namespace and sandbox name +- public app URL +- ttyd URL +- file browser URL +- runtime image and resource requests +- resource lifecycle status +- optimistic lock window + +### `Database` + +Represents the optional PostgreSQL cluster for a project. + +Important fields: + +- Kubernetes namespace and database name +- connection credentials and URL +- resource lifecycle status +- optimistic lock window + +## Global Skills and Async Tasks + +### `UserSkill` + +Represents globally enabled skills for a user. + +The current UI exposes a catalog-backed global desired state rather than project-local toggles. + +### `ProjectTask` + +Represents asynchronous work such as: + +- `CLONE_REPOSITORY` +- `INSTALL_SKILL` +- `UNINSTALL_SKILL` +- `DEPLOY_PROJECT` + +Important fields: + +- `status` +- `triggerSource` +- `payload` +- `result` +- `attemptCount` +- `maxAttempts` +- lock and timing fields + +## Status Models + +### Resource Status + +Used by sandboxes and databases: + +- `CREATING` +- `STARTING` +- `RUNNING` +- `STOPPING` +- `STOPPED` +- `TERMINATING` +- `TERMINATED` +- `ERROR` +- `UPDATING` + +### Project Status + +Derived from child resource states rather than independently authored. + +This lets project status reflect mixed runtime conditions such as: + +- creating +- starting +- stopping +- terminating +- error +- partial + +## Important Semantics + +- Projects can be deleted automatically when all child runtime resources are gone and aggregate to `TERMINATED`. +- The schema allows more than one sandbox or database per project, but current UI flows usually operate on the first sandbox and the first database. +- Task execution is resilient rather than strictly synchronous; retries and prerequisite waiting are first-class concerns in the model. + diff --git a/docs/wiki/features/auth-and-identity.md b/docs/wiki/features/auth-and-identity.md new file mode 100644 index 0000000..aacd81e --- /dev/null +++ b/docs/wiki/features/auth-and-identity.md @@ -0,0 +1,37 @@ +# Auth and Identity + +## Purpose + +This domain gets a user into the product and binds external identities to a stable Fulling user record. + +## User-Facing Surfaces + +- `/login` - credentials sign-in plus GitHub sign-in +- `/auth-error` - auth failure surface +- `/github/app/callback` - popup completion view for GitHub App installation + +## Main Flows + +- Credentials sign-in doubles as auto-registration when the username does not exist yet. +- GitHub sign-in creates or refreshes a `GITHUB` identity and maps it onto a Fulling user. +- Sealos auth can bootstrap kubeconfig and AI proxy settings for users coming from a Sealos environment. + +## Supporting APIs + +- `GET | POST /api/auth/[...nextauth]` - NextAuth handler +- `GET /api/github/app/callback` - bind GitHub App installation to the current user + +## Key Modules + +- `app/(auth)/login/page.tsx` - login UI +- `lib/auth.ts` - auth providers, callbacks, and cookie/session policy +- `provider/sealos.tsx` - Sealos environment detection +- `lib/actions/sealos-auth.ts` - server-side Sealos sign-in helper +- `app/github/app/callback/page.tsx` - popup completion flow + +## Constraints + +- Available auth providers depend on environment flags. +- There is no role or team permission model yet; access is owner-scoped. +- GitHub App install completion is not enough by itself; the installation must still be bound to the authenticated Fulling user. + diff --git a/docs/wiki/features/github-and-import.md b/docs/wiki/features/github-and-import.md new file mode 100644 index 0000000..881085e --- /dev/null +++ b/docs/wiki/features/github-and-import.md @@ -0,0 +1,42 @@ +# GitHub and Import + +## Purpose + +This domain connects Fulling projects to GitHub for repository import, installation tracking, and push-back to GitHub. + +## User-Facing Surfaces + +- project import dialog from `/projects` +- `/github/app/callback` - GitHub App install completion page +- `/projects/[id]/github` - repository initialize and push surface +- `/settings/integrations` - GitHub installation status summary + +## Main Flows + +- Install the GitHub App through a popup flow and persist the resulting installation. +- Select a repository from the installation and create a project in import mode. +- Wait for the sandbox to reach `RUNNING`, then clone the selected repository into the sandbox through a queued task. +- Initialize a new Git repository for a blank project and push changes back to GitHub from the project GitHub page. + +## Supporting APIs + +- `GET /api/github/app/callback` - installation binding +- `POST /api/github/app/webhook` - installation lifecycle updates +- `GET /api/projects/[id]` - import progress polling through project tasks + +## Key Modules + +- `app/(dashboard)/projects/_components/import-github-dialog.tsx` - repository picker and import progress poller +- `lib/actions/github.ts` - installation and repository reads +- `lib/actions/project.ts` - import action entrypoint +- `lib/platform/control/commands/project/create-project-from-github.ts` - import intent creation +- `lib/jobs/project-task/executors/clone-repository.ts` - in-sandbox clone execution +- `lib/services/github-app.ts` - GitHub App and OAuth service layer +- `lib/services/repoService.ts` - repo initialization and push helper for already-created projects + +## Constraints + +- Organization GitHub App installations are explicitly rejected today. +- Imported repositories are cloned into `/home/fulling/next/import/-`. +- The GitHub page for existing projects uses ttyd command execution and a `claude -p` commit command inside the sandbox when initializing and committing repositories. + diff --git a/docs/wiki/features/global-skills.md b/docs/wiki/features/global-skills.md new file mode 100644 index 0000000..d68f993 --- /dev/null +++ b/docs/wiki/features/global-skills.md @@ -0,0 +1,40 @@ +# Global Skills + +## Purpose + +This domain defines shared skill desired state for a user and fans that state out across projects through asynchronous tasks. + +## User-Facing Surfaces + +- `/skills` - global skill library + +## Main Flows + +- Enable a global skill and create `INSTALL_SKILL` tasks for existing projects. +- Inherit currently enabled skills when new projects are created. +- Uninstall a global skill, cancel stale pending installs, and create `UNINSTALL_SKILL` tasks where removal is still needed. +- Execute install and uninstall commands inside project sandboxes after prerequisite checks pass. + +## Supporting APIs + +This domain does not currently expose a dedicated REST route. The UI uses server actions: + +- `enableGlobalSkill` +- `uninstallGlobalSkill` + +## Key Modules + +- `app/(dashboard)/skills/_components/skills-library.tsx` - skills UI +- `lib/actions/skill.ts` - server action entrypoints +- `lib/skills/catalog.ts` - source of available skills +- `lib/platform/control/commands/skill/enable-global-skill.ts` +- `lib/platform/control/commands/skill/uninstall-global-skill.ts` +- `lib/jobs/project-task/executors/install-skill.ts` +- `lib/jobs/project-task/executors/uninstall-skill.ts` + +## Constraints + +- The current catalog is intentionally small; only `frontend-design` is present in code today. +- Skill rollout depends on sandbox availability and, for imported projects, clone task completion. +- Uninstall does not auto-start stopped sandboxes just to remove a skill. + diff --git a/docs/wiki/features/project-workspace.md b/docs/wiki/features/project-workspace.md new file mode 100644 index 0000000..09e924d --- /dev/null +++ b/docs/wiki/features/project-workspace.md @@ -0,0 +1,52 @@ +# Project Workspace + +## Purpose + +This domain is the day-to-day operating surface for a project: runtime status, terminal access, optional database, and project-scoped configuration. + +## User-Facing Surfaces + +- `/projects` - project list and creation entry +- `/projects/[id]/terminal` - primary runtime view +- `/projects/[id]/database` - optional PostgreSQL surface +- `/projects/[id]/environment` - general env vars +- `/projects/[id]/secrets` - secret env vars +- `/projects/[id]/auth` - auth-related env templates +- `/projects/[id]/payment` - payment-related env templates + +## Main Flows + +- Create a blank project from the dashboard dialog. +- Open the workspace shell, where the terminal remains mounted across route changes. +- Start, stop, or delete the project by updating resource statuses and waiting for reconcile. +- Add a database later if the project does not already have one. +- Edit environment variables only while the project runtime is already running. + +## Supporting APIs + +- `GET /api/projects/[id]` - live project state +- `POST /api/projects/[id]/start` - request runtime start +- `POST /api/projects/[id]/stop` - request runtime stop +- `POST /api/projects/[id]/delete` - request project teardown +- `GET | POST /api/projects/[id]/environment` - grouped env read and create/batch replace +- `PUT | DELETE /api/projects/[id]/environment/[envId]` - individual env edits +- `GET /api/sandbox/[id]/cwd` - terminal working directory lookup +- `POST /api/sandbox/[id]/exec` - detached sandbox command execution + +## Key Modules + +- `app/(dashboard)/projects/(list)/page.tsx` - projects overview +- `app/(dashboard)/projects/[id]/layout.tsx` - workspace shell and auth gate +- `components/layout/project-content-wrapper.tsx` - persistent terminal/content split +- `hooks/use-project.ts` - live project polling +- `hooks/use-project-operations.ts` - start/stop/delete client helper +- `hooks/use-environment-variables.ts` - environment variable CRUD +- `lib/actions/project.ts` - create/import server actions +- `lib/actions/database.ts` - optional database actions + +## Constraints + +- `/projects/[id]` is just a redirect to the terminal page. +- Current UI logic assumes one primary sandbox and at most one practical database, even though the schema is more flexible. +- Environment writes are rejected unless all sandboxes are already `RUNNING`. + diff --git a/docs/wiki/features/user-settings.md b/docs/wiki/features/user-settings.md new file mode 100644 index 0000000..85a669b --- /dev/null +++ b/docs/wiki/features/user-settings.md @@ -0,0 +1,40 @@ +# User Settings + +## Purpose + +This domain manages user-scoped configuration that affects all projects or the platform shell itself. + +## User-Facing Surfaces + +- `/settings` - redirects to integrations +- `/settings/integrations` - current settings page +- settings dialog opened from sidebars or project GitHub surfaces + +## Main Flows + +- Save a system prompt for AI-assisted development context. +- Validate and store kubeconfig for user-scoped Kubernetes access. +- Save Anthropic-compatible proxy configuration. +- Install or inspect the connected GitHub App account. + +## Supporting APIs + +- `GET | POST /api/user/config` +- `GET | POST /api/user/config/anthropic` +- `GET | POST /api/user/config/kc` +- `GET | POST /api/user/config/system-prompt` + +## Key Modules + +- `components/dialog/settings-dialog.tsx` - primary settings UI +- `app/(dashboard)/settings/integrations/page.tsx` - settings landing page +- `app/(dashboard)/settings/_components/github-status-card.tsx` - GitHub integration summary +- `provider/sealos.tsx` - Sealos environment detection +- `lib/k8s/k8s-service-helper.ts` - kubeconfig persistence and cache invalidation + +## Constraints + +- Only `/settings/integrations` is implemented; `/settings/account` is linked but missing. +- Kubeconfig is user-scoped, not project-scoped. +- In a Sealos environment the app can detect iframe context and treat kubeconfig differently from a normal browser session. + diff --git a/docs/wiki/index.md b/docs/wiki/index.md new file mode 100644 index 0000000..2369143 --- /dev/null +++ b/docs/wiki/index.md @@ -0,0 +1,47 @@ +# Fulling Wiki + +## Project Summary + +Fulling is a single-repo Next.js application for creating and operating AI-assisted development sandboxes. A project always starts with a sandbox runtime and can optionally add a PostgreSQL database later. GitHub App installation, repository import, runtime control, and global skill rollout all hang off that core project model. + +The codebase combines a conventional App Router UI with a control plane that persists intent in PostgreSQL and lets background reconcile jobs bring Kubernetes resources into the expected state. + +## Current Routing Mode + +- Router mode: `app` +- UI routes live under `app/` +- API routes live under `app/api/` +- No Pages Router UI surface was found +- No `middleware.ts` was found + +See [Routing](./routing.md) for the route map and layout structure. + +## Main Business Domains + +- [Auth and Identity](./features/auth-and-identity.md) +- [Project Workspace](./features/project-workspace.md) +- [GitHub and Import](./features/github-and-import.md) +- [User Settings](./features/user-settings.md) +- [Global Skills](./features/global-skills.md) + +## Main Runtime Surfaces + +- UI and layouts: App Router pages under `app/` +- Internal API surface: authenticated route handlers under `app/api/` +- Server actions: write-side entrypoints under `lib/actions/` +- Control plane commands: durable intent handling under `lib/platform/control/commands/` +- Reconcile jobs and listeners: `lib/jobs/` and `lib/events/` +- External integrations: Kubernetes, Sealos, GitHub App, ttyd, and Anthropic proxy support + +## Wiki Map + +- [Architecture](./architecture.md) +- [Routing](./routing.md) +- [Rendering and Data Flow](./rendering-and-data-flow.md) +- [Auth and State](./auth-and-state.md) +- [Config and Env](./config-and-env.md) +- [Data Models](./data-models.md) +- [Integrations](./integrations.md) +- [Background Jobs](./background-jobs.md) +- [TODO](./todo.md) +- [API Index](./api/index.md) diff --git a/docs/wiki/integrations.md b/docs/wiki/integrations.md new file mode 100644 index 0000000..2c5c76c --- /dev/null +++ b/docs/wiki/integrations.md @@ -0,0 +1,101 @@ +# Integrations + +## Overview + +The repository integrates with external systems through a mix of `lib/k8s/`, `lib/services/`, `lib/util/`, and the newer `lib/platform/integrations/` layer. + +The main integrations are: + +- Kubernetes +- Sealos +- GitHub App and GitHub OAuth +- ttyd +- Anthropic-compatible proxy settings + +## Kubernetes + +Kubernetes is the primary infrastructure backend for both sandbox and database resources. + +Core integration points: + +- `lib/k8s/k8s-service-helper.ts` - user-scoped service resolution from `KUBECONFIG` +- `lib/k8s/kubernetes-service-factory.ts` - service instance caching +- `lib/k8s/kubernetes.ts` - main service implementation +- `lib/platform/integrations/k8s/get-user-default-namespace.ts` - control-plane namespace lookup + +Kubernetes effects are intentionally kept out of the initial user mutation path. The control plane writes intent first, then reconcile jobs call the Kubernetes service later. + +## Sealos + +Sealos appears in two roles: + +1. embedded runtime detection through `provider/sealos.tsx` +2. auth bootstrap through the Sealos credentials provider in `lib/auth.ts` + +When the app detects a Sealos iframe, it can pull session data, kubeconfig, and namespace-like identity details from the Sealos desktop SDK. + +## GitHub App and GitHub OAuth + +GitHub integration covers three related needs: + +- user sign-in and token storage +- GitHub App installation tracking +- repository discovery and import + +Core modules: + +- `lib/services/github-app.ts` +- `app/api/github/app/callback/route.ts` +- `app/api/github/app/webhook/route.ts` +- `lib/actions/github.ts` +- `lib/platform/integrations/github/find-installation-repository.ts` + +The webhook currently updates installation lifecycle status. Repository import uses installation tokens rather than user PAT-like flows. + +## ttyd + +ttyd is the transport layer for sandbox command execution. + +Important modules: + +- `lib/util/ttyd-context.ts` +- `lib/util/ttyd-exec.ts` +- `app/api/sandbox/[id]/exec/route.ts` +- `app/api/sandbox/[id]/cwd/route.ts` +- `lib/jobs/project-task/executors/*` + +This is how the app: + +- runs background commands in the sandbox +- resolves current working directories +- clones GitHub repositories into the sandbox +- installs and uninstalls skills inside project workspaces + +## Anthropic Proxy Support + +User-level Anthropic settings are stored in `UserConfig`. `lib/services/aiproxy.ts` then: + +- creates proxy tokens when Sealos auth is used +- projects Anthropic env vars into sandboxes during create and update flows + +This lets sandboxes inherit AI configuration without storing those values directly in project env rows. + +## Emerging `lib/platform/integrations/` Layer + +Readmes under `lib/platform/integrations/` describe a cleaner boundary for provider-specific protocol logic. + +Currently visible integration slices: + +- `github/` +- `k8s/` +- `aiproxy/` +- `ttyd/` + +The repository still mixes old and new approaches, so these directories should be read as directionally important rather than fully exhaustive of all provider-facing code. + +## Constraints + +- GitHub organization installations are explicitly rejected in the callback flow today. +- ttyd-backed command execution is powerful and central to task execution, so sandbox availability is a hard prerequisite for import and skill rollout. +- Kubernetes access is entirely user-scoped. Without `KUBECONFIG`, project and database creation fail early. + diff --git a/docs/wiki/rendering-and-data-flow.md b/docs/wiki/rendering-and-data-flow.md new file mode 100644 index 0000000..a606f90 --- /dev/null +++ b/docs/wiki/rendering-and-data-flow.md @@ -0,0 +1,117 @@ +# Rendering and Data Flow + +## Rendering Model + +The repository mixes Server Components for routing, access control, and initial reads with Client Components for long-lived UI state and runtime interaction. + +Server-driven examples: + +- `app/(landing)/page.tsx` fetches GitHub star count on the server. +- `app/(dashboard)/projects/(list)/page.tsx` checks the session and reads projects on the server. +- `app/(dashboard)/projects/[id]/layout.tsx` verifies ownership on the server before rendering the workspace shell. + +Client-driven examples: + +- project configuration pages under `app/(dashboard)/projects/[id]/*` +- `components/layout/project-content-wrapper.tsx` +- `components/dialog/settings-dialog.tsx` +- `app/(dashboard)/skills/_components/skills-library.tsx` + +## Data Fetching + +### Server Reads + +Server Components mainly use: + +- `auth()` from `lib/auth.ts` +- cached Prisma reads from `lib/data/project.ts` and `lib/data/user-skill.ts` + +These reads are request-scoped and do not try to keep live runtime state in sync after render. + +### Client Reads + +The client uses React Query for live state. + +- `provider/providers.tsx` creates the shared `QueryClient` +- `hooks/use-project.ts` polls `/api/projects/[id]` every 3 seconds by default +- `hooks/use-environment-variables.ts` reads and mutates environment variables through internal API routes + +The result is a split model: + +- server render for secure entry and initial HTML +- client polling for runtime status, task progress, and mutation refresh + +## Cache and Revalidation + +- Landing page fetches GitHub star count with `next: { revalidate: 3600 }`. +- Query client default `staleTime` is 5 seconds. +- `useProject` uses a 2 second stale window and a 3 second refetch interval. +- `useEnvironmentVariables` uses a 5 second stale window and no focus refetch. + +There is no repository-wide custom cache layer beyond React cache and React Query. + +## Mutations and Server Actions + +The repository uses both server actions and internal APIs. + +### Server Actions + +Used when the UI wants a direct write-side call: + +- `createProject` +- `importProjectFromGitHub` +- `createDatabase` +- `deleteDatabase` +- `enableGlobalSkill` +- `uninstallGlobalSkill` +- GitHub installation and repository listing helpers + +### Internal APIs + +Used when the UI needs explicit route contracts or browser fetch: + +- project polling and lifecycle control +- environment variable CRUD +- sandbox execution and status endpoints +- user configuration endpoints + +## Runtime State Flow + +### Project Workspace + +The project layout keeps a persistent terminal shell mounted through `ProjectContentWrapper`. + +- terminal state stays alive across route changes +- non-terminal pages render in a separate content panel +- route changes switch visibility instead of unmounting the terminal + +This is important because sandbox terminal state depends on long-lived websocket and ttyd interaction. + +### Settings and Forms + +Most forms use local component state plus mutation hooks or direct fetch calls. + +Common patterns: + +- `useState` for form fields and dialogs +- `useTransition` for optimistic UI around server actions +- `useMutation` for environment variable writes +- `toast` notifications for success and failure + +## Client State + +Shared client state is limited and intentional: + +- session state from NextAuth +- React Query cache +- Sealos iframe/session context +- theme selection via `next-themes` + +There is no broader global store such as Redux or Zustand in the current codebase. + +## Constraints + +- Project status is intentionally eventual. UI polling is the primary way users observe background reconcile progress. +- Environment writes are blocked unless the project and all sandboxes are already running. +- Some sandbox operations still live under route handlers even though `lib/actions/sandbox.ts` notes a future migration toward server actions. + diff --git a/docs/wiki/routing.md b/docs/wiki/routing.md new file mode 100644 index 0000000..09410c9 --- /dev/null +++ b/docs/wiki/routing.md @@ -0,0 +1,149 @@ +# Routing + +## Routing Overview + +Fulling uses the App Router only. The route tree is organized with route groups for landing, auth, and dashboard surfaces, plus a standalone GitHub callback page. + +Route groups: + +- `(landing)` - marketing and public entry surface +- `(auth)` - login and auth error views +- `(dashboard)` - authenticated application UI for projects, settings, and skills +- standalone `/github/app/callback` - popup-oriented GitHub App install completion page + +No `middleware.ts` was found, so route access is enforced in server components and API helpers rather than global middleware. + +## Layouts + +### Root Layout + +`app/layout.tsx` wraps the app in: + +- `SessionProvider` +- `QueryClientProvider` +- `SealosProvider` +- `ThemeProvider` +- global toaster notifications + +### Projects List Layout + +`app/(dashboard)/projects/(list)/layout.tsx` renders: + +- shared dashboard sidebar +- search bar +- projects list content + +### Project Detail Layout + +`app/(dashboard)/projects/[id]/layout.tsx` is the main workspace shell. + +It: + +- checks auth with `auth()` +- verifies the project belongs to the current user +- mounts a primary sidebar +- mounts a project-specific sidebar +- renders `ProjectContentWrapper`, which keeps the terminal mounted across navigation + +### Settings Layout + +`app/(dashboard)/settings/layout.tsx` renders the shared sidebar and a settings sidebar, then redirects the top-level settings page to `/settings/integrations`. + +### Skills Layout + +`app/(dashboard)/skills/layout.tsx` renders the shared dashboard sidebar and a single-column content area. + +## App Routes + +### Public and Pre-Auth Pages + +- `/` - landing page with server-fetched GitHub star count +- `/login` - credentials and GitHub sign-in UI +- `/auth-error` - auth error view +- `/github/app/callback` - popup page that calls the API callback and posts a message back to the opener + +### Dashboard Pages + +- `/projects` +- `/projects/[id]` + - redirects to `/projects/[id]/terminal` +- `/projects/[id]/terminal` +- `/projects/[id]/database` +- `/projects/[id]/environment` +- `/projects/[id]/secrets` +- `/projects/[id]/auth` +- `/projects/[id]/payment` +- `/projects/[id]/github` +- `/projects/[id]/exec-test` +- `/settings` + - redirects to `/settings/integrations` +- `/settings/integrations` +- `/skills` + +## API Routes + +API routes live under `app/api/` and are documented in [API Index](./api/index.md). + +Main route families: + +- `/api/auth/[...nextauth]` +- `/api/github/app/*` +- `/api/projects/[id]/*` +- `/api/sandbox/[id]/*` +- `/api/user/config/*` + +## Dynamic Segments + +UI dynamic segments: + +- `/projects/[id]` + +API dynamic segments: + +- `/api/auth/[...nextauth]` +- `/api/projects/[id]` +- `/api/projects/[id]/environment/[envId]` +- `/api/sandbox/[id]` + +## Navigation by Domain + +### Global Sidebar + +The shared dashboard sidebar exposes links for: + +- `/projects` +- `/skills` +- `/settings` + +It also advertises additional surfaces that are not implemented as routes yet: + +- `/mcp` +- `/templates` +- `/integrations` + +### Project Sidebar + +The project workspace sidebar is split into: + +- Workspace + - terminal + - database +- Configuration + - environment + - secrets + - auth + - payment + - GitHub + +### Settings Sidebar + +The settings sidebar links to: + +- `/settings/integrations` +- `/settings/account` (currently unimplemented) + +## Route-Level Constraints + +- Project detail access is enforced in the project layout, not middleware. +- `/projects/[id]` is not a real overview page; it always redirects to the terminal page. +- `app/(dashboard)/projects/(list)/_components/project-actions-menu.tsx` still pushes to `/projects/[id]/settings`, but no such route exists. The actual project configuration pages are split across database, environment, secrets, auth, payment, and GitHub routes. diff --git a/docs/wiki/todo.md b/docs/wiki/todo.md new file mode 100644 index 0000000..4f8527e --- /dev/null +++ b/docs/wiki/todo.md @@ -0,0 +1,29 @@ +# TODO + +## Overview + +This page collects code-backed follow-up work that is visible from the current repository state. These items are not a roadmap promise. They are simply the most obvious gaps and cleanup points surfaced while generating the wiki. + +## Navigation Gaps + +- Implement `/mcp`, `/templates`, and `/integrations`, or remove those links from `components/sidebar.tsx`. +- Implement `/settings/account`, or remove that link from `app/(dashboard)/settings/_components/settings-sidebar.tsx`. +- Fix the stale `/projects/[id]/settings` navigation target in `app/(dashboard)/projects/(list)/_components/project-actions-menu.tsx`. + +## Project Workspace Follow-Ups + +- Decide whether `/projects/[id]/exec-test` is a permanent product surface or a debug-only page, then align navigation and docs accordingly. +- Review the current assumption that the first sandbox and first database are the primary runtime surfaces, even though the schema supports more than one of each. +- Revisit the environment update rule that blocks writes unless the full project is already `RUNNING`, and confirm that this is the intended UX for setup flows. + +## API and Control Plane Follow-Ups + +- Add stronger request validation around internal route handlers, which currently rely mostly on inline checks instead of shared schemas. +- Finish the migration noted in `lib/actions/sandbox.ts` so sandbox operations do not remain split across route handlers and server actions. +- Continue consolidating platform logic into `lib/platform/` so the newer control-plane layering becomes the clear source of truth. + +## Documentation Follow-Ups + +- Keep this page in sync when missing routes are implemented or removed. +- If task priority starts to matter, replace this flat list with a status-driven backlog page rather than mixing implementation state into architecture pages. +