[object Object]

← back to Dw Activation Calendar

Document Google Calendar layer: README + updated server header comment

c3c31accf039a6900efeb9246b12c69d0e376979 · 2026-06-24 13:43:28 -0700 · Steve

Files touched

Diff

commit c3c31accf039a6900efeb9246b12c69d0e376979
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 24 13:43:28 2026 -0700

    Document Google Calendar layer: README + updated server header comment
---
 README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 server.js | 18 +++++++++++-------
 2 files changed, 71 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5ccfde8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,60 @@
+# DW Calendar
+
+Two surfaces in one Express app on `:9765` (DTD verdict **AX**, 2026-06-24).
+
+## Tabs
+- **Google Calendar** — live, **editable** view of the shared DW Google Calendar.
+  Click any day or event → modal creates / edits / deletes real events
+  (`events.insert` / `patch` / `delete`). Built on a fetch-only Google Calendar
+  v3 client (`google-cal.js`) — **no `googleapis` SDK dependency**.
+- **SKU Activation** — read-only projection of the staged-for-active SKU rollout
+  (`/api/schedule`, sourced from `dw_unified.bulk_fivefield_worklist`). Unchanged
+  from the original build.
+
+## API
+| Method | Path | Notes |
+|---|---|---|
+| GET | `/api/calendar/status` | `{oauth_configured, connected, calendar_id}` |
+| GET | `/api/events?timeMin=&timeMax=` | events.list for a window |
+| POST | `/api/events` | create — body `{summary,description?,location?,start,end,allDay?}` |
+| PATCH | `/api/events/:id` | update (events.patch) |
+| DELETE | `/api/events/:id` | delete |
+| GET | `/api/oauth/start` | 302 → Google consent (503 if not configured) |
+| GET | `/api/oauth/callback` | token exchange |
+| POST | `/api/oauth/revoke` | disconnect |
+| GET | `/api/schedule` | SKU-activation projection (existing) |
+
+All event routes degrade gracefully when no credential is present: `409 not_connected`
+/ `{connected:false}` — **never a 500**.
+
+## Connecting the Google Calendar (Steve — GATED)
+The OAuth credential, secrets-fan-out, and consent click are Steve-only. The full
+runbook is queued at:
+
+`~/.claude/yolo-queue/pending-approval/2026-06-24-dw-google-calendar-oauth-credential.md`
+
+Short version:
+1. Google Cloud Console → enable Calendar API → create a **Web application** OAuth
+   client → add redirect URI `http://127.0.0.1:9765/api/oauth/callback`.
+2. Route the secret: `node ~/Projects/secrets-manager/cli.js add GOOGLE_OAUTH_CLIENT_ID '<id>'`
+   and `... GOOGLE_OAUTH_CLIENT_SECRET '<secret>'` (add a routes.json entry first
+   so it lands in `./.env`). Optionally set `GOOGLE_DW_CALENDAR_ID` to a dedicated
+   "DW Ops" calendar id; default is `primary`.
+3. Visit `http://127.0.0.1:9765/api/oauth/start` and grant consent.
+4. Verify: `curl -s http://127.0.0.1:9765/api/calendar/status` → `connected:true`.
+
+## Env
+```
+PORT                       default 9765
+GOOGLE_OAUTH_CLIENT_ID     (or GOOGLE_CLIENT_ID)
+GOOGLE_OAUTH_CLIENT_SECRET (or GOOGLE_CLIENT_SECRET)
+GOOGLE_OAUTH_REDIRECT_URI  default http://127.0.0.1:9765/api/oauth/callback
+GOOGLE_DW_CALENDAR_ID      default 'primary'
+GOOGLE_CAL_TOKEN_FILE      default ./.google-tokens.local.json (gitignored, 0600)
+DATABASE_URL / PG*         dw_unified (for the SKU tab)
+```
+
+## Run
+```
+PORT=9765 node server.js
+```
diff --git a/server.js b/server.js
index 401a0d9..b0c6a1e 100644
--- a/server.js
+++ b/server.js
@@ -1,13 +1,17 @@
 'use strict';
 /*
- * DW Activation Calendar — projects the go-active rollout of every SKU staged
- * for activation, at the publish cadence (18/hr = 432/day) with a per-vendor
- * daily cap (10/vendor/day), in date order, until the staged list is exhausted.
- * Renders a 1-month calendar; each SKU is a chip with its vendor name + product
- * image. Read-only projection (no Shopify/PG writes).
+ * DW Calendar — TWO surfaces in one app (DTD verdict AX, 2026-06-24):
  *
- * Source = dw_unified.bulk_fivefield_worklist (the staged-for-active list),
- * joined to shopify_products for the product image.
+ *  1) Google Calendar tab (EDITABLE): live read + CRUD against a real shared
+ *     DW Google Calendar via google-cal.js (OAuth + events.list/insert/patch/
+ *     delete). The modal creates/edits/deletes real events. Degrades gracefully
+ *     to a "not connected" state when no OAuth credential is present (never 500s).
+ *     Credential + consent are Steve-gated (see README + pending-approval memo).
+ *
+ *  2) SKU Activation tab (read-only): projects the go-active rollout of every
+ *     SKU staged for activation, at the publish cadence, in date order, until
+ *     the staged list is exhausted. Each SKU is a chip with vendor + image.
+ *     Source = dw_unified.bulk_fivefield_worklist joined to shopify_products.
  */
 const express = require('express');
 const path = require('path');

← 5498582 Add two-tab DW Calendar UI: editable Google Calendar modal (  ·  back to Dw Activation Calendar  ·  Restyle DW Calendar to luxe Figma spec (Cormorant/Inter, plu 73ec16d →