Skip to content

Commit af64ac3

Browse files
committed
WEB-547 feat(proxy): forward /fineract-provider to sandbox; add localhost sample and README MD034 fixes
1 parent e52691b commit af64ac3

File tree

4 files changed

+224
-25
lines changed

4 files changed

+224
-25
lines changed

README.md

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Mifos X Web App is a modern single-page application (SPA) built on top of the Mi
1212

1313
## Quick Links
1414

15-
- [Live Demo](https://sandbox.mifos.community/#/login) (Updated nightly ** System is restored every 6 hours **)
15+
- [Live Demo](https://sandbox.mifos.community/#/login) (Updated nightly — sandbox data is reset every 6 hours; test data and transient state may be cleared.)
1616
- [GitHub Repository](https://github.com/openMF/web-app)
1717
- [Slack Channel](https://app.slack.com/client/T0F5GHE8Y/CJJGJLN10)
1818
- [Jira Board of Mifos](https://mifosforge.jira.com/jira/your-work)
@@ -31,13 +31,13 @@ Before installing the web app, you need to set up the Fineract backend server:
3131

3232
1. **Choose ONE of these backend options:**
3333
- **Option A: Use existing remote server**
34-
- Use the sandbox (MariaDB) at https://sandbox.mifos.community ** System is restored every 6 hours **
35-
- Use the demo (MariaDB) at https://demo.mifos.community
36-
- Use the demo (Keycloak) at https://oauth.mifos.community
37-
- Use the demo (2FA) at https://2fa.mifos.community
38-
- Use the demo (Oidc) at https://oidc.mifos.community
39-
- Use the demo (Postgres) at https://elephant.mifos.community
40-
- Configure to your server by updating API URLs in environment files
34+
- Use the [sandbox (MariaDB)](https://sandbox.mifos.community) — sandbox data is reset every 6 hours; test data and transient state may be cleared.
35+
- Use the [demo (MariaDB)](https://demo.mifos.community)
36+
- Use the [demo (Keycloak)](https://oauth.mifos.community)
37+
- Use the [demo (2FA)](https://2fa.mifos.community)
38+
- Use the [demo (Oidc)](https://oidc.mifos.community)
39+
- Use the [demo (Postgres)](https://elephant.mifos.community)
40+
- Configure to your server by updating API URLs in environment files
4141

4242
- **Option B: Install local Fineract server**
4343

@@ -132,6 +132,101 @@ When using the development server with basic authentication:
132132
- **Build for production:** `ng build --configuration production` or `npm run build:prod`
133133
- **Get Angular CLI help:** `ng help`
134134

135+
## Proxy Configuration
136+
137+
The web app includes a proxy configuration (`proxy.conf.js`) that allows you to forward API requests to a remote Fineract backend during local development. This helps avoid CORS issues and enables you to work against production-like environments.
138+
139+
### Using the Sandbox Proxy (Default)
140+
141+
By default, the proxy forwards `/fineract-provider` requests to the Mifos sandbox environment:
142+
143+
- **Target:** `https://sandbox.mifos.community`
144+
- **API Endpoint:** `https://apis.mifos.community` (exposed in the sandbox)
145+
- **System Reset:** Sandbox test data and transient state are reset every 6 hours (expect data to be periodically cleared).
146+
147+
**Sandbox Environment Variables:**
148+
149+
```bash
150+
FINERACT_API_URLS=https://apis.mifos.community
151+
FINERACT_API_URL=https://apis.mifos.community
152+
FINERACT_API_PROVIDER=/fineract-provider/api
153+
FINERACT_API_ACTUATOR=/fineract-provider
154+
FINERACT_API_VERSION=/v1
155+
FINERACT_PLATFORM_TENANT_IDENTIFIER=default
156+
MIFOS_DEFAULT_LANGUAGE=en-US
157+
MIFOS_SUPPORTED_LANGUAGES=cs-CS,de-DE,en-US,es-MX,fr-FR,it-IT,ko-KO,lt-LT,lv-LV,ne-NE,pt-PT,sw-SW
158+
MIFOS_PRELOAD_CLIENTS=true
159+
MIFOS_DEFAULT_CHAR_DELIMITER=,
160+
```
161+
162+
### Using a Local Fineract Instance
163+
164+
To proxy to a local Fineract server instead:
165+
166+
Use the provided localhost proxy file (recommended for `ng serve`):
167+
168+
1. Start the dev server with the localhost proxy:
169+
170+
```bash
171+
ng serve --proxy-config proxy.localhost.conf.js
172+
```
173+
174+
2. Ensure your local Fineract instance is running on `http://localhost:8443`.
175+
176+
Notes:
177+
178+
- `proxy.localhost.conf.js` forwards `/fineract-provider` to your local backend to avoid CORS during development.
179+
- The `HttpsProxyAgent` / `setupForProxy` logic (present in `proxy.conf.js`) is only necessary when an upstream corporate/HTTP proxy must be used (set via `HTTP_PROXY`/`http_proxy`). It is not required for a direct `localhost` backend.
180+
181+
### Proxy Features
182+
183+
- **CORS Avoidance:** Eliminates cross-origin issues during local development
184+
- **Error Handling:** Gracefully handles proxy failures with detailed logging
185+
- **Corporate Proxy Support:** Maintains support for corporate proxy agents via `HTTP_PROXY` environment variable
186+
- **Debug Logging:** All proxy requests are logged for troubleshooting
187+
188+
The proxy is configured to work with Fineract endpoints as described in this section.
189+
190+
### Testing the Proxy
191+
192+
To verify the proxy is working correctly, start the development server (`ng serve`) and test with curl:
193+
194+
**Successful proxy request:**
195+
196+
```bash
197+
curl -i "http://localhost:4200/fineract-provider/api/v1/runreports/FullClientReport?R_officeId=1&output-type=HTML&R_loanOfficerId=-1"
198+
```
199+
200+
Expected: HTTP 200 response with proxied data from the sandbox. Server console shows:
201+
202+
```text
203+
[Proxy] Proxying: GET /fineract-provider/api/v1/runreports/... -> https://sandbox.mifos.community/api/v1/runreports/...
204+
```
205+
206+
**Simulated proxy error (backend unreachable):**
207+
208+
If the backend is unreachable or returns an error, the proxy returns HTTP 502:
209+
210+
```bash
211+
# Stop your Fineract backend (if using localhost) or test with an invalid target
212+
# The proxy will log the error and return:
213+
```
214+
215+
Server console (example):
216+
217+
```text
218+
[Proxy] Error while proxying request: GET /fineract-provider/... -> https://sandbox.mifos.community - ECONNREFUSED
219+
```
220+
221+
HTTP response:
222+
223+
```http
224+
HTTP/1.1 502 Bad Gateway
225+
Content-Type: text/plain
226+
227+
Proxy error: connect ECONNREFUSED
228+
```
229+
135230
## Configuration Options
136231

137232
### Environment Variables for Docker
@@ -166,7 +261,7 @@ Available languages:
166261
| French | fr | fr-FR.json |
167262
| Italian | it | it-IT.json |
168263
| Korean | ko | ko-KO.json |
169-
| Lithuanian | li | li-LI.json |
264+
| Lithuanian | lt | lt-LT.json |
170265
| Latvian | lv | lv-LV.json |
171266
| Nepali | ne | ne-NE.json |
172267
| Portuguese | pt | pt-PT.json |

docs/backend-proxy.md

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,72 @@ The interesting part is there:
1818
```js
1919
const proxyConfig = [
2020
{
21-
context: '/api',
22-
pathRewrite: { '^/api': '' },
23-
target: 'https://api.chucknorris.io',
24-
changeOrigin: true
21+
context: ['/fineract-provider'],
22+
target: 'https://sandbox.mifos.community',
23+
pathRewrite: { '^/fineract-provider': '' },
24+
changeOrigin: true,
25+
secure: true,
26+
logLevel: 'debug',
27+
onProxyReq: function (proxyReq, req, res) {
28+
// Log the rewritten path so the console shows the actual forwarded URL
29+
const rewrittenPath = (req.url || '').replace(/^\/fineract-provider/, '');
30+
console.log('[Proxy] Proxying:', req.method, req.url, '->', this.target + rewrittenPath);
31+
},
32+
onError: function (err, req, res) {
33+
// Log proxy errors and return HTTP 502 to the client
34+
console.error('[Proxy] Error while proxying request:', req.method, req.url, '->', this.target, '-', err.message);
35+
if (res && !res.headersSent) {
36+
res.writeHead(502, { 'Content-Type': 'text/plain' });
37+
res.end('Proxy error: ' + err.message);
38+
}
39+
}
2540
}
2641
];
2742
```
2843

29-
This is where you can setup one or more proxy rules.
44+
This forwards requests sent to `/fineract-provider/...` on the dev server to the Fineract backend root (for example,
45+
`/fineract-provider/1.0/...` becomes `https://sandbox.mifos.community/1.0/...`). Use `pathRewrite` to strip the prefix
46+
because the sandbox exposes Fineract APIs at the root path.
47+
48+
**Error Handling:**
49+
50+
The `onError` handler captures proxy failures (network errors, backend unreachable, timeouts, etc.) and:
51+
52+
- Logs detailed error information to the server console (method, URL, target, error message)
53+
- Returns HTTP 502 (Bad Gateway) to the client with a plain-text error message
54+
55+
Example server console output when proxy fails:
56+
57+
```text
58+
[Proxy] Error while proxying request: GET /fineract-provider/api/v1/clients -> https://sandbox.mifos.community - ECONNREFUSED
59+
```
60+
61+
Example client response:
62+
63+
```http
64+
HTTP/1.1 502 Bad Gateway
65+
Content-Type: text/plain
66+
67+
Proxy error: connect ECONNREFUSED
68+
```
69+
70+
You can add multiple rules or change the `target` to point to other environments (demo, localhost, etc.).
3071

3172
For the complete set of options, see the `http-proxy-middleware`
3273
[documentation](https://github.com/chimurai/http-proxy-middleware#options).
3374

3475
### Corporate proxy support
3576

36-
To allow external API calls redirection through a corporate proxy, you will also find a `setupForCorporateProxy()`
37-
function in the proxy configuration file. By default, this method configures a corporate proxy agent based on the
38-
`HTTP_PROXY` environment variable, see the [corporate proxy documentation](corporate-proxy.md) for more details.
77+
The repository configures a helper function in `proxy.conf.js` named `setupForProxy` which will attach an
78+
`HttpsProxyAgent` to proxy entries when the `HTTP_PROXY` (or `http_proxy`) environment variable is present. This lets
79+
the dev server forward requests through a corporate proxy when required.
80+
81+
**Behavior:**
82+
83+
- **When `HTTP_PROXY` is set:** Logs `"Using proxy server: <url>"` and configures the agent for corporate proxy forwarding
84+
- **When `HTTP_PROXY` is not set:** Logs `"No proxy server configured. API requests will not be proxied."` — note that this refers only to corporate proxy forwarding; the Angular dev server proxy (forwarding `/fineract-provider` to the sandbox) still works normally
3985

40-
If you need to, you can further customize this function to fit the network of your working environment.
86+
See `proxy.conf.js` for the exact implementation.
4187

42-
If your corporate proxy use a custom SSL certificate, your may need to add the `secure: false` option to your
43-
backend proxy configuration.
88+
If your corporate proxy uses a custom SSL certificate you may need to set `secure: false` on the specific proxy entry
89+
or configure your environment to trust the corporate CA.

proxy.conf.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,41 @@
22

33
const { HttpsProxyAgent } = require('https-proxy-agent');
44

5-
/*
5+
/* IMPORTANT:
66
* API proxy configuration.
77
* This allows you to proxy HTTP request like `http.get('/api/stuff')` to another server/port.
88
* This is especially useful during app development to avoid CORS issues while running a local server.
99
* For more details and options, see https://github.com/angular/angular-cli#proxy-to-backend
1010
*/
1111
const proxyConfig = [
1212
{
13-
context: '/api',
14-
pathRewrite: { '^/api': '' },
15-
target: 'https://api.chucknorris.io',
13+
context: ['/fineract-provider'],
14+
target: 'https://sandbox.mifos.community',
15+
pathRewrite: { '^/fineract-provider': '' },
1616
changeOrigin: true,
17-
secure: false
17+
secure: true,
18+
logLevel: 'debug',
19+
onProxyReq: function (proxyReq, req, res) {
20+
const rewrittenPath = (req.url || '').replace(/^\/fineract-provider/, '');
21+
console.log('[Proxy] Proxying:', req.method, req.url, '->', this.target + rewrittenPath);
22+
},
23+
onError: function (err, req, res) {
24+
console.error(
25+
'[Proxy] Error while proxying request:',
26+
req && req.method,
27+
req && req.url,
28+
'->',
29+
this.target,
30+
'-',
31+
err && err.message
32+
);
33+
if (res && !res.headersSent) {
34+
res.writeHead(502, { 'Content-Type': 'text/plain' });
35+
res.end('Proxy error: ' + (err && err.message ? err.message : 'Unknown error'));
36+
}
37+
}
1838
}
39+
// For local development use `proxy.localhost.conf js` .
1940
];
2041

2142
/*

proxy.localhost.conf.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
/**
4+
* Proxy configuration for running the app against a local Fineract instance.
5+
* Usage:
6+
* ng serve --proxy-config proxy.localhost.conf.js
7+
*/
8+
9+
module.exports = [
10+
{
11+
context: ['/fineract-provider'],
12+
target: 'http://localhost:8443',
13+
pathRewrite: { '^/fineract-provider': '' },
14+
changeOrigin: true,
15+
secure: false,
16+
logLevel: 'debug',
17+
onProxyReq: function (proxyReq, req, res) {
18+
const rewrittenPath = (req.url || '').replace(/^\/fineract-provider/, '');
19+
console.log('[Proxy] Proxying:', req.method, req.url, '->', this.target + rewrittenPath);
20+
},
21+
onError: function (err, req, res) {
22+
console.error(
23+
'[Proxy] Error while proxying request:',
24+
req && req.method,
25+
req && req.url,
26+
'->',
27+
this.target,
28+
'-',
29+
err && err.message
30+
);
31+
if (res && !res.headersSent) {
32+
res.writeHead(502, { 'Content-Type': 'text/plain' });
33+
res.end('Proxy error: ' + (err && err.message ? err.message : 'Unknown error'));
34+
}
35+
}
36+
}
37+
];

0 commit comments

Comments
 (0)