Skip to content

Production-readiness + feature advancements (analytics, notifications, email, semantic search) - #1

Merged
rogerdemello merged 8 commits into
mainfrom
production-readiness
Jun 23, 2026
Merged

Production-readiness + feature advancements (analytics, notifications, email, semantic search)#1
rogerdemello merged 8 commits into
mainfrom
production-readiness

Conversation

@rogerdemello

Copy link
Copy Markdown
Owner

Summary

Two bodies of work, in 7 logical commits.

Production-readiness sprint

  • Security: helmet + rate limiting on auth/AI endpoints; secured GET /api/audit (was readable unauthenticated).
  • Testing: Vitest + Supertest from zero → 47 tests (compliance/risk math, auth/RBAC, analytics aggregation, notifications, email templates).
  • Quality: extracted shared src/api/lib/compliance.ts; removed as any JWT casts; fixed 3 latent bugs (intCompanyId undefined, change-password req.user.id, apiOrigin typo); replaced the broken eslint-config-next config with a working Vite flat config (tsc --noEmit and eslint now clean).
  • DevOps: multi-stage Dockerfile (Chromium for PDF export), docker-compose, .dockerignore, GitHub Actions CI, production SPA serving, docs/DEPLOYMENT.md.

Feature advancements

  1. Analytics dashboard/analytics (recharts) + GET /api/analytics/summary (company-scoped); Dashboard trends are now real deltas.
  2. In-app notifications + activity feed — bell + GET /api/notifications sourced from AuditLog.
  3. Email notifications — Resend provider, gated OFF (EMAIL_ENABLED + key), never sends in tests.
  4. Semantic search (scaffold) — embeddings + GET /api/proposals/search + pgvector migration/backfill; falls back to substring search until activated.

Verification

npm run lint ✅ · npm run typecheck ✅ · 47 tests pass ✅ · prisma validate ✅ · vite build

Follow-ups needed (by design)

  • Email: set RESEND_API_KEY + EMAIL_ENABLED=true in .env to actually send.
  • Semantic search: run prisma/manual/semantic_search.sql on Supabase, then npm run backfill:embeddings (see docs/SEMANTIC_SEARCH.md).
  • Credentials: rotate the Supabase/Azure keys + NEXTAUTH_SECRET that were surfaced in plaintext.
  • Docker image build wasn't validated locally (no Docker daemon on the dev box).

Roger Demello added 7 commits June 22, 2026 21:18
Vitest+Supertest setup, GitHub Actions CI (lint/typecheck/test/build), multi-stage Dockerfile with Chromium for PDF export, helmet+rate-limit middleware, and a NODE_ENV-gated logger. Replaces the broken eslint-config-next config with a proper Vite flat config.
Extract deterministic risk/markdown logic into src/api/lib/compliance.ts (unit-tested). Replace as-any JWT casts, fix latent bugs (intCompanyId undefined, change-password req.user.id, apiOrigin typo), align frontend types. Remove dead authMiddleware.
New /analytics page (recharts) backed by GET /api/analytics/summary (auth + company-scoped) with tested pure aggregation. Dashboard now shows real period-over-period deltas instead of hardcoded values.
Notification bell with unread badge + feed sourced from AuditLog via shared getScopedAuditLogs. Secures GET /api/audit (previously unauthenticated + unscoped) and adds GET /api/notifications.
Pluggable email layer with tested pure templates. Sends only when EMAIL_ENABLED=true and a key is set; never under tests.
Embedding helper, pgvector SQL migration + match_proposals RPC, backfill script, and Proposals UI that ranks by similarity with substring fallback. Inactive until the migration is run; see docs/SEMANTIC_SEARCH.md.
Mount analytics/notifications routers + production SPA serving in server.ts; add email-on-status-change and embed-on-create + /search to proposals.ts; add analytics/notifications/search API clients; add deps (helmet, rate-limit, vitest, supertest, resend) and email/embedding env vars.
Copilot AI review requested due to automatic review settings June 22, 2026 15:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR combines a production-readiness sweep (security hardening, CI/Docker, lint/typecheck cleanup, and a new test suite) with feature additions: an analytics dashboard, in-app notifications/activity feed, gated email notifications, and a semantic-search scaffold (pgvector + embeddings with graceful fallback).

Changes:

  • Added Vitest/Supertest test harness and new unit tests for compliance, analytics, auth/RBAC, notifications, and email template generation.
  • Implemented analytics summary API + new /analytics UI, plus notifications API + notification bell UI (sourced from AuditLog).
  • Added semantic search scaffolding (embeddings generator, pgvector SQL migration + backfill script, frontend debounced search) and introduced baseline security middleware (Helmet + rate limiting) and deployment artifacts (Docker/CI/docs).

Reviewed changes

Copilot reviewed 47 out of 48 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
vitest.config.ts Adds standalone Vitest config (Node env, aliasing, coverage).
tests/setup.ts Global env setup for deterministic tests (JWT/Azure/Supabase dummy config).
tests/notifications.test.ts Adds notifications endpoint tests with Supabase + scoped-audit mock.
tests/auth.test.ts Adds auth middleware, RBAC helper, and login endpoint tests.
src/pages/Proposals.tsx Adds debounced semantic search + similarity ranking fallback behavior.
src/pages/Integrations.tsx Fixes integration PATCH URL to use computed API base.
src/pages/Home.tsx Minor typing tweak to animation variants (as const).
src/pages/Dashboard.tsx Fetches real analytics deltas and renders trend badges conditionally.
src/pages/Compliance.tsx Switches Rule typing source and adjusts rule type handling.
src/pages/Audit.tsx Aligns AuditLog typing import with API client types.
src/pages/Analytics.tsx Adds new analytics dashboard page with recharts visualizations.
src/lib/api-client.ts Adds analytics/notifications clients and semantic search API call.
src/components/NotificationBell.tsx Adds polling notification bell + activity popover UI.
src/components/layout/ClientLayout.tsx Adds Analytics nav item and renders notification bell when logged in.
src/App.tsx Registers /analytics route behind ProtectedRoute.
src/api/proposals.ts Adds embeddings storage, semantic search endpoint, AI rate limiting, and status-change email hook.
src/api/oauth.ts Removes as any JWT cast in query auth and swaps console logs for logger.
src/api/notifications.ts Adds notifications API backed by scoped audit querying.
src/api/middleware/rateLimit.ts Introduces auth + AI rate limiters with relaxed non-prod limits.
src/api/lib/logger.ts Adds minimal leveled logger for API layer.
src/api/lib/embeddings.ts Adds Azure OpenAI embedding generation helper (best-effort).
src/api/lib/emailTemplates.ts Adds pure email template builder for status-change notifications.
src/api/lib/emailTemplates.test.ts Adds unit tests for email template correctness + HTML escaping.
src/api/lib/email.ts Adds gated Resend email sender (disabled in tests/CI).
src/api/lib/compliance.ts Extracts shared compliance/risk helpers + markdown renderer.
src/api/lib/compliance.test.ts Adds unit tests for compliance helpers and markdown conversion.
src/api/lib/auditQuery.ts Adds shared scoped audit querying used by audit + notifications routes.
src/api/lib/analytics.ts Adds pure analytics aggregation functions + delta calculations.
src/api/lib/analytics.test.ts Adds unit tests for analytics aggregation and delta logic.
src/api/integrations.ts Replaces console logs with logger and fixes integration sync scoping variable.
src/api/auth.ts Tightens JWT typing, fixes change-password user id lookup, removes legacy auth middleware.
src/api/audit.ts Secures audit endpoint with requireAuth and scoped querying.
src/api/analyze.ts Normalizes AI analysis output and centralizes auto-review threshold logic.
src/api/analytics.ts Adds analytics summary API endpoint with company scoping.
server.ts Adds Helmet, rate limiting on auth/AI endpoints, new routes, and production SPA serving.
scripts/backfill-embeddings.ts Adds embeddings backfill script for existing proposals.
prisma/schema.prisma Documents pgvector embedding column on Proposal.
prisma/manual/semantic_search.sql Adds pgvector extension, embedding column/index, and match_proposals RPC.
package.json Adds test/typecheck scripts and new deps (vitest/supertest/helmet/rate-limit/resend).
package-lock.json Locks dependency additions/updates for new tooling and features.
eslint.config.mjs Replaces broken Next.js eslint config with working Vite/TS flat config.
docs/SEMANTIC_SEARCH.md Documents semantic search setup and fallback behavior.
docs/DEPLOYMENT.md Adds deployment guide for Node/Docker, env config, and CI notes.
Dockerfile Adds multi-stage build and runtime Chromium install for PDF export.
docker-compose.yml Adds compose file for running the combined service on port 3001.
.github/workflows/ci.yml Adds CI workflow: install → prisma generate → lint → typecheck → test → build.
.env.example Documents embedding + email env vars and defaults.
.dockerignore Adds Docker context ignores, keeps .env.example.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/api/lib/compliance.ts
Comment on lines +73 to +82
/**
* Convert a subset of markdown to HTML for rendering. Note: this does NOT
* escape HTML — callers that embed untrusted content elsewhere must escape
* separately. Preserved verbatim from the proposal PDF renderer.
*/
export function markdownToHtml(text: string): string {
if (!text) return '';

let html = text;

Comment thread src/api/proposals.ts
Comment on lines +138 to +145
// Company scoping: admins search everything, others their company only.
const filterCompany = isAdmin(req) ? null : req.user?.companyId ?? null;

const { data, error } = await supabase.rpc('match_proposals', {
query_embedding: queryEmbedding,
match_count: 20,
filter_company: filterCompany,
});
Comment thread src/api/analytics.ts
Comment on lines +32 to +34
if (!isAdmin(req) && req.user?.companyId) {
query = query.eq('company_id', req.user.companyId);
}
Comment thread src/api/lib/auditQuery.ts
Comment on lines +66 to +71
const { data: companyProposals } = await supabase
.from('Proposal')
.select('id')
.eq('company_id', companyId);
const ids = (companyProposals || []).map((p: { id: string }) => p.id);

Comment thread package.json
Comment on lines 118 to +119
"vite": "^5.4.19",
"vitest": "^4.1.9",
Add render.yaml Blueprint (Docker web service, auto-generated NEXTAUTH_SECRET, secrets via dashboard). Server now binds Render's injected PORT; Docker healthcheck is port-aware. Document the Render deploy flow.
@rogerdemello
rogerdemello merged commit 27701a2 into main Jun 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants