Redis Caching Implementation Plan
Status: Ready for ImplementationExpected Impact: 10-30x performance improvement (22 β 600 documents/min)
Estimated Effort: 2-3 days
Monthly Cost: ~$50 for Redis hosting
π Overview
This document outlines where to add Redis caching and cache invalidation across CONA to achieve the performance goals outlined in the Stage 1 optimization plan. Two Layers of Caching:- Core Package Functions (CRITICAL for Temporal workers) -
packages/core/src/services/ - Webapp Server Actions (For UI/API) -
apps/webapp/app/lib/actions/
TODO comments showing exactly where to add caching logic.
β οΈ IMPORTANT: Most queries come from Temporal workers, so caching in the core package has the biggest impact!
π― Core Package Caching (FOR TEMPORAL WORKERS)
Priority 0: MOST CRITICAL (For Workflow Performance)
These are called by Temporal workflows/activities and have the BIGGEST impact:-
fetchPostingMatrixRules() - Core Package
- File:
packages/core/src/services/fetch-posting-matrix-rules.ts - Function:
fetchPostingMatrixRules() - Cache Key:
posting_matrix_rules:${organizationId}:${dimensionLabel}:${triggerEventSlug} - TTL: 3600 seconds (1 hour)
- Impact: Called 600+ times per 100 documents (100ms β 5ms = 20x faster)
- Savings: 57 seconds per 100 documents
- Status: β TODO comments added (lines 54-94 & 191-206)
- File:
-
fetchGlDimensions() - Core Package
- File:
packages/core/src/services/fetch-gl-dimensions.ts - Function:
fetchGlDimensions() - Cache Key:
gl_dimensions_list:${organizationId} - TTL: 3600 seconds (1 hour)
- Impact: Called once per document (30ms β 3ms = 10x faster)
- Savings: 2.7 seconds per 100 documents
- Status: β TODO comments added (lines 8-38)
- File:
TEMPORAL_WORKER_CACHING_GUIDE.md for detailed worker-specific implementation guide.
π― Implementation Priority
Priority 1: CRITICAL PATH (π΄ Red Priority)
Impact: 100ms β 5ms per call (20x faster) These are called for EVERY document during accounting impact calculation:-
GL Dimensions with Posting Matrix
- File:
apps/webapp/app/lib/actions/gl_dimensions/get-gl-dimensions.ts - Function:
getGlDimensions() - Cache Key:
gl_dimensions:${organizationId}:${triggerEventId}:${includePostingMatrix}:${includeDeleted} - TTL: 3600 seconds (1 hour)
- File:
-
Individual Posting Matrix Lookup
- File:
apps/webapp/app/lib/actions/posting_matrix/get-posting-matrix.ts - Function:
getMatrix(id) - Cache Key:
posting_matrix:${id}:${organizationId} - TTL: 3600 seconds (1 hour)
- File:
-
Chart of Accounts List
- File:
apps/webapp/app/lib/actions/chart_of_accounts/list-chart-of-accounts.ts - Function:
listChartOfAccounts() - Cache Key:
chart_of_accounts:list:${organizationId}:${onlyReconcileAccounts} - TTL: 1800 seconds (30 minutes)
- File:
-
Chart of Accounts Search
- File:
apps/webapp/app/lib/actions/chart_of_accounts/search-chart-of-accounts.ts - Function:
searchChartOfAccounts() - Cache Key:
chart_of_accounts:search:${organizationId} - TTL: 1800 seconds (30 minutes)
- File:
Priority 2: HIGH FREQUENCY (π‘ Yellow Priority)
Impact: 20-50ms β 2-5ms per call These are called frequently but not on every document:-
Organization Details
- File:
apps/webapp/app/lib/actions/organization/get-organisation-details.ts - Function:
getOrganizationDetails() - Cache Key:
organization:details:${organizationId} - TTL: 3600 seconds (1 hour)
- File:
-
Tool/Integration Settings
- File:
apps/webapp/app/lib/actions/tools/get-tool-settings.ts - Function:
getToolSettings(toolSlug) - Cache Key:
tool_settings:${organizationId}:${toolSlug} - TTL: 1800 seconds (30 minutes)
- File:
-
Chart of Account by ID
- File:
apps/webapp/app/lib/actions/chart_of_accounts/get-chart-of-account-by-id.ts - Function:
getChartOfAccountById() - Cache Key:
chart_of_accounts:id:${organizationId}:${id} - TTL: 1800 seconds (30 minutes)
- File:
-
Chart of Account by Number
- File:
apps/webapp/app/lib/actions/chart_of_accounts/get-chart-of-account-id-by-number.ts - Function:
getAccountIdByNumber() - Cache Key:
chart_of_accounts:number:${organizationId}:${accountNumber} - TTL: 1800 seconds (30 minutes)
- File:
-
Posting Matrices Grouped by Trigger Event
- File:
apps/webapp/app/lib/actions/posting_matrix/get-posting-matrix-grouped-by-trigger-event.ts - Function:
getPostingMatricesGroupedByTriggerEvent() - Cache Key:
posting_matrices_grouped:${organizationId} - TTL: 3600 seconds (1 hour)
- File:
π Cache Invalidation Map
When Posting Matrix Changes
Affected Actions:save-posting-matrix.ts(create/update)delete-posting-matrix.ts(delete)create-posting-matrix.ts(create)
- β
apps/webapp/app/lib/actions/posting_matrix/save-posting-matrix.ts(line 142) - β
apps/webapp/app/lib/actions/posting_matrix/delete-posting-matrix.ts(line 65) - β
apps/webapp/app/lib/actions/posting_matrix/create-posting-matrix.ts(line 29)
When Chart of Accounts Changes
Affected Actions:create-chart-of-account.ts(create)update-chart-of-account.ts(update)- Any chart deletion actions
- β
apps/webapp/app/lib/actions/chart_of_accounts/create-chart-of-account.ts(line 48) - β
apps/webapp/app/lib/actions/chart_of_accounts/update-chart-of-account.ts(line 75) - β
apps/webapp/app/lib/actions/chart_of_accounts/delete-chart-of-account.ts(line 31)
When Organization Settings Change
Affected Actions:update-organisation-onboarding-complete.ts- Any organization update actions (name, currency, timezone, etc.)
- β
apps/webapp/app/lib/actions/organization/update-organisation-onboarding-complete.ts(line 31) - π² Search for other organization update actions
When Tool Settings Change
Affected Actions:update-tool-settings.ts
- β
apps/webapp/app/lib/actions/tools/update-tool-settings.ts(line 40)
ποΈ Implementation Pattern
Basic Caching Pattern
Cache Invalidation Pattern
π οΈ Setup Requirements
1. Get Redis Credentials
If using Supabase Redis/Upstash Integration:- Go to your Supabase Dashboard β Project Settings β Integrations
- Find Redis/Upstash integration
- Copy connection details:
- Redis Host (e.g.,
your-project.upstash.io) - Redis Port (usually
6379) - Redis Password
- Redis Host (e.g.,
2. Create Redis Client
Create a Redis client utility:3. Environment Variables
Add to.env:
Option A: Individual credentials
apps/temporal-workers/.env)
4. Create Redis Client for Core Package (Temporal Workers)
Since workers use core package functions, also create a Redis client there:π¨ Important Considerations
1. Cache Invalidation is Critical
- Always invalidate related caches when data changes
- Missing invalidation = stale data = bugs
- Use wildcard invalidation for safety when unsure
2. Error Handling
3. Cache Key Consistency
- Always include
organizationIdin cache keys - Use consistent separator (
:recommended) - Document cache key patterns
4. TTL Selection
- Posting matrix rules: 1 hour (rarely change)
- Chart of accounts: 30 minutes (moderate change)
- Organization settings: 1 hour (rarely change)
- Adjust based on real-world usage
π Reference Files
All files with inline TODO comments:Read Operations (Add Caching)
apps/webapp/app/lib/actions/gl_dimensions/get-gl-dimensions.ts(line 64)apps/webapp/app/lib/actions/posting_matrix/get-posting-matrix.ts(line 30)apps/webapp/app/lib/actions/posting_matrix/get-posting-matrix-grouped-by-trigger-event.ts(line 31)apps/webapp/app/lib/actions/chart_of_accounts/list-chart-of-accounts.ts(line 18)apps/webapp/app/lib/actions/chart_of_accounts/search-chart-of-accounts.ts(line 14)apps/webapp/app/lib/actions/chart_of_accounts/get-chart-of-account-by-id.ts(line 18)apps/webapp/app/lib/actions/chart_of_accounts/get-chart-of-account-id-by-number.ts(line 18)apps/webapp/app/lib/actions/organization/get-organisation-details.ts(line 28)apps/webapp/app/lib/actions/tools/get-tool-settings.ts(line 16)
Write Operations (Add Cache Invalidation)
apps/webapp/app/lib/actions/posting_matrix/save-posting-matrix.ts(line 142)apps/webapp/app/lib/actions/posting_matrix/delete-posting-matrix.ts(line 65)apps/webapp/app/lib/actions/posting_matrix/create-posting-matrix.ts(line 29)apps/webapp/app/lib/actions/chart_of_accounts/create-chart-of-account.ts(line 48)apps/webapp/app/lib/actions/chart_of_accounts/update-chart-of-account.ts(line 75)apps/webapp/app/lib/actions/chart_of_accounts/delete-chart-of-account.ts(line 31)apps/webapp/app/lib/actions/tools/update-tool-settings.ts(line 40)apps/webapp/app/lib/actions/organization/update-organisation-onboarding-complete.ts(line 31)
π― Success Criteria
Performance Metrics
- β Posting matrix fetch: 100ms β 5ms
- β Chart of accounts fetch: 50ms β 5ms
- β Overall processing: 400ms β 150ms per document
- β Throughput: 22 β 600 documents/min (27x improvement)
Reliability Metrics
- β Cache hit rate > 90% after warm-up
- β No stale data bugs in production
- β Database connection usage reduced by 80%+
- β Redis availability > 99.9%
π Important: Redis FDW vs Direct Connection
Supabase Redis Wrapper (FDW) - Documentation- β Not for this use case
- Purpose: Query Redis data FROM Postgres using SQL
- Use case:
SELECT * FROM redis.my_data;in SQL queries - Read-only access
- β This is what weβre implementing
- Purpose: Application-level caching from Node.js/Next.js
- Use case:
await redis.get('cache_key')in TypeScript code - Read and write access
- Bypasses Postgres entirely