|
| 1 | +# Involute |
| 2 | + |
| 3 | +一人团队的 Linear 式项目管理系统开源实现。 |
| 4 | + |
| 5 | +Involute bundles a GraphQL API, a kanban web app, and a CLI that can export one Linear team, import it into Involute, verify the result, and then let you visually accept it in the board UI. |
| 6 | + |
| 7 | +## Workspace layout |
| 8 | + |
| 9 | +- `packages/server`: GraphQL API, Prisma schema, import pipeline |
| 10 | +- `packages/web`: React + Vite kanban UI |
| 11 | +- `packages/cli`: `involute` CLI for config, export, import, verify, issues, and comments |
| 12 | +- `docs/vision.md`: current product vision |
| 13 | +- `docs/milestones.md`: active milestones and sequencing |
| 14 | + |
| 15 | +## Quick start |
| 16 | + |
| 17 | +1. Install dependencies and create the repo `.env`. |
| 18 | + |
| 19 | +```bash |
| 20 | +pnpm install |
| 21 | +cp .env.example .env |
| 22 | +``` |
| 23 | + |
| 24 | +The default `.env.example` is enough for local Docker Compose. You only need to change it when you want a different auth token, port, or database URL. |
| 25 | + |
| 26 | +2. Start the local stack with Docker Compose. |
| 27 | + |
| 28 | +```bash |
| 29 | +pnpm compose:up |
| 30 | +``` |
| 31 | + |
| 32 | +3. Smoke check the stack. |
| 33 | + |
| 34 | +```bash |
| 35 | +curl http://localhost:4200/health |
| 36 | +open http://localhost:4201 |
| 37 | +``` |
| 38 | + |
| 39 | +Compose defaults: |
| 40 | + |
| 41 | +- API: `http://localhost:4200` |
| 42 | +- Web: `http://localhost:4201` |
| 43 | +- Postgres: `127.0.0.1:5434` |
| 44 | +- CLI export mount: `.tmp/` on the host is available as `/exports` in the `cli` container |
| 45 | + |
| 46 | +Stop the stack with: |
| 47 | + |
| 48 | +```bash |
| 49 | +pnpm compose:down |
| 50 | +``` |
| 51 | + |
| 52 | +## Manual single-team import |
| 53 | + |
| 54 | +Set your Linear token in the shell: |
| 55 | + |
| 56 | +```bash |
| 57 | +export LINEAR_TOKEN='lin_api_xxx' |
| 58 | +``` |
| 59 | + |
| 60 | +Run the end-to-end team import inside the compose CLI container: |
| 61 | + |
| 62 | +```bash |
| 63 | +docker compose run --rm cli import team --token "$LINEAR_TOKEN" --team SON --keep-export --output /exports/son-export |
| 64 | +``` |
| 65 | + |
| 66 | +What this does: |
| 67 | + |
| 68 | +- exports one Linear team into `.tmp/son-export` |
| 69 | +- imports the exported data into Involute |
| 70 | +- runs `import verify` |
| 71 | +- writes `.tmp/son-export/involute-import-summary.json` |
| 72 | + |
| 73 | +After it completes, open `http://localhost:4201` and visually check the imported team in the board. |
| 74 | + |
| 75 | +Recommended acceptance checks: |
| 76 | + |
| 77 | +- the target team appears in the board |
| 78 | +- issue count looks complete for that team |
| 79 | +- a few issues have the expected state, labels, assignee, and comments |
| 80 | +- the latest imported issues are visible in the board, not hidden behind the first page |
| 81 | + |
| 82 | +## Local development without Docker |
| 83 | + |
| 84 | +Start the API: |
| 85 | + |
| 86 | +```bash |
| 87 | +DATABASE_URL="postgresql://involute:involute@127.0.0.1:5434/involute?schema=public" AUTH_TOKEN="changeme-set-your-token" pnpm --filter @involute/server exec tsx src/index.ts |
| 88 | +``` |
| 89 | + |
| 90 | +Start the web app: |
| 91 | + |
| 92 | +```bash |
| 93 | +VITE_INVOLUTE_AUTH_TOKEN="changeme-set-your-token" VITE_INVOLUTE_GRAPHQL_URL="http://127.0.0.1:4200/graphql" pnpm --filter @involute/web exec vite --host 127.0.0.1 --port 4201 |
| 94 | +``` |
| 95 | + |
| 96 | +Run the CLI against that local API: |
| 97 | + |
| 98 | +```bash |
| 99 | +pnpm --filter @involute/cli exec node dist/index.js import team --token "$LINEAR_TOKEN" --team SON --keep-export --output .tmp/son-export |
| 100 | +``` |
| 101 | + |
| 102 | +## Quality gates |
| 103 | + |
| 104 | +Unit and integration checks: |
| 105 | + |
| 106 | +```bash |
| 107 | +pnpm typecheck |
| 108 | +pnpm test |
| 109 | +pnpm build |
| 110 | +``` |
| 111 | + |
| 112 | +Browser E2E: |
| 113 | + |
| 114 | +```bash |
| 115 | +pnpm e2e |
| 116 | +``` |
| 117 | + |
| 118 | +The Playwright suite resets the local compose Postgres, seeds the base team, starts the API and web app, and verifies the full issue lifecycle: create, update, comment, delete comment, delete issue. |
| 119 | + |
| 120 | +## Docker images |
| 121 | + |
| 122 | +This repo ships one multi-target `Dockerfile` with `server`, `web`, and `cli` targets. The Docker Hub publish workflow expects these secrets: |
| 123 | + |
| 124 | +- `DOCKERHUB_USERNAME` |
| 125 | +- `DOCKERHUB_TOKEN` |
| 126 | + |
| 127 | +When they are set, `.github/workflows/docker-publish.yml` pushes: |
| 128 | + |
| 129 | +- `${DOCKERHUB_USERNAME}/involute-server` |
| 130 | +- `${DOCKERHUB_USERNAME}/involute-web` |
| 131 | +- `${DOCKERHUB_USERNAME}/involute-cli` |
| 132 | + |
| 133 | +If you want to use the published images directly, tag and push them from `main` through the workflow instead of building ad hoc local variants. The compose stack is the reference runtime path and should stay green before publishing. |
| 134 | + |
| 135 | +## Current focus |
| 136 | + |
| 137 | +- Make single-team import a repeatable acceptance loop |
| 138 | +- Keep the compose stack and CI reproducible |
| 139 | +- Lock the core board lifecycle down with E2E before the larger UI/UX redesign |
| 140 | + |
| 141 | +See [docs/vision.md](/Users/chris/workspace/Involute/docs/vision.md) and [docs/milestones.md](/Users/chris/workspace/Involute/docs/milestones.md) for the product direction. |
0 commit comments