Ticket: TBD
Date: 2026-04-11
HEL-702 (collapse 6 containers to 1) was deployed April 10 and is running healthy.
This PR bundles all remaining fixes into one shipment to avoid multiple slow rebuilds.
docker/entrypoint.sh was changed from */15 to */30 after HEL-702 because 15-min
cron kept CPU pegged (build takes ~15 min). The change is on disk but not committed —
next Coolify deploy would regress to 15 min.
File: docker/entrypoint.sh
*/15 → */30every 15 min → every 30 minAlso commit CLAUDE.md workflow update (already on disk).
Do NOT commit the package.json dev script change (--port 4000 removal) —
it would break dev-evidence.sayhellocollege.com Traefik routing.
static/build-info.json from git (DRAFT-fix-build-info-timestamps)rebuild.sh writes timestamps to static/build-info.json before every build. But the
file is git-tracked with empty strings committed. When git pull runs, git resets it to
empty. If the build fails between pull and write, timestamps show dashes on every page.
Files:
.gitignore — add static/build-info.jsongit rm --cached static/build-info.json — stop tracking (file stays on disk)The 404 page renders â€" instead of — because Content-Type: text/html has no
charset=utf-8 declaration. Same issue on the 403 page.
File: docker/server.cjs
'Content-Type': 'text/html' → 'Content-Type': 'text/html; charset=utf-8''Content-Type': 'text/html' → 'Content-Type': 'text/html; charset=utf-8'The Accounts Receivable page has 8 SQL queries. Two depend on selected_month and
re-execute when the user changes the month dropdown:
daily_ar_month (daily cash flow table)student_payment_details (customer detail table)Both contain 3 expensive CTEs (active_orders, order_totals, expected_first_payment)
that are completely static (no input dependencies) but get recomputed on every month
switch. These same CTEs are duplicated across 5 of the 8 queries.
Fix: Extract the 3 static CTEs as standalone cached queries at the top of the page.
Replace all CTE occurrences with ${query_name} subquery references. DuckDB caches the
standalone query results, so month switches only recompute the month-specific filtering.
File: pages/Finance/accounts_receivable.md
Add 3 new queries after the ar_months query (after line 50):
SELECT DISTINCT o.id AS order_id
FROM orders o
INNER JOIN student_orders so ON so.order_id = o.id
INNER JOIN students s ON s.id = so.student_id
WHERE s.hidden = false
AND s.suspended = false
SELECT
o.id AS order_id,
SUM(op_product.price * op_product.quantity) AS order_total
FROM orders o
LEFT JOIN order_products op_product ON op_product.order_id = o.id
GROUP BY o.id
SELECT
o.id AS order_id,
SUM(
((op.price + COALESCE(op.service_charge, 0) - COALESCE(op.discount, 0)) * op.quantity) / COALESCE(op.number_of_months, 1)
) AS expected_amount
FROM orders o
INNER JOIN order_products op ON op.order_id = o.id
GROUP BY o.id
Then in all 6 queries that use these CTEs (daily_ar_summary, daily_ar_month,
summary_totals, monthly_ar_trend, student_payment_details, date_range_check):
active_orders CTE, replace active_orders ao with (${active_orders}) aoorder_totals CTE, replace order_totals ot with (${order_totals}) otexpected_first_payment CTE, replace with (${expected_first_payment}) efpThis is the standard Evidence pattern (used in college_decisions.md with ${college_decision_report}).
pages/Planning/capacity_dashboard.md line 392 uses list({struct}) which produces
an ARRAY[STRUCT] column that Evidence can't serialize, causing build warnings.
File: pages/Planning/capacity_dashboard.md
list(...) with TO_JSON():-- Before
list(
{'month': month_date, 'util': ROUND(total_hours / capacity, 4)}
ORDER BY month_date
) AS utilization_trend
-- After
TO_JSON(list(
{'month': month_date, 'util': ROUND(total_hours / capacity, 4)}
ORDER BY month_date
)) AS utilization_trend
scaleColor deprecation warningsEvidence v5 renamed scaleColor to colorScale. 14 occurrences across 7 files.
Files:
pages/Service Delivery/Counselors/counselor_performance.md (1)pages/Service Delivery/contact_health.md (1)pages/Service Delivery/team_performance.md (2)pages/Service Delivery/Essay Coaches/essay_performance.md (1)pages/Service Delivery/Tutors/tutor_dashboard.md (2)pages/Planning/counselor_deep_dive.md (4)pages/Growth/retention_churn.md (1)pages/Growth/onboarding.md (2)Change: scaleColor → colorScale (14 occurrences, find-and-replace)
| File | Change |
|---|---|
docker/entrypoint.sh |
Commit existing cron */30 change |
CLAUDE.md |
Commit existing workflow update |
.gitignore |
Add static/build-info.json |
static/build-info.json |
Untrack from git |
docker/server.cjs |
Add charset=utf-8 to 403 and 404 headers |
pages/Finance/accounts_receivable.md |
Extract 3 cached queries, remove duplicate CTEs |
pages/Planning/capacity_dashboard.md |
Wrap sparkline list() in TO_JSON() |
| 7 pages across Service Delivery/Planning/Growth | scaleColor → colorScale |
capacity_dashboard (only one query causes it)npm run build:strict passes clean (no errors, reduced warnings)git ls-files static/build-info.json returns nothingscaleColor deprecation warnings in build outputdocker/entrypoint.sh committed with */30 cronstatic/build-info.json untracked from git, listed in .gitignorecharset=utf-8 in Content-Typeactive_orders, order_totals, expected_first_payment)active_orders/order_totals/expected_first_payment CTEs in AR queriescapacity_dashboard.md sparkline uses TO_JSON(list(...))scaleColor replaced with colorScalenpm run build:strict passes with zero errorsscaleColor deprecation warnings eliminated