@programinglive/dev-workflow-mcp-server 1.7.13 โ†’ 1.7.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,76 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.7.16](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.15...v1.7.16) (2025-12-24)
6
+
7
+
8
+ ### ๐Ÿ› Bug Fixes
9
+
10
+ * align database schema with dashboard and improve user ID handling ([69e7f38](https://github.com/programinglive/dev-workflow-mcp-server/commit/69e7f381955d15bb727a6e309082a344729d1c1e))
11
+
12
+
13
+ ### ๐Ÿงน Chores
14
+
15
+ * cleanup temporary debugging scripts ([a5e2b15](https://github.com/programinglive/dev-workflow-mcp-server/commit/a5e2b15b894632efadce46d83caf4d008e50fdd3))
16
+ * sync version to 1.7.15 across web and landing pages ([c520e4a](https://github.com/programinglive/dev-workflow-mcp-server/commit/c520e4a5d795c880fb74f31142b128a9c55beb6f))
17
+
18
+
19
+ ### ๐Ÿ“ Documentation
20
+
21
+ * update macOS MCP config instructions ([1e368da](https://github.com/programinglive/dev-workflow-mcp-server/commit/1e368da37bede45e0282b1312002f2fedeb6ad60))
22
+
23
+ ### [1.7.15](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.14...v1.7.15) (2025-12-19)
24
+
25
+
26
+ ### ๐Ÿ› Bug Fixes
27
+
28
+ * optimize startup performance and add database connection resilience ([bff2714](https://github.com/programinglive/dev-workflow-mcp-server/commit/bff27146fe9537788741e4a084191bce93588569))
29
+ * refactor Navbar and History to use absolute API client URLs v1.7.18 ([dc33eae](https://github.com/programinglive/dev-workflow-mcp-server/commit/dc33eae612067c5246ca69d08960090c0a0ad6bd))
30
+ * sync all version labels to 1.7.14 and improve netlify routing ([78712eb](https://github.com/programinglive/dev-workflow-mcp-server/commit/78712eb398458605f77b2ba78c9ff61a0be1d335))
31
+ * sync all version strings to 1.7.14 ([e2a1795](https://github.com/programinglive/dev-workflow-mcp-server/commit/e2a1795a7b794c8874b1e610de3370cd6ed5fa7a))
32
+ * sync version to 1.7.14 and fix static routing via trailingSlash ([1c152bd](https://github.com/programinglive/dev-workflow-mcp-server/commit/1c152bd23bbfd30a73e0a89107f4ea18564d20d0))
33
+
34
+ ### [1.7.14](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.13...v1.7.14) (2025-12-19)
35
+
36
+
37
+ ### โœจ Features
38
+
39
+ * add API dependencies and update login to use API client ([94bb42f](https://github.com/programinglive/dev-workflow-mcp-server/commit/94bb42f27b4bd225bb3813b81d5f2bff973edb16))
40
+ * add REST API server for frontend database access ([cdb347c](https://github.com/programinglive/dev-workflow-mcp-server/commit/cdb347cf204ce423b94db7e72980783e986a124d))
41
+ * implement JWT authentication and update client ([8efbe80](https://github.com/programinglive/dev-workflow-mcp-server/commit/8efbe80c3a69046f716b247fc359158dc8fec3e2))
42
+
43
+
44
+ ### โ™ป๏ธ Refactors
45
+
46
+ * remove session cookies, enforce JWT only ([bacd83a](https://github.com/programinglive/dev-workflow-mcp-server/commit/bacd83a16510499667143f4906d0cc8de0127d61))
47
+
48
+
49
+ ### ๐Ÿ› Bug Fixes
50
+
51
+ * add credentials:include to getCurrentUser to persist session ([b8f2df5](https://github.com/programinglive/dev-workflow-mcp-server/commit/b8f2df531a2d2bae78ad3c3ea2c7dcda62e5e835))
52
+ * add root netlify.toml for monorepo support ([54c5ed3](https://github.com/programinglive/dev-workflow-mcp-server/commit/54c5ed3960aafd5a814773efa487efe9197d4385))
53
+ * enable trust proxy and force secure cookies for cross-domain session ([2c5d6e8](https://github.com/programinglive/dev-workflow-mcp-server/commit/2c5d6e858d05de06304d88286b931b1f12a95bf1))
54
+ * ensure getMe uses full API URL ([b3bd0da](https://github.com/programinglive/dev-workflow-mcp-server/commit/b3bd0da097de57b42d9253615f791677011486af))
55
+ * force API URL to tunnel address to resolve cached old IP ([1883731](https://github.com/programinglive/dev-workflow-mcp-server/commit/18837313a7b96395f1cf04b56d7fe1a74e13b1ed))
56
+ * inline auth functions in API server ([eefd73c](https://github.com/programinglive/dev-workflow-mcp-server/commit/eefd73c82dcf47d419662eaeb8854f6047e6464a))
57
+ * remove duplicate variable declarations in API server ([31d3621](https://github.com/programinglive/dev-workflow-mcp-server/commit/31d3621213ddb3560ee0570fdf6411d9acf7018f))
58
+ * remove dynamic API route for static export ([05a4dd0](https://github.com/programinglive/dev-workflow-mcp-server/commit/05a4dd0e4901e5ac329e50ebe392839d1242de4e))
59
+ * remove explicit publish path to fix netlify build ([cd64bcf](https://github.com/programinglive/dev-workflow-mcp-server/commit/cd64bcf0b4effb71be090235357d665d1f26b567))
60
+ * remove incorrect netlify publish dir for dynamic build ([ea34cf4](https://github.com/programinglive/dev-workflow-mcp-server/commit/ea34cf464466b4ddc8eaa6432434d1fbabb3583e))
61
+ * remove incorrect publish dir from netlify config ([010236f](https://github.com/programinglive/dev-workflow-mcp-server/commit/010236fd0eb1419f7cae4429159f4aac1a988174))
62
+ * restore static export for netlify deployment ([685d841](https://github.com/programinglive/dev-workflow-mcp-server/commit/685d84178b239b5cd681b4d479456e69519a8af8))
63
+ * update API URL to use Cloudflare Tunnel for HTTPS ([ab72f6c](https://github.com/programinglive/dev-workflow-mcp-server/commit/ab72f6c0b8acc6974aba7c8df8418e35da6f2a51))
64
+ * use apiClient in history page and add version indicator ([4889669](https://github.com/programinglive/dev-workflow-mcp-server/commit/48896694166cd5d42ab4134d4dbfdb0df8ca0d44))
65
+ * use npm install instead of ci to avoid lockfile issues ([e5fae26](https://github.com/programinglive/dev-workflow-mcp-server/commit/e5fae26f767c5f0e4aba2593df321c700ac14a38))
66
+
67
+
68
+ ### ๐Ÿงน Chores
69
+
70
+ * bump version to 1.7.14 to ensure fresh build ([f7d8886](https://github.com/programinglive/dev-workflow-mcp-server/commit/f7d88861ceb111c57e3b34bf4b5a5cc25a19805b))
71
+ * bump version to 1.7.15 for JWT frontend deploy ([7850268](https://github.com/programinglive/dev-workflow-mcp-server/commit/7850268d019251619d60a0a841db2bab8061be04))
72
+ * cleanup post-release and update website version to 1.7.13 ([7341d44](https://github.com/programinglive/dev-workflow-mcp-server/commit/7341d446bbddcb9232e70606acaf950fde7ff5c2))
73
+ * save pending changes before release ([4d4b1c9](https://github.com/programinglive/dev-workflow-mcp-server/commit/4d4b1c9e6122baed3cc6782a572fe3700dabf19b))
74
+
5
75
  ### [1.7.13](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.12...v1.7.13) (2025-12-18)
6
76
 
7
77
 
package/README.md CHANGED
@@ -8,6 +8,11 @@
8
8
 
9
9
  An MCP (Model Context Protocol) server that helps enforce development discipline and workflow best practices. This server acts as your coding conscience, reminding you to follow proper development workflows.
10
10
 
11
+ ### ๐Ÿ›ก๏ธ Resilience Features
12
+ - **Startup Resilience**: 5-second connection timeouts for external databases.
13
+ - **Background Loading**: Non-critical assets (compatibility mirrors) initialize in the background to ensure sub-second startup.
14
+ - **Diagnostic Mode**: Automatic startup timing logs displayed in stderr.
15
+
11
16
  ## ๐ŸŽฏ Purpose
12
17
 
13
18
  This MCP server guides you through a disciplined development workflow:
@@ -100,7 +105,12 @@ Point your MCP client to the server entry point. Replace `<PROJECT_ROOT>` with t
100
105
  "mcpServers": {
101
106
  "dev-workflow": {
102
107
  "command": "node",
103
- "args": ["<PROJECT_ROOT>/index.js"]
108
+ "cwd": "<PROJECT_ROOT>",
109
+ "args": ["index.js"],
110
+ "env": {
111
+ "DEV_WORKFLOW_DB_TYPE": "postgres",
112
+ "DEV_WORKFLOW_DB_URL": "postgres://USER:PASS@HOST:5432/devworkflow"
113
+ }
104
114
  }
105
115
  }
106
116
  }
@@ -177,6 +187,28 @@ Point your MCP client to the server entry point. Replace `<PROJECT_ROOT>` with t
177
187
 
178
188
  > **Note:** On Windows paths in JSON require escaped backslashes (e.g., `"C:\\path\\to\\project"`).
179
189
 
190
+ #### Full Windsurf MCP Config Example (macOS)
191
+
192
+ If you keep this repository checked out at `/Users/alex/code/dev-workflow-mcp-server` and want to point Windsurf at a hosted PostgreSQL instance, drop the following into `~/Library/Application Support/Windsurf/mcp_config.json`:
193
+
194
+ ```json
195
+ {
196
+ "mcpServers": {
197
+ "dev-workflow": {
198
+ "command": "node",
199
+ "cwd": "/Users/alex/code/dev-workflow-mcp-server",
200
+ "args": ["index.js"],
201
+ "env": {
202
+ "DEV_WORKFLOW_DB_TYPE": "postgres",
203
+ "DEV_WORKFLOW_DB_URL": "postgres://devworkflow:devworkflow_secure_password@34.50.121.142:5432/devworkflow"
204
+ }
205
+ }
206
+ }
207
+ }
208
+ ```
209
+
210
+ This mirrors the Windows configuration shared in previous releases, but avoids `npx` lookup issues on macOS by launching the local `index.js` directly.
211
+
180
212
  ### 4. Restart Windsurf/Claude Desktop
181
213
 
182
214
  After adding the configuration, restart the application to load the MCP server.
@@ -201,6 +233,29 @@ Antigravity users should configure the MCP server in their `mcp_config.json`.
201
233
 
202
234
  See [Antigravity Getting Started](./docs/antigravity/GETTING-STARTED.md) for detailed instructions and troubleshooting.
203
235
 
236
+ ### โšก Performance Optimization (Recommended)
237
+
238
+ To ensure the fastest possible startup (critical for IDE-integrated clients like Claude Desktop), we recommend pointing directly to `index.js` using `node` rather than `npx`. This avoids the overhead of checking for package updates.
239
+
240
+ **Optimized Configuration:**
241
+
242
+ ```json
243
+ {
244
+ "mcpServers": {
245
+ "dev-workflow": {
246
+ "command": "node",
247
+ "args": ["<PROJECT_ROOT>\\index.js"],
248
+ "env": {
249
+ "DEV_WORKFLOW_USER_ID": "your_user_id"
250
+ }
251
+ }
252
+ }
253
+ }
254
+ ```
255
+
256
+ The server automatically times its own startup and logs it to stderr:
257
+ `Dev Workflow MCP Server running on stdio (startup took 15ms)`
258
+
204
259
  ## โš™๏ธ Configuration
205
260
 
206
261
  ### Database Setup
@@ -241,6 +296,19 @@ export DEV_WORKFLOW_DB_TYPE=postgres
241
296
  export DEV_WORKFLOW_DB_URL="postgresql://user:password@localhost:5432/dev_workflow"
242
297
  ```
243
298
 
299
+ #### ๐Ÿ› ๏ธ Database Schema Normalization (Postgres/MySQL)
300
+ To ensure compatibility with existing reporting dashboards, the `PostgresAdapter` and `MysqlAdapter` automatically normalize column names:
301
+ - `task_description` โ†’ DB column: `description`
302
+ - `timestamp` โ†’ DB column: `completed_at`
303
+
304
+ The adapters use aliases in queries so the MCP tools still receive the expected `task_description` and `timestamp` fields.
305
+
306
+ #### ๐Ÿ‘ค User ID Handling (Postgres/MySQL)
307
+ These databases use an `INTEGER` column for `user_id`.
308
+ - **Numeric strings** (e.g., `"1"`) are parsed directly into integers.
309
+ - **Non-numeric strings** (e.g., `"programinglive"`) are automatically hashed into a consistent, positive integer to ensure compatibility with the schema while maintaining unique user isolation.
310
+
311
+
244
312
  ### User & State Management
245
313
 
246
314
  | Variable | Description |
@@ -0,0 +1,3 @@
1
+ url: http://localhost:8080
2
+ tunnel: api-devworkflow
3
+ credentials-file: /home/dhika/.cloudflared/credentials.json
@@ -15,11 +15,25 @@ export class PostgresAdapter extends DbAdapter {
15
15
  this.pool = null;
16
16
  }
17
17
 
18
+ getNumericUserId(userId) {
19
+ let numericUserId = parseInt(userId, 10);
20
+ if (isNaN(numericUserId)) {
21
+ let hash = 0;
22
+ for (let i = 0; i < userId.length; i++) {
23
+ hash = (hash << 5) - hash + userId.charCodeAt(i);
24
+ hash |= 0;
25
+ }
26
+ numericUserId = Math.abs(hash);
27
+ }
28
+ return numericUserId;
29
+ }
30
+
18
31
  async connect() {
19
32
  if (!this.pool) {
20
33
  this.pool = new Pool({
21
34
  connectionString: this.config.connectionUrl,
22
- // pg pool handles connections automatically
35
+ connectionTimeoutMillis: 5000, // 5 second timeout for new connections
36
+ idleTimeoutMillis: 10000, // close idle connections after 10 seconds
23
37
  });
24
38
  await this.migrate();
25
39
  }
@@ -31,23 +45,55 @@ export class PostgresAdapter extends DbAdapter {
31
45
  await client.query(`
32
46
  CREATE TABLE IF NOT EXISTS workflow_history (
33
47
  id SERIAL PRIMARY KEY,
34
- user_id TEXT NOT NULL,
48
+ user_id INTEGER NOT NULL,
35
49
  project_path TEXT DEFAULT '',
36
- task_description TEXT NOT NULL,
50
+ description TEXT NOT NULL,
37
51
  task_type TEXT NOT NULL,
38
52
  commit_message TEXT,
39
- timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
53
+ completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
40
54
  forced BOOLEAN DEFAULT FALSE,
41
55
  force_reason TEXT,
42
56
  dropped BOOLEAN DEFAULT FALSE,
43
57
  drop_reason TEXT,
44
- UNIQUE (user_id, project_path, timestamp, task_description)
58
+ UNIQUE (user_id, project_path, completed_at, description)
45
59
  )
46
60
  `);
47
61
 
62
+ // Migration: Add columns to existing table if they don't exist
63
+ const columns = await client.query(`
64
+ SELECT column_name FROM information_schema.columns WHERE table_name = 'workflow_history'
65
+ `);
66
+ const existingColumns = columns.rows.map(r => r.column_name);
67
+
68
+ if (!existingColumns.includes('project_path')) {
69
+ await client.query('ALTER TABLE workflow_history ADD COLUMN project_path TEXT DEFAULT \'\'');
70
+ }
71
+ if (!existingColumns.includes('forced')) {
72
+ await client.query('ALTER TABLE workflow_history ADD COLUMN forced BOOLEAN DEFAULT FALSE');
73
+ }
74
+ if (!existingColumns.includes('force_reason')) {
75
+ await client.query('ALTER TABLE workflow_history ADD COLUMN force_reason TEXT');
76
+ }
77
+ if (!existingColumns.includes('dropped')) {
78
+ await client.query('ALTER TABLE workflow_history ADD COLUMN dropped BOOLEAN DEFAULT FALSE');
79
+ }
80
+ if (!existingColumns.includes('drop_reason')) {
81
+ await client.query('ALTER TABLE workflow_history ADD COLUMN drop_reason TEXT');
82
+ }
83
+ // Ensure completed_at vs timestamp handled if table exists
84
+ if (!existingColumns.includes('completed_at') && existingColumns.includes('timestamp')) {
85
+ await client.query('ALTER TABLE workflow_history RENAME COLUMN timestamp TO completed_at');
86
+ } else if (existingColumns.includes('completed_at') && !existingColumns.includes('timestamp')) {
87
+ // Keep completed_at
88
+ }
89
+ // Logic for description vs task_description
90
+ if (!existingColumns.includes('description') && existingColumns.includes('task_description')) {
91
+ await client.query('ALTER TABLE workflow_history RENAME COLUMN task_description TO description');
92
+ }
93
+
48
94
  await client.query(`
49
95
  CREATE TABLE IF NOT EXISTS project_summary (
50
- user_id TEXT,
96
+ user_id INTEGER,
51
97
  project_path TEXT DEFAULT '',
52
98
  total_tasks INTEGER DEFAULT 0,
53
99
  task_types JSONB,
@@ -60,7 +106,7 @@ export class PostgresAdapter extends DbAdapter {
60
106
 
61
107
  await client.query(`
62
108
  CREATE TABLE IF NOT EXISTS workflow_state (
63
- user_id TEXT,
109
+ user_id INTEGER,
64
110
  project_path TEXT DEFAULT '',
65
111
  state_json JSONB,
66
112
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -75,12 +121,13 @@ export class PostgresAdapter extends DbAdapter {
75
121
  async insertHistoryEntry(userId, projectPath, entry) {
76
122
  await this.connect();
77
123
  const normalizedProjectPath = projectPath || '';
124
+ const numericUserId = this.getNumericUserId(userId);
78
125
 
79
126
  const query = `
80
127
  INSERT INTO workflow_history
81
- (user_id, project_path, task_description, task_type, commit_message, timestamp, forced, force_reason, dropped, drop_reason)
128
+ (user_id, project_path, description, task_type, commit_message, completed_at, forced, force_reason, dropped, drop_reason)
82
129
  VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
83
- ON CONFLICT (user_id, project_path, timestamp, task_description) DO UPDATE SET
130
+ ON CONFLICT (user_id, project_path, completed_at, description) DO UPDATE SET
84
131
  commit_message=EXCLUDED.commit_message,
85
132
  forced=EXCLUDED.forced,
86
133
  force_reason=EXCLUDED.force_reason,
@@ -89,12 +136,12 @@ export class PostgresAdapter extends DbAdapter {
89
136
  `;
90
137
 
91
138
  await this.pool.query(query, [
92
- userId,
139
+ numericUserId,
93
140
  normalizedProjectPath,
94
- entry.taskDescription,
141
+ entry.taskDescription || entry.description,
95
142
  entry.taskType,
96
143
  entry.commitMessage,
97
- entry.timestamp || new Date().toISOString(),
144
+ entry.timestamp || entry.completed_at || new Date().toISOString(),
98
145
  entry.forced || false,
99
146
  entry.forceReason || null,
100
147
  entry.dropped || false,
@@ -107,14 +154,16 @@ export class PostgresAdapter extends DbAdapter {
107
154
  async updateSummaryForUser(userId, projectPath) {
108
155
  await this.connect();
109
156
  const normalizedProjectPath = projectPath || '';
157
+ const numericUserId = this.getNumericUserId(userId);
110
158
 
111
159
  const res = await this.pool.query(`
112
- SELECT task_type, timestamp, task_description
160
+ SELECT task_type, completed_at as timestamp, description as task_description
113
161
  FROM workflow_history
114
162
  WHERE user_id = $1 AND project_path = $2
115
- ORDER BY timestamp DESC
163
+ ORDER BY completed_at DESC
116
164
  LIMIT 20
117
- `, [userId, normalizedProjectPath]);
165
+ `, [numericUserId, normalizedProjectPath]);
166
+ // ... (lines continue similarly)
118
167
 
119
168
  const rows = res.rows;
120
169
 
@@ -144,7 +193,7 @@ export class PostgresAdapter extends DbAdapter {
144
193
  `;
145
194
 
146
195
  await this.pool.query(upsert, [
147
- userId,
196
+ numericUserId,
148
197
  normalizedProjectPath,
149
198
  rows.length,
150
199
  JSON.stringify(taskTypes),
@@ -157,10 +206,11 @@ export class PostgresAdapter extends DbAdapter {
157
206
  async getSummaryForUser(userId, projectPath) {
158
207
  await this.connect();
159
208
  const normalizedProjectPath = projectPath || '';
209
+ const numericUserId = this.getNumericUserId(userId);
160
210
 
161
211
  const res = await this.pool.query(`
162
212
  SELECT * FROM project_summary WHERE user_id = $1 AND project_path = $2
163
- `, [userId, normalizedProjectPath]);
213
+ `, [numericUserId, normalizedProjectPath]);
164
214
 
165
215
  const row = res.rows[0];
166
216
  if (!row) return null;
@@ -183,16 +233,18 @@ export class PostgresAdapter extends DbAdapter {
183
233
  const sanitizedPageSize = Math.min(100, Math.max(1, Number.isFinite(Number(pageSize)) ? Math.floor(Number(pageSize)) : 20));
184
234
  const offset = (sanitizedPage - 1) * sanitizedPageSize;
185
235
 
236
+ const numericUserId = this.getNumericUserId(userId);
237
+
186
238
  const clauses = [];
187
- const params = [userId, normalizedProjectPath];
239
+ const params = [numericUserId, normalizedProjectPath];
188
240
  let paramIdx = 3;
189
241
 
190
242
  if (startDate) {
191
- clauses.push(`DATE(timestamp) >= DATE($${paramIdx++})`);
243
+ clauses.push(`DATE(completed_at) >= DATE($${paramIdx++})`);
192
244
  params.push(startDate);
193
245
  }
194
246
  if (endDate) {
195
- clauses.push(`DATE(timestamp) <= DATE($${paramIdx++})`);
247
+ clauses.push(`DATE(completed_at) <= DATE($${paramIdx++})`);
196
248
  params.push(endDate);
197
249
  }
198
250
 
@@ -205,10 +257,10 @@ export class PostgresAdapter extends DbAdapter {
205
257
  const total = parseInt(countRes.rows[0].total, 10);
206
258
 
207
259
  const entriesRes = await this.pool.query(`
208
- SELECT *
260
+ SELECT *, description as task_description, completed_at as timestamp
209
261
  FROM workflow_history
210
262
  WHERE ${where}
211
- ORDER BY timestamp DESC
263
+ ORDER BY completed_at DESC
212
264
  LIMIT $${paramIdx++}
213
265
  OFFSET $${paramIdx++}
214
266
  `, [...params, sanitizedPageSize, offset]);
@@ -228,23 +280,25 @@ export class PostgresAdapter extends DbAdapter {
228
280
  const { startDate, endDate, frequency = "daily" } = options;
229
281
  const format = FREQUENCY_FORMATS[frequency] || FREQUENCY_FORMATS.daily;
230
282
 
283
+ const numericUserId = this.getNumericUserId(userId);
284
+
231
285
  const clauses = [];
232
- const params = [userId, normalizedProjectPath];
286
+ const params = [numericUserId, normalizedProjectPath];
233
287
  let paramIdx = 3;
234
288
 
235
289
  if (startDate) {
236
- clauses.push(`DATE(timestamp) >= DATE($${paramIdx++})`);
290
+ clauses.push(`DATE(completed_at) >= DATE($${paramIdx++})`);
237
291
  params.push(startDate);
238
292
  }
239
293
  if (endDate) {
240
- clauses.push(`DATE(timestamp) <= DATE($${paramIdx++})`);
294
+ clauses.push(`DATE(completed_at) <= DATE($${paramIdx++})`);
241
295
  params.push(endDate);
242
296
  }
243
297
 
244
298
  const where = [`user_id = $1`, `project_path = $2`, ...clauses].join(" AND ");
245
299
 
246
300
  const res = await this.pool.query(`
247
- SELECT to_char(timestamp, '${format}') AS period, COUNT(*) AS count
301
+ SELECT to_char(completed_at, '${format}') AS period, COUNT(*) AS count
248
302
  FROM workflow_history
249
303
  WHERE ${where}
250
304
  GROUP BY period
@@ -267,8 +321,10 @@ export class PostgresAdapter extends DbAdapter {
267
321
  updated_at=EXCLUDED.updated_at
268
322
  `;
269
323
 
324
+ const numericUserId = this.getNumericUserId(userId);
325
+
270
326
  await this.pool.query(query, [
271
- userId,
327
+ numericUserId,
272
328
  normalizedProjectPath,
273
329
  JSON.stringify(state),
274
330
  new Date().toISOString()
@@ -278,10 +334,11 @@ export class PostgresAdapter extends DbAdapter {
278
334
  async getState(userId, projectPath) {
279
335
  await this.connect();
280
336
  const normalizedProjectPath = projectPath || '';
337
+ const numericUserId = this.getNumericUserId(userId);
281
338
 
282
339
  const res = await this.pool.query(`
283
340
  SELECT state_json FROM workflow_state WHERE user_id = $1 AND project_path = $2
284
- `, [userId, normalizedProjectPath]);
341
+ `, [numericUserId, normalizedProjectPath]);
285
342
 
286
343
  const row = res.rows[0];
287
344
  if (!row) return null;
@@ -25,9 +25,15 @@ export class SqliteAdapter extends DbAdapter {
25
25
  // Otherwise, attempt to find project root relative to CWD
26
26
  const initCwd = process.env.INIT_CWD || process.cwd();
27
27
  let projectRoot = initCwd;
28
- while (projectRoot !== path.dirname(projectRoot)) {
28
+ let limit = 20; // Prevent infinite loop in weird environments
29
+ while (projectRoot !== path.dirname(projectRoot) && limit > 0) {
29
30
  if (existsSync(path.join(projectRoot, "package.json"))) break;
30
31
  projectRoot = path.dirname(projectRoot);
32
+ limit--;
33
+ }
34
+ if (limit === 0) {
35
+ console.error("Warning: Could not find project root effectively, defaulting to INIT_CWD");
36
+ projectRoot = initCwd;
31
37
  }
32
38
  return path.join(projectRoot, ".state", DB_FILENAME);
33
39
  }
@@ -19,6 +19,23 @@ services:
19
19
  timeout: 5s
20
20
  retries: 5
21
21
 
22
+ api:
23
+ build:
24
+ context: ./web
25
+ dockerfile: Dockerfile.api
26
+ container_name: dev-workflow-api
27
+ ports:
28
+ - "8080:8080"
29
+ environment:
30
+ - DEV_WORKFLOW_DB_URL=${DEV_WORKFLOW_DB_URL}
31
+ - SESSION_SECRET=${SESSION_SECRET:-dev-workflow-secret-change-in-production}
32
+ - NODE_ENV=${NODE_ENV:-production}
33
+ - API_PORT=8080
34
+ depends_on:
35
+ postgres:
36
+ condition: service_healthy
37
+ restart: unless-stopped
38
+
22
39
  volumes:
23
40
  postgres_data:
24
41
  driver: local
@@ -4,7 +4,7 @@
4
4
  - **Product**: Development Workflow MCP Server
5
5
  - **Prepared by**: Cascade (AI assistant)
6
6
  - **Date**: 2025-12-16
7
- - **Status**: Live v1.7.11
7
+ - **Status**: Live v1.7.15
8
8
 
9
9
  ## 2. Problem Statement
10
10
  Developers need structured guidance to maintain disciplined workflows across projects. Existing tooling lacks enforcement of sequential best practices (testing, documentation, release hygiene) and offers limited visibility into historical task execution.
@@ -67,7 +67,9 @@ Developers need structured guidance to maintain disciplined workflows across pro
67
67
  3. **v1.5.0**: Netlify deployment support for static web dashboard (complete).
68
68
  4. **v1.6.0+**: Dark/Light mode, UI Improvements (complete).
69
69
  5. **Multi-Database Support**: Refactor storage layer to support MySQL and PostgreSQL (complete v1.7.1).
70
- 6. **Future**: Expanded dashboard analytics, customizable workflows, richer integrations.
70
+ 7. **v1.7.14 Performance & Resilience**: Implemented connection timeouts and optimized startup sequence for stdio clients (complete).
71
+ 8. **v1.7.15 Schema Alignment**: Implemented Postgres/MySQL column normalization and automated integer User ID hashing for cross-dashboard compatibility (complete).
72
+ 9. **Future**: Expanded dashboard analytics, customizable workflows, richer integrations.
71
73
 
72
74
  ## 11. Risks & Mitigations
73
75
  - **Risk**: Workflow feels overly prescriptive. **Mitigation**: Provide escape hatches (`force_complete_task`, `drop_task`) with audit trails.
@@ -4,6 +4,10 @@ Authoritative history of user-visible changes for the Development Workflow MCP S
4
4
 
5
5
  | Version | Date | Notes |
6
6
  |---------|------|-------|
7
+ | 1.7.16 | 2025-12-24 | align database schema with dashboard and improve user ID handling (69e7f38) |
8
+ | 1.7.15 | 2025-12-19 | optimize startup performance and add database connection resilience (bff2714) |
9
+ | 1.7.14 | 2025-12-19 | add API dependencies and update login to use API client (94bb42f) |
10
+ | 1.7.13 | 2025-12-18 | remote db connection, history api 500 errors, and windows startup (ce559a6) |
7
11
  | 1.7.12 | 2025-12-17 | post-release cleanup v1.7.11 (c2ee733) |
8
12
  | 1.7.11 | 2025-12-17 | test: comprehensive DB adapter tests, env support, and warning fixes (64b029a) |
9
13
  | 1.7.10 | 2025-12-16 | update release notes and finalize ci config (92ac78a) |
@@ -37,6 +41,63 @@ Authoritative history of user-visible changes for the Development Workflow MCP S
37
41
 
38
42
 
39
43
 
44
+
45
+
46
+
47
+
48
+ ## 1.7.16 โ€“ ๐Ÿ› Bug Fixes
49
+
50
+ Released on **2025-12-24**.
51
+
52
+ - align database schema with dashboard and improve user ID handling (69e7f38)
53
+ - cleanup temporary debugging scripts (a5e2b15)
54
+ - sync version to 1.7.15 across web and landing pages (c520e4a)
55
+ - update macOS MCP config instructions (1e368da)
56
+
57
+ ## 1.7.15 โ€“ ๐Ÿ› Bug Fixes
58
+
59
+ Released on **2025-12-19**.
60
+
61
+ - optimize startup performance and add database connection resilience (bff2714)
62
+ - refactor Navbar and History to use absolute API client URLs v1.7.18 (dc33eae)
63
+ - sync all version labels to 1.7.14 and improve netlify routing (78712eb)
64
+ - sync all version strings to 1.7.14 (e2a1795)
65
+ - sync version to 1.7.14 and fix static routing via trailingSlash (1c152bd)
66
+
67
+ ## 1.7.14 โ€“ โœจ Features
68
+
69
+ Released on **2025-12-19**.
70
+
71
+ - add API dependencies and update login to use API client (94bb42f)
72
+ - add REST API server for frontend database access (cdb347c)
73
+ - implement JWT authentication and update client (8efbe80)
74
+ - remove session cookies, enforce JWT only (bacd83a)
75
+ - add credentials:include to getCurrentUser to persist session (b8f2df5)
76
+ - add root netlify.toml for monorepo support (54c5ed3)
77
+ - enable trust proxy and force secure cookies for cross-domain session (2c5d6e8)
78
+ - ensure getMe uses full API URL (b3bd0da)
79
+ - force API URL to tunnel address to resolve cached old IP (1883731)
80
+ - inline auth functions in API server (eefd73c)
81
+ - remove duplicate variable declarations in API server (31d3621)
82
+ - remove dynamic API route for static export (05a4dd0)
83
+ - remove explicit publish path to fix netlify build (cd64bcf)
84
+ - remove incorrect netlify publish dir for dynamic build (ea34cf4)
85
+ - remove incorrect publish dir from netlify config (010236f)
86
+ - restore static export for netlify deployment (685d841)
87
+ - update API URL to use Cloudflare Tunnel for HTTPS (ab72f6c)
88
+ - use apiClient in history page and add version indicator (4889669)
89
+ - use npm install instead of ci to avoid lockfile issues (e5fae26)
90
+ - bump version to 1.7.14 to ensure fresh build (f7d8886)
91
+ - bump version to 1.7.15 for JWT frontend deploy (7850268)
92
+ - cleanup post-release and update website version to 1.7.13 (7341d44)
93
+ - save pending changes before release (4d4b1c9)
94
+
95
+ ## 1.7.13 โ€“ ๐Ÿ› Bug Fixes
96
+
97
+ Released on **2025-12-18**.
98
+
99
+ - remote db connection, history api 500 errors, and windows startup (ce559a6)
100
+
40
101
  ## 1.7.12 โ€“ ๐Ÿ“ Documentation
41
102
 
42
103
  Released on **2025-12-17**.
package/index.js CHANGED
@@ -191,20 +191,30 @@ Use 'check_ready_to_commit' to verify workflow completion.
191
191
 
192
192
  // Start server
193
193
  export async function main() {
194
+ const startTime = Date.now();
195
+ console.error(`[${new Date().toISOString()}] MCP Server starting...`);
196
+
194
197
  try {
195
198
  // Initialize workflow state
196
199
  workflowState = new WorkflowState();
200
+ console.error(`[${new Date().toISOString()}] Loading workflow state...`);
197
201
  await workflowState.load();
202
+ console.error(`[${new Date().toISOString()}] Workflow state loaded.`);
203
+
204
+ console.error(`[${new Date().toISOString()}] Ensuring primary file...`);
198
205
  await workflowState.ensurePrimaryFile();
206
+ console.error(`[${new Date().toISOString()}] Workflow state initialization complete.`);
199
207
  } catch (error) {
200
- console.error("Warning: Failed to initialize workflow state:", error.message);
208
+ console.error(`[${new Date().toISOString()}] Warning: Failed to initialize workflow state:`, error.message);
201
209
  // Continue anyway - workflow state is optional for MCP to function
202
210
  workflowState = new WorkflowState();
203
211
  }
204
212
 
205
213
  const transport = new StdioServerTransport();
214
+ console.error(`[${new Date().toISOString()}] Connecting transport...`);
206
215
  await server.connect(transport);
207
- console.error("Dev Workflow MCP Server running on stdio");
216
+ const duration = Date.now() - startTime;
217
+ console.error(`[${new Date().toISOString()}] Dev Workflow MCP Server running on stdio (startup took ${duration}ms)`);
208
218
  }
209
219
 
210
220
  // --- Lightweight CLI: dev-workflow-mcp call <toolName> [--args '<json>'] ---
package/netlify.toml ADDED
@@ -0,0 +1,7 @@
1
+ [build]
2
+ base = "web"
3
+ command = "npm run build"
4
+ # publish = ".next" (Removed to allow auto-detection)
5
+
6
+ [[plugins]]
7
+ package = "@netlify/plugin-nextjs"
package/nginx-api.conf ADDED
@@ -0,0 +1,27 @@
1
+ server {
2
+ listen 80;
3
+ server_name api.devworkflow.programinglive.com;
4
+
5
+ location / {
6
+ proxy_pass http://localhost:8080;
7
+ proxy_http_version 1.1;
8
+ proxy_set_header Upgrade $http_upgrade;
9
+ proxy_set_header Connection 'upgrade';
10
+ proxy_set_header Host $host;
11
+ proxy_set_header X-Real-IP $remote_addr;
12
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
13
+ proxy_set_header X-Forwarded-Proto $scheme;
14
+ proxy_cache_bypass $http_upgrade;
15
+
16
+ # CORS headers (backup in case API doesn't set them)
17
+ add_header 'Access-Control-Allow-Origin' 'https://devworkflow.programinglive.com' always;
18
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
19
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
20
+ add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
21
+
22
+ # Handle preflight requests
23
+ if ($request_method = 'OPTIONS') {
24
+ return 204;
25
+ }
26
+ }
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.7.13",
3
+ "version": "1.7.16",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "homepage": "https://devworkflow.programinglive.com/",
6
6
  "mcpName": "io.github.programinglive/dev-workflow-mcp-server",