A multi-tenant financial analytics platform with natural language querying powered by OpenAI, built on Spring Boot and React. Achieved a 98 Lighthouse performance score with sub-200ms API responses.
Portfolio rebuild — inspired by production work at Power R&D Consultants. Business-sensitive data and logic replaced with anonymised equivalents.
Screenshots / GIF to be added
Ask questions in plain English — the backend translates them into safe, parameterised SQL via OpenAI function calling.
User: "Show me revenue trends for Q1 vs Q2 broken down by region"
→ GPT generates structured query parameters
→ Backend executes safe parameterised query
→ Frontend renders animated chart
- Row-level security (RLS) enforced at the PostgreSQL level — not just application logic
- Each tenant's data is completely isolated; a misconfigured query cannot leak cross-tenant data
- JWT-based auth with tenant context embedded in every request
- Sub-200ms API responses via query result caching, connection pooling (HikariCP), and N+1 elimination
- 98 Lighthouse score — code splitting, lazy loading, progressive chart rendering
- Optimistic UI updates — charts update immediately on filter change, confirmed on response
┌──────────────────────────────────────────┐
│ React Frontend │
│ (TypeScript, Redux, Recharts) │
└───────────────┬──────────────────────────┘
│ HTTPS / REST
┌───────────────▼──────────────────────────┐
│ Spring Boot API │
│ ┌─────────────────┐ ┌───────────────┐ │
│ │ NL Query │ │ Auth / JWT │ │
│ │ Service │ │ + Tenant │ │
│ │ (OpenAI) │ │ Resolver │ │
│ └────────┬────────┘ └───────────────┘ │
└───────────┼──────────────────────────────┘
│
┌───────────▼──────────────────────────────┐
│ PostgreSQL │
│ • Row-level security per tenant │
│ • Materialised views for aggregations │
│ • Indexed on tenant_id + date columns │
└──────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Redux Toolkit, Recharts |
| Backend | Java 17, Spring Boot 3, Spring Security |
| AI | OpenAI GPT-4o (function calling for NL→SQL) |
| Database | PostgreSQL 15 with RLS |
| Cache | Redis (query result cache) |
| Auth | JWT + Spring Security |
| Testing | JUnit 5, Mockito, Jest, Cypress |
- Java 17+, Node.js 18+, Docker
- OpenAI API key
cp backend/.env.example backend/.env
# Add your OPENAI_API_KEY to .envdocker-compose up -d postgres redis
cd backend && ./mvnw spring-boot:run
cd frontend && npm install && npm run devcd backend && ./mvnw test
cd frontend && npm test
cd frontend && npm run cypress:open # E2EThe natural language feature uses OpenAI function calling (not raw prompt-to-SQL), which means:
- The model fills structured parameters, not raw SQL strings
- The backend builds the actual query — SQL injection is impossible
- Responses are deterministic and validatable
// Simplified example of the function calling approach
ChatFunction queryFunction = ChatFunction.builder()
.name("build_financial_query")
.description("Build a financial data query from user intent")
.executor(FinancialQueryParams.class, params -> executeQuery(params))
.build();Row-level security is enforced at the database level:
-- Each table has RLS enabled
ALTER TABLE financial_records ENABLE ROW LEVEL SECURITY;
-- Policy ensures tenants only see their own data
CREATE POLICY tenant_isolation ON financial_records
USING (tenant_id = current_setting('app.current_tenant')::uuid);The Spring backend sets app.current_tenant from the JWT on every connection — not in application code where it could be bypassed.
- Lighthouse 98 achieved via: route-based code splitting, deferred chart library loading, skeleton screens, and pre-fetching on hover
- API p95 < 200ms via: Redis query cache (5-min TTL), HikariCP connection pool (20 connections), materialised views for expensive aggregations
Shreya H S — Full Stack Software Engineer, London
LinkedIn · GitHub