Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Local development values. For a production server deployment (Linux/nginx
# over an SSH tunnel), see docs/deploy-linux-prod.md for the prod .env shape.
NODE_ENV=development
APP_ORIGIN=http://127.0.0.1:6173,http://localhost:6173
API_BASE_URL=http://127.0.0.1:4000
Expand Down
8 changes: 7 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ timefraim/
├── apps/
│ ├── server/ # Fastify API + MCP endpoint
│ └── web/ # Vite + React SPA
├── docs/
│ └── deploy-linux-prod.md # Production deploy runbook (Linux/nginx via SSH tunnel)
├── packages/
│ └── shared/ # Zod schemas shared by apps
├── skills/
Expand Down Expand Up @@ -66,7 +68,8 @@ timefraim/
### 4.2 apps/server (backend, port 4000)

- **Entry:** `src/index.ts` — registers HTTP routes, mounts `POST /mcp`, constructs `PlannerService`.
- **Config:** `src/config/env.ts` (Zod-validated env).
- **Config:** `src/config/env.ts` (Zod-validated env; locates the repo-root `.env` by walking up to `pnpm-workspace.yaml`).
- **Production build:** `tsup.config.ts` bundles `@timefraim/shared` into `dist/index.js` (the shared package resolves to TS source and is not runtime-loadable); run the build with `pnpm start:server`. Deploy runbook: `docs/deploy-linux-prod.md`.
- **HTTP routes:** `src/http/` — `routes.ts` + modular `register-*-routes.ts` (planner, integration, preferences, auth, timer, draft). `auth.ts` verifies Supabase JWT. `route-helpers.ts` holds shared middleware.
- **Repositories (data access):** `src/repositories/` — `planner-repository.ts` composes per-domain stores (`planner-repository-task-store.ts`, `-schedule-store.ts`, `-calendar-store.ts`, `-timer-store.ts`, `-integration-store.ts`, `-preferences-store.ts`, `-draft-store.ts`). Row → domain mapping in `planner-repository-mappers.ts`; row types in `planner-repository-types.ts`.
- **Services (business logic):** `src/services/` — `planner-service.ts` orchestrates; `planner-service-google-integrations.ts`, `planner-service-toggl-integrations.ts` handle external calls; `planner-service-preferences.ts` reads/writes user preferences; `planner-domain.ts` applies drafts; `planner-*-changes.ts` compute diffs; `planner-service-apply.ts` confirms drafts; `planner-side-effects.ts` handles audit logs + external syncs.
Expand Down Expand Up @@ -132,6 +135,7 @@ pnpm dev # web + server in parallel
pnpm dev:linked # web + server in parallel against LINKED_SUPABASE_* values
pnpm dev:web # web only (6173)
pnpm dev:server # server only (4000)
pnpm start:server # run the built API (apps/server/dist) — production
pnpm lint # ESLint across shared/server/web
pnpm typecheck # tsc --noEmit across all packages
pnpm test # Vitest across all packages
Expand Down Expand Up @@ -257,6 +261,8 @@ Canonical list lives in [.env.example](.env.example). Highlights:
| [apps/server/src/integration/toggl-track.ts](apps/server/src/integration/toggl-track.ts) | Toggl client |
| [apps/server/src/mcp/create-mcp-server.ts](apps/server/src/mcp/create-mcp-server.ts) | MCP tools exposed to agents |
| [packages/shared/src/index.ts](packages/shared/src/index.ts) | Shared schema barrel |
| [docs/deploy-linux-prod.md](docs/deploy-linux-prod.md) | Production deploy runbook (Linux/nginx, SSH tunnel) |
| [apps/server/tsup.config.ts](apps/server/tsup.config.ts) | Server build config (bundles `@timefraim/shared`) |
| [skills/coding-standards/SKILL.md](skills/coding-standards/SKILL.md) | Production coding standards for Node, React, and TypeScript work |
| [skills/sync-agent-briefs/SKILL.md](skills/sync-agent-briefs/SKILL.md) | Repo-local workflow for syncing agent orientation files |
| [supabase/migrations/](supabase/migrations/) | Schema evolution |
Expand Down
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ timefraim/
├── apps/
│ ├── server/ # Fastify API + MCP endpoint
│ └── web/ # Vite + React SPA
├── docs/
│ └── deploy-linux-prod.md # Production deploy runbook (Linux/nginx via SSH tunnel)
├── packages/
│ └── shared/ # Zod schemas shared by apps
├── skills/
Expand Down Expand Up @@ -66,7 +68,8 @@ timefraim/
### 4.2 apps/server (backend, port 4000)

- **Entry:** `src/index.ts` — registers HTTP routes, mounts `POST /mcp`, constructs `PlannerService`.
- **Config:** `src/config/env.ts` (Zod-validated env).
- **Config:** `src/config/env.ts` (Zod-validated env; locates the repo-root `.env` by walking up to `pnpm-workspace.yaml`).
- **Production build:** `tsup.config.ts` bundles `@timefraim/shared` into `dist/index.js` (the shared package resolves to TS source and is not runtime-loadable); run the build with `pnpm start:server`. Deploy runbook: `docs/deploy-linux-prod.md`.
- **HTTP routes:** `src/http/` — `routes.ts` + modular `register-*-routes.ts` (planner, integration, preferences, auth, timer, draft). `auth.ts` verifies Supabase JWT. `route-helpers.ts` holds shared middleware.
- **Repositories (data access):** `src/repositories/` — `planner-repository.ts` composes per-domain stores (`planner-repository-task-store.ts`, `-schedule-store.ts`, `-calendar-store.ts`, `-timer-store.ts`, `-integration-store.ts`, `-preferences-store.ts`, `-draft-store.ts`). Row → domain mapping in `planner-repository-mappers.ts`; row types in `planner-repository-types.ts`.
- **Services (business logic):** `src/services/` — `planner-service.ts` orchestrates; `planner-service-google-integrations.ts`, `planner-service-toggl-integrations.ts` handle external calls; `planner-service-preferences.ts` reads/writes user preferences; `planner-domain.ts` applies drafts; `planner-*-changes.ts` compute diffs; `planner-service-apply.ts` confirms drafts; `planner-side-effects.ts` handles audit logs + external syncs.
Expand Down Expand Up @@ -132,6 +135,7 @@ pnpm dev # web + server in parallel
pnpm dev:linked # web + server in parallel against LINKED_SUPABASE_* values
pnpm dev:web # web only (6173)
pnpm dev:server # server only (4000)
pnpm start:server # run the built API (apps/server/dist) — production
pnpm lint # ESLint across shared/server/web
pnpm typecheck # tsc --noEmit across all packages
pnpm test # Vitest across all packages
Expand Down Expand Up @@ -257,6 +261,8 @@ Canonical list lives in [.env.example](.env.example). Highlights:
| [apps/server/src/integration/toggl-track.ts](apps/server/src/integration/toggl-track.ts) | Toggl client |
| [apps/server/src/mcp/create-mcp-server.ts](apps/server/src/mcp/create-mcp-server.ts) | MCP tools exposed to agents |
| [packages/shared/src/index.ts](packages/shared/src/index.ts) | Shared schema barrel |
| [docs/deploy-linux-prod.md](docs/deploy-linux-prod.md) | Production deploy runbook (Linux/nginx, SSH tunnel) |
| [apps/server/tsup.config.ts](apps/server/tsup.config.ts) | Server build config (bundles `@timefraim/shared`) |
| [skills/coding-standards/SKILL.md](skills/coding-standards/SKILL.md) | Production coding standards for Node, React, and TypeScript work |
| [skills/sync-agent-briefs/SKILL.md](skills/sync-agent-briefs/SKILL.md) | Repo-local workflow for syncing agent orientation files |
| [supabase/migrations/](supabase/migrations/) | Schema evolution |
Expand Down
8 changes: 7 additions & 1 deletion GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ timefraim/
├── apps/
│ ├── server/ # Fastify API + MCP endpoint
│ └── web/ # Vite + React SPA
├── docs/
│ └── deploy-linux-prod.md # Production deploy runbook (Linux/nginx via SSH tunnel)
├── packages/
│ └── shared/ # Zod schemas shared by apps
├── skills/
Expand Down Expand Up @@ -66,7 +68,8 @@ timefraim/
### 4.2 apps/server (backend, port 4000)

- **Entry:** `src/index.ts` — registers HTTP routes, mounts `POST /mcp`, constructs `PlannerService`.
- **Config:** `src/config/env.ts` (Zod-validated env).
- **Config:** `src/config/env.ts` (Zod-validated env; locates the repo-root `.env` by walking up to `pnpm-workspace.yaml`).
- **Production build:** `tsup.config.ts` bundles `@timefraim/shared` into `dist/index.js` (the shared package resolves to TS source and is not runtime-loadable); run the build with `pnpm start:server`. Deploy runbook: `docs/deploy-linux-prod.md`.
- **HTTP routes:** `src/http/` — `routes.ts` + modular `register-*-routes.ts` (planner, integration, preferences, auth, timer, draft). `auth.ts` verifies Supabase JWT. `route-helpers.ts` holds shared middleware.
- **Repositories (data access):** `src/repositories/` — `planner-repository.ts` composes per-domain stores (`planner-repository-task-store.ts`, `-schedule-store.ts`, `-calendar-store.ts`, `-timer-store.ts`, `-integration-store.ts`, `-preferences-store.ts`, `-draft-store.ts`). Row → domain mapping in `planner-repository-mappers.ts`; row types in `planner-repository-types.ts`.
- **Services (business logic):** `src/services/` — `planner-service.ts` orchestrates; `planner-service-google-integrations.ts`, `planner-service-toggl-integrations.ts` handle external calls; `planner-service-preferences.ts` reads/writes user preferences; `planner-domain.ts` applies drafts; `planner-*-changes.ts` compute diffs; `planner-service-apply.ts` confirms drafts; `planner-side-effects.ts` handles audit logs + external syncs.
Expand Down Expand Up @@ -132,6 +135,7 @@ pnpm dev # web + server in parallel
pnpm dev:linked # web + server in parallel against LINKED_SUPABASE_* values
pnpm dev:web # web only (6173)
pnpm dev:server # server only (4000)
pnpm start:server # run the built API (apps/server/dist) — production
pnpm lint # ESLint across shared/server/web
pnpm typecheck # tsc --noEmit across all packages
pnpm test # Vitest across all packages
Expand Down Expand Up @@ -257,6 +261,8 @@ Canonical list lives in [.env.example](.env.example). Highlights:
| [apps/server/src/integration/toggl-track.ts](apps/server/src/integration/toggl-track.ts) | Toggl client |
| [apps/server/src/mcp/create-mcp-server.ts](apps/server/src/mcp/create-mcp-server.ts) | MCP tools exposed to agents |
| [packages/shared/src/index.ts](packages/shared/src/index.ts) | Shared schema barrel |
| [docs/deploy-linux-prod.md](docs/deploy-linux-prod.md) | Production deploy runbook (Linux/nginx, SSH tunnel) |
| [apps/server/tsup.config.ts](apps/server/tsup.config.ts) | Server build config (bundles `@timefraim/shared`) |
| [skills/coding-standards/SKILL.md](skills/coding-standards/SKILL.md) | Production coding standards for Node, React, and TypeScript work |
| [skills/sync-agent-briefs/SKILL.md](skills/sync-agent-briefs/SKILL.md) | Repo-local workflow for syncing agent orientation files |
| [supabase/migrations/](supabase/migrations/) | Schema evolution |
Expand Down
5 changes: 3 additions & 2 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"lint": "eslint src",
"build": "tsup src/index.ts --format esm --dts --clean",
"lint": "eslint src tsup.config.ts",
"build": "tsup",
"start": "node dist/index.js",
"test": "vitest run",
"typecheck": "tsc --noEmit"
},
Expand Down
17 changes: 16 additions & 1 deletion apps/server/src/config/env.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
import dotenv from "dotenv";
import { existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";

// The bundled output lives at a different depth than src/config, so locate
// the repo root by marker file instead of a fixed number of parent hops.
function findRepoRoot(startDir: string): string {
let dir = startDir;
while (!existsSync(resolve(dir, "pnpm-workspace.yaml"))) {
const parent = dirname(dir);
if (parent === dir) {
return startDir;
}
dir = parent;
}
return dir;
}

const currentDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(currentDir, "../../../../");
const repoRoot = findRepoRoot(currentDir);

const envCandidates = [
resolve(process.cwd(), ".env"),
Expand Down
5 changes: 2 additions & 3 deletions apps/server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["node", "vitest/globals"],
"rootDir": "src"
"types": ["node", "vitest/globals"]
},
"include": ["src"]
"include": ["src", "tsup.config.ts"]
}
10 changes: 10 additions & 0 deletions apps/server/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
clean: true,
// @timefraim/shared resolves to TypeScript source (no runtime build),
// so it must be bundled for `node dist/index.js` to work.
noExternal: ["@timefraim/shared"],
});
Loading