From 0430d4954982a2e91412fc22c79f89a8b06ef181 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2026 08:01:19 +0000
Subject: [PATCH 1/4] Add CODE_REVIEW.md and LIGHTNING_TALK.md
Co-authored-by: lucasrangit <701818+lucasrangit@users.noreply.github.com>
---
CODE_REVIEW.md | 40 ++++++++++++++++++++++++++++++++++++
LIGHTNING_TALK.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
create mode 100644 CODE_REVIEW.md
create mode 100644 LIGHTNING_TALK.md
diff --git a/CODE_REVIEW.md b/CODE_REVIEW.md
new file mode 100644
index 0000000..b54af85
--- /dev/null
+++ b/CODE_REVIEW.md
@@ -0,0 +1,40 @@
+# Code Review: Plotline Google Docs Add-on
+
+## Summary
+The codebase is logically organized into frontend (`Sidebar.html`, `PickerModal.html`) and backend components (`Code.js`, `Data.js`, `Library.js`). The separation of Google Docs context vs standard Apps Script logic is solid. However, following the `AGENTS.md` guidelines and general best practices, the following architectural and stylistic improvements would elevate the project.
+
+## 1. Modern JavaScript & V8 Engine Support
+
+Google Apps Script now runs on the V8 engine, which supports ES2017 syntax. Several files use older syntax that can be modernized for readability and performance.
+
+### Suggestions:
+- **`var` vs `let`/`const`:** In frontend scripts (e.g., `Sidebar.html` and `PickerModal.html`), variables are extensively declared using `var` (e.g., `var html`, `var appData`). Use `let` and `const` for proper block-scoping.
+- **Loops:** You rely heavily on C-style `for` loops (e.g., `for (let i = 0; i < paragraphs.length; i++)` in `Data.js`). Utilize `for...of` loops, or higher-order array methods like `.map()`, `.filter()`, and `.reduce()` for cleaner iteration.
+- **Object Iteration:** In `Data.js` (`migrateRevisionLegacyCachedWordCounts`, `getRevisionCachedWordCounts`), loops are driven by `Object.keys()`. You can streamline these blocks using `Object.entries()` or modern iteration directly on Maps if you refactor the caching logic.
+- **String Interpolation:** Update string concatenations (e.g., `"Revision " + rev.id + " Date: " + new Date(rev.date).toLocaleString()`) to template literals (e.g., `` `Revision ${rev.id} Date: ${new Date(rev.date).toLocaleString()}` ``).
+
+## 2. Magic Strings and Centralized Constants
+
+Strings used for property keys, DOM IDs, and error messages are hardcoded across multiple functions, which increases the likelihood of typos and complicates future refactors.
+
+### Suggestions:
+- Extract property keys (e.g., `'WORD_COUNT_GOAL'`, `'SIMULATE_FILE_NOT_FOUND'`) into a central `Constants` object at the top of your scripts.
+- Extract common error string matchers in `showError()` (`Sidebar.html`) to well-named constant arrays or objects.
+- Centralize cache keys and prefixes (e.g., `"REV_WC_"`, `"ALL_REVISIONS_CACHE"`) into the same module/scope to prevent drift.
+
+## 3. Frontend Architecture (Separation of Concerns)
+
+The HTML files (`Sidebar.html`, `PickerModal.html`) contain a dense mixture of HTML markup, inline CSS styles, and client-side JavaScript logic.
+
+### Suggestions:
+- **Componentization:** Move styles into a separate `Stylesheet.html` and scripts into a `JavaScript.html` file. You can then include these dynamically in your main HTML files using `HtmlService.createTemplateFromFile()` and `!= include('Stylesheet'); ?>` scriptlets.
+- **Inline Event Handlers:** Remove inline HTML event handlers (e.g., `onload="onLoad()"`, `onclick="refreshOutline()"`) in favor of standard event listeners attached within your client-side JavaScript block (e.g., `document.getElementById('refreshBtn').addEventListener('click', refreshOutline)`).
+- **DOM Manipulations:** The frequent string concatenation to build HTML nodes (e.g., `var html = '
`Date,WordCount`). The next time the user opens the sidebar or refreshes, Plotline pulls everything from the cache instantly, and only queries the Drive API for *new* revisions that happened since the last check. It dramatically speeds up the UI."
+
+---
+
+## 4:30 - UI Implementation & Wrap Up (30 seconds)
+
+**Presenter:**
+"Finally, the UI itself. We use `HtmlService` to serve the sidebar, and client-side JavaScript talks to our backend functions using `google.script.run`. Because Apps Script calls are asynchronous, we use success and failure handlers to update the DOM—like rendering our Chart.js timeline or showing error messages—without freezing the Docs interface.
+
+And that's Plotline! A serverless add-on turning raw revision data into actionable insights for writers. Thanks!"
From 57d0f7fdfeceb991495263ab90c09d1857955073 Mon Sep 17 00:00:00 2001
From: Lucas Rangit MAGASWERAN
Date: Tue, 28 Jul 2026 10:36:20 +0200
Subject: [PATCH 2/4] Update CODE_REVIEW.md
---
CODE_REVIEW.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/CODE_REVIEW.md b/CODE_REVIEW.md
index b54af85..dbe63c5 100644
--- a/CODE_REVIEW.md
+++ b/CODE_REVIEW.md
@@ -11,7 +11,6 @@ Google Apps Script now runs on the V8 engine, which supports ES2017 syntax. Seve
- **`var` vs `let`/`const`:** In frontend scripts (e.g., `Sidebar.html` and `PickerModal.html`), variables are extensively declared using `var` (e.g., `var html`, `var appData`). Use `let` and `const` for proper block-scoping.
- **Loops:** You rely heavily on C-style `for` loops (e.g., `for (let i = 0; i < paragraphs.length; i++)` in `Data.js`). Utilize `for...of` loops, or higher-order array methods like `.map()`, `.filter()`, and `.reduce()` for cleaner iteration.
- **Object Iteration:** In `Data.js` (`migrateRevisionLegacyCachedWordCounts`, `getRevisionCachedWordCounts`), loops are driven by `Object.keys()`. You can streamline these blocks using `Object.entries()` or modern iteration directly on Maps if you refactor the caching logic.
-- **String Interpolation:** Update string concatenations (e.g., `"Revision " + rev.id + " Date: " + new Date(rev.date).toLocaleString()`) to template literals (e.g., `` `Revision ${rev.id} Date: ${new Date(rev.date).toLocaleString()}` ``).
## 2. Magic Strings and Centralized Constants
From 45919c0e3f7dd79a4c494f23cc5643cb464a102d Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2026 07:27:52 +0000
Subject: [PATCH 3/4] Update CODE_REVIEW.md with best practices
Co-authored-by: lucasrangit <701818+lucasrangit@users.noreply.github.com>
---
CODE_REVIEW.md | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/CODE_REVIEW.md b/CODE_REVIEW.md
index dbe63c5..ca750dc 100644
--- a/CODE_REVIEW.md
+++ b/CODE_REVIEW.md
@@ -11,6 +11,7 @@ Google Apps Script now runs on the V8 engine, which supports ES2017 syntax. Seve
- **`var` vs `let`/`const`:** In frontend scripts (e.g., `Sidebar.html` and `PickerModal.html`), variables are extensively declared using `var` (e.g., `var html`, `var appData`). Use `let` and `const` for proper block-scoping.
- **Loops:** You rely heavily on C-style `for` loops (e.g., `for (let i = 0; i < paragraphs.length; i++)` in `Data.js`). Utilize `for...of` loops, or higher-order array methods like `.map()`, `.filter()`, and `.reduce()` for cleaner iteration.
- **Object Iteration:** In `Data.js` (`migrateRevisionLegacyCachedWordCounts`, `getRevisionCachedWordCounts`), loops are driven by `Object.keys()`. You can streamline these blocks using `Object.entries()` or modern iteration directly on Maps if you refactor the caching logic.
+- **String Interpolation:** Update string concatenations (e.g., `"Revision " + rev.id + " Date: " + new Date(rev.date).toLocaleString()`) to template literals (e.g., `` `Revision ${rev.id} Date: ${new Date(rev.date).toLocaleString()}` ``).
## 2. Magic Strings and Centralized Constants
@@ -30,10 +31,13 @@ The HTML files (`Sidebar.html`, `PickerModal.html`) contain a dense mixture of H
- **Inline Event Handlers:** Remove inline HTML event handlers (e.g., `onload="onLoad()"`, `onclick="refreshOutline()"`) in favor of standard event listeners attached within your client-side JavaScript block (e.g., `document.getElementById('refreshBtn').addEventListener('click', refreshOutline)`).
- **DOM Manipulations:** The frequent string concatenation to build HTML nodes (e.g., `var html = '
Date: Wed, 29 Jul 2026 08:37:35 +0000
Subject: [PATCH 4/4] Add production monitoring suggestion to CODE_REVIEW.md
Co-authored-by: lucasrangit <701818+lucasrangit@users.noreply.github.com>
---
CODE_REVIEW.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CODE_REVIEW.md b/CODE_REVIEW.md
index ca750dc..f7ff7ee 100644
--- a/CODE_REVIEW.md
+++ b/CODE_REVIEW.md
@@ -38,6 +38,7 @@ The HTML files (`Sidebar.html`, `PickerModal.html`) contain a dense mixture of H
- **Configuration & Secrets:** Configuration options in `PickerModal.html` refer directly to `GOOGLE_CLOUD_API_KEY` and `GOOGLE_CLOUD_PROJECT_NUMBER`. Ensure proper fallback defaults and validation in your backend configuration getters. Avoid checking any real keys into the codebase.
- **Error Handling & Quotas:** The backoff retry wrapper in `Library.js` is excellent for handling 429s. However, ensure you properly wait explicitly on `429` retry-after headers if they are provided by the Drive API, rather than purely relying on exponential backoff, to better respect Google's quota limits.
- **Manifest Permissions (`appsscript.json`):** You have defined narrow scopes like `documents.currentonly` which is great for security. Ensure that the Stackdriver exception logging (`"exceptionLogging": "STACKDRIVER"`) does not inadvertently log PII from document text when an error is thrown.
+- **Production Monitoring:** Since the add-on is distributed to end users, set up robust monitoring using Google Cloud operations suite (formerly Stackdriver) or a third-party service. Actively track error rates (especially `429` rate limits and permissions errors), API latency, and quota exhaustion to proactively address performance regressions or scale issues before users report them.
---
*Overall, the integration logic is sound and the backend is well-structured for Apps Script execution.*