Files
product_inventory/docs/ARCHITECTURE.md
2025-12-25 04:13:09 -07:00

4.9 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

  1. Product Updates:

    • User edits a cell in the "product_inventory" sheet.
    • onEditQueue trigger fires, capturing the SKU and timestamp.
    • Edits are batched in PropertiesService (script properties).
    • A time-based trigger runs processBatchedEdits every minute.
    • The processing function locks the script, reads the queue, and pushes changes to Shopify via the Admin API.
  2. Order Sync:

    • Users can run menu commands to fetch orders from Shopify.
    • The Shop class 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, Quantity 1.
  • Sold/Artist Swap: Sets Shopify Status ACTIVE, Quantity 0.
  • 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) -> processBatchedEdits
  • TimeBased (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 global queueEnabled script 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 & Quality

To enable unit testing without Google Apps Script dependencies, the project uses a Service pattern with Dependency Injection.

Architecture

  • ISpreadsheetService: Interface for all sheet interactions.
  • GASSpreadsheetService: Production implementation wrapping SpreadsheetApp.
  • MockSpreadsheetService: In-memory implementation for tests.

Quality Assurance

We use Husky and lint-staged to enforce quality standards at the commit level:

  1. Pre-commit Hook: Automatically runs npm test -- --onlyChanged --coverage.
  2. Coverage Policy: Any file modified in a commit must meet an 80% line coverage threshold. This ensures the codebase quality improves monotonically ("Boy Scout Rule").

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.