- Added Jest infrastructure (deps, config, global mocks) - Introduced ISpreadsheetService with GAS and Mock implementations - Refactored Product.ts to use dependency injection - Added unit tests for Product class - Updated documentation (README, SETUP, ARCHITECTURE) to reflect testing and init scripts
4.5 KiB
Architecture Documentation
System Overview
This project serves as a bridge between Google Sheets and Shopify. It enables a two-way sync (primarily Sheets to Shopify for products) and allows managing inventory directly from a spreadsheet.
Core Flows
-
Product Updates:
- User edits a cell in the "product_inventory" sheet.
onEditQueuetrigger fires, capturing the SKU and timestamp.- Edits are batched in
PropertiesService(script properties). - A time-based trigger runs
processBatchedEditsevery minute. - The processing function locks the script, reads the queue, and pushes changes to Shopify via the Admin API.
-
Order Sync:
- Users can run menu commands to fetch orders from Shopify.
- The
Shopclass fetches orders via the REST API, handling pagination. - Data is populated into specific sheets (
_orders,_line_items,_customer, etc.).
Key Components
1. Queue System (src/onEditQueue.ts)
To avoid hitting Shopify API rate limits and Google Apps Script execution time limits, edits are not processed immediately.
-
onEditQueue(e):- Triggered on every cell edit.
- Checks if the edit is valid (correct sheet, valid SKU).
- Acquires a
DocumentLock. - Updates a JSON list in
ScriptProperties(pendingEdits). - Debounces edits (updates timestamp if SKU is already pending).
-
processBatchedEdits():- Run via time-based trigger (every 1 minute).
- Acquires a
ScriptLock. - Reads
pendingEdits. - Filters for edits older than
BATCH_INTERVAL_MS(30s) to allow for multiple quick edits to the same SKU. - Iterates through valid edits and calls
Product.UpdateShopifyProduct.
2. Shopify Integration (src/shopifyApi.ts)
The project uses a hybrid approach for the Shopify Admin API:
- REST API: Used primarily for fetching Orders (legacy support).
- GraphQL API: Used for fetching and updating Products and Inventory.
The Shop class handles authentication using credentials stored in the "vars" sheet.
3. Configuration (src/config.ts)
Configuration, including API keys, is stored in a dedicated Google Sheet named "vars". The Config class reads these values at runtime using a vlookup style helper.
Required "vars" columns:
key: The name of the configuration variable.value: The actual value.
4. Global Entry Points (src/global.ts)
Since Apps Script functions must be top-level to be triggered or attached to buttons, src/global.ts explicitly exposes necessary functions from the modules to the global scope.
5. Status Automation (src/statusHandlers.ts)
A modular system handles changes to the status column. It uses a registry of StatusHandler implementations:
- Published: Sets Shopify Status
ACTIVE, Quantity1. - Sold/Artist Swap: Sets Shopify Status
ACTIVE, Quantity0. - Drafted: Sets Shopify Status
DRAFT.
Triggers
Triggers are managed programmatically via src/triggers.ts. Running reinstallTriggers will wipe existing project triggers and set up the standard set:
onEdit->onEditHandler(Main Router)TimeBased (1 min)->processBatchedEditsTimeBased (10 min)->checkRecentSales
5. Troubleshooting Panel (src/sidebar.ts, src/Sidebar.html)
A dedicated side panel provides visibility into the background queue system.
-
Backend (
src/sidebar.ts):getQueueStatus(): Returns the current state of the queue and global toggle.setQueueEnabled(): Toggles the globalqueueEnabledscript property.deleteEdit()/pushEdit(): Manages specific items in the queue with safety checks.
-
Frontend (
src/Sidebar.html):- Displays pending edits with timestamps.
- Provides controls to globally enable/disable processing.
- Allows manual intervention (delete/push) for individual items.
6. Service Layer & Testing
To enable unit testing without Google Apps Script dependencies, the project uses a Service pattern with Dependency Injection.
ISpreadsheetService: Interface for all sheet interactions.GASSpreadsheetService: Production implementation wrappingSpreadsheetApp.MockSpreadsheetService: In-memory implementation for tests.
Classes (like Product) should accept an ISpreadsheetService in their constructor. This allows providing the Mock service during tests to verify logic without touching real Google Sheets.