Skip to content

Commit c9a684c

Browse files
chrischris
authored andcommitted
Productize team import and add board e2e
1 parent 6123bad commit c9a684c

40 files changed

Lines changed: 1936 additions & 180 deletions

.dockerignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
node_modules
2+
.git
3+
.DS_Store
4+
.env
5+
.factory
6+
dist
7+
packages/*/dist
8+
packages/server/src/*.js
9+
packages/server/src/*.js.map
10+
packages/server/src/*.d.ts
11+
packages/server/src/*.d.ts.map
12+
packages/server/prisma/*.js
13+
packages/server/prisma/*.js.map
14+
packages/server/prisma/*.d.ts
15+
packages/server/prisma/*.d.ts.map
16+
.tmp
17+
playwright-report
18+
test-results

.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
DATABASE_URL=YOUR_DATABASE_URL_HERE
2-
AUTH_TOKEN=YOUR_AUTH_TOKEN_HERE
1+
DATABASE_URL=postgresql://involute:involute@127.0.0.1:5434/involute?schema=public
2+
AUTH_TOKEN=changeme-set-your-token
33
PORT=4200

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
concurrency:
10+
group: ci-${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
verify:
15+
runs-on: ubuntu-latest
16+
env:
17+
CI: "true"
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Setup pnpm
23+
uses: pnpm/action-setup@v4
24+
with:
25+
version: 10.30.1
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: 22
31+
cache: pnpm
32+
33+
- name: Install dependencies
34+
run: pnpm install --frozen-lockfile
35+
36+
- name: Install Playwright browser
37+
run: pnpm exec playwright install --with-deps chromium
38+
39+
- name: Typecheck
40+
run: pnpm typecheck
41+
42+
- name: Unit tests
43+
run: pnpm test
44+
45+
- name: End-to-end tests
46+
run: pnpm e2e
47+
48+
- name: Build
49+
run: pnpm build
50+
51+
- name: Docker Compose build
52+
run: docker compose build
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Docker Publish
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
publish:
11+
if: ${{ secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
include:
17+
- image: involute-server
18+
target: server
19+
- image: involute-web
20+
target: web
21+
- image: involute-cli
22+
target: cli
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Set up Docker Buildx
28+
uses: docker/setup-buildx-action@v3
29+
30+
- name: Log in to Docker Hub
31+
uses: docker/login-action@v3
32+
with:
33+
username: ${{ secrets.DOCKERHUB_USERNAME }}
34+
password: ${{ secrets.DOCKERHUB_TOKEN }}
35+
36+
- name: Build and push
37+
uses: docker/build-push-action@v6
38+
with:
39+
context: .
40+
push: true
41+
target: ${{ matrix.target }}
42+
tags: |
43+
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image }}:latest
44+
${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image }}:sha-${{ github.sha }}

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,14 @@ dist
44
.env
55
.DS_Store
66
!packages/server/prisma/.env
7+
.tmp
8+
playwright-report
9+
test-results
10+
packages/server/src/*.js
11+
packages/server/src/*.js.map
12+
packages/server/src/*.d.ts
13+
packages/server/src/*.d.ts.map
14+
packages/server/prisma/*.js
15+
packages/server/prisma/*.js.map
16+
packages/server/prisma/*.d.ts
17+
packages/server/prisma/*.d.ts.map

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM node:22-bookworm-slim AS base
2+
3+
ENV PNPM_HOME=/pnpm
4+
ENV PATH=$PNPM_HOME:$PATH
5+
6+
WORKDIR /app
7+
8+
RUN corepack enable
9+
RUN apt-get update \
10+
&& apt-get install -y --no-install-recommends ca-certificates openssl \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json ./
14+
COPY packages/shared/package.json packages/shared/package.json
15+
COPY packages/server/package.json packages/server/package.json
16+
COPY packages/cli/package.json packages/cli/package.json
17+
COPY packages/web/package.json packages/web/package.json
18+
19+
RUN pnpm install --frozen-lockfile
20+
21+
COPY . .
22+
23+
FROM base AS server
24+
25+
RUN pnpm --filter @involute/server build
26+
27+
EXPOSE 4200
28+
29+
CMD ["sh", "-lc", "pnpm --filter @involute/server exec prisma db push --skip-generate && if [ \"${SEED_DATABASE:-false}\" = \"true\" ]; then pnpm --filter @involute/server exec prisma db seed; fi && node packages/server/dist/index.js"]
30+
31+
FROM base AS web
32+
33+
EXPOSE 4201
34+
35+
CMD ["pnpm", "--filter", "@involute/web", "exec", "vite", "--host", "0.0.0.0", "--port", "4201"]
36+
37+
FROM base AS cli
38+
39+
RUN pnpm --filter @involute/server build && pnpm --filter @involute/cli build
40+
41+
ENTRYPOINT ["node", "packages/cli/dist/index.js"]
42+
CMD ["--help"]

README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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

Comments
 (0)