Skip to content

Commit 9cdcf6d

Browse files
committed
using single package.json, fixing ntfy issue
1 parent b26f30b commit 9cdcf6d

11 files changed

Lines changed: 2290 additions & 2883 deletions

File tree

CLAUDE.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Commands
6+
7+
```bash
8+
yarn dev # Start both server (port 3001) and Vite dev server (port 5173) concurrently
9+
yarn dev:server # Server only: node --watch server/src/index.js
10+
yarn dev:client # Client only: Vite dev server with /api proxy to port 3001
11+
12+
yarn test # All tests (server then client)
13+
yarn test:server # Server tests via vitest.config.js
14+
yarn test:client # Client tests via vite.config.js
15+
16+
yarn build # Vite build → client/dist/
17+
yarn start # yarn build + node server/src/index.js
18+
19+
yarn lint # ESLint across entire repo
20+
yarn lint:fix
21+
yarn format # Prettier
22+
```
23+
24+
**Run a single test file:**
25+
```bash
26+
yarn test:server --reporter=verbose server/tests/jobs.test.js
27+
yarn test:client --reporter=verbose client/tests/JobForm.test.jsx
28+
```
29+
30+
## Architecture
31+
32+
### Server (`server/src/`)
33+
34+
Express app wired together in `index.js``app.js`. The server serves the built React client from `client/dist/` in production; in dev, the Vite proxy handles `/api` routing.
35+
36+
**Request flow:** `gatewayTokenMiddleware` → route handlers → `executor` / DB
37+
38+
- **`db/`** – Single module-level `db` singleton (`getDb()` / `initDb()`). SQLite in WAL mode with foreign keys. Schema and migrations are in `migrations.js` — all tables are created with `IF NOT EXISTS`.
39+
- **`scheduler/index.js`**`node-cron` tasks re-fetch the job from the DB on each tick (so config changes take effect immediately without rescheduling). Jobs are stored raw (integers for booleans) at this layer.
40+
- **`scheduler/executor.js`** – Spawns child processes, caps output at 512 KB, enforces `EXEC_TIMEOUT_MS` (default 30 min). After completion, calls `ntfySend` and emits SSE events via `eventBus`.
41+
- **`routes/jobs.js`**`formatJob()` converts raw SQLite rows (integers) to typed JS objects (booleans) before sending to the client. All boolean DB columns are `0`/`1` integers — only `formatJob()` and the route write handlers deal with the conversion.
42+
- **`services/eventBus.js`** – In-process EventEmitter. The SSE endpoint in `app.js` subscribes to `run:started` and `run:finished` events.
43+
- **`services/ntfy.js`** – Fire-and-forget HTTP POST to the configured ntfy server. Errors are logged but never re-thrown.
44+
- **`services/cronUtils.js`** – Uses `cron-parser` v5 (`CronExpressionParser.parse()`, not the old `parseExpression()`) and `cronstrue` for human-readable descriptions.
45+
- **`env.js`** – Loads `.env` via dotenv (skipped in `NODE_ENV=test`). Exports `PROJECT_ROOT` (two directories up from `server/src/`). The version shown in the UI is read from root `package.json` by `app.js` at startup.
46+
47+
### Client (`client/src/`)
48+
49+
Single-page React app. State lives in hooks; components are presentational.
50+
51+
- **`api/client.js`** – Thin fetch wrapper; sends `X-Gateway-Token` header on every request (reads from URL `?token=`). Throws typed errors with `.fields` for validation responses.
52+
- **`hooks/useJobs.js`** – Owns the jobs list state and all CRUD operations.
53+
- **`hooks/useRunHistory.js`** – Paginated run history for a selected job.
54+
- **`hooks/useJobEvents.js`** – SSE subscription (`/api/events`). Delivers `run:started` / `run:finished` to `App.jsx` which fans them out to `useJobs` and `useRunHistory`.
55+
- **`hooks/useCronValidation.js`** – Debounced cron expression validation against `/api/jobs/validate`.
56+
- **`components/`** – Organized by domain: `jobs/`, `runs/`, `cron/`, `ui/`, `layout/`, `auth/`.
57+
58+
### Build / Config
59+
60+
Single `package.json` at root. `vite.config.js` (root) sets `root: 'client'` so Vite treats `client/` as the project root; build output goes to `client/dist/`. `vitest.config.js` (root) scopes server tests to `server/tests/**`.
61+
62+
Client tests run in **happy-dom** (not jsdom). Server tests run in the node environment; `server/tests/setup.js` exposes `makeDb()`, `makeApp()`, and `makeScheduler()` helpers.
63+
64+
### ntfy Notification Logic
65+
66+
`ntfy_on_run` fires on **every** execution (success and error). `ntfy_on_error` fires only on failures, even when `ntfy_on_run` is off. Condition in `executor.js`:
67+
```js
68+
if (job.ntfy_enabled && ((isError && job.ntfy_on_error) || job.ntfy_on_run))
69+
```
70+
71+
### Security
72+
73+
`GATEWAY_TOKEN` in `.env` enables the gateway. The token is passed as `?token=` in the URL for browser access (SSE cannot set custom headers). The middleware uses `timingSafeEqual` to prevent timing attacks.
74+
75+
### Coding
76+
- You must not commit anything or create new branches unless I told you so
77+
- Use ESM
78+
- Document everything you add with proper JSDoc

Dockerfile

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
88
python3 make g++ \
99
&& rm -rf /var/lib/apt/lists/*
1010

11-
# Copy lockfiles and manifests first for layer caching
12-
COPY server/package.json server/yarn.lock ./server/
13-
COPY client/package.json client/yarn.lock ./client/
14-
15-
RUN yarn --cwd server install --frozen-lockfile \
16-
&& yarn --cwd client install --frozen-lockfile
11+
# Copy manifest first for layer caching
12+
COPY package.json yarn.lock ./
13+
RUN yarn install --frozen-lockfile
1714

1815
# Copy source
1916
COPY server/src ./server/src
2017
COPY client/src ./client/src
21-
COPY client/index.html client/vite.config.js ./client/
18+
COPY client/index.html ./client/
19+
COPY vite.config.js ./
20+
21+
RUN yarn build
22+
23+
# ---- Production deps stage ----
24+
FROM node:22-slim AS deps
25+
26+
WORKDIR /app
27+
28+
# Build tools required to compile better-sqlite3 native bindings
29+
RUN apt-get update && apt-get install -y --no-install-recommends \
30+
python3 make g++ \
31+
&& rm -rf /var/lib/apt/lists/*
2232

23-
RUN yarn --cwd client build
33+
COPY package.json yarn.lock ./
34+
RUN yarn install --frozen-lockfile --production
2435

2536
# ---- Production stage ----
2637
FROM node:22-slim
@@ -31,11 +42,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
3142
curl \
3243
&& rm -rf /var/lib/apt/lists/*
3344

34-
# Copy compiled server dependencies (includes native better-sqlite3 binary)
35-
COPY --from=builder /app/server/node_modules ./server/node_modules
45+
COPY --from=deps /app/node_modules ./node_modules
3646
COPY --from=builder /app/client/dist ./client/dist
3747
COPY server/src ./server/src
38-
COPY server/package.json ./server/
3948
COPY package.json ./
4049

4150
RUN mkdir -p /data

client/package.json

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)