|
1 | 1 | ### Description |
2 | 2 |
|
3 | | -This directory will hold `lambda@edge` functions. |
| 3 | +This directory holds `lambda@edge` functions deployed to CloudFront as `origin-request` handlers. |
4 | 4 |
|
5 | | -`forwarder` - lambda function that sits infront of the CDN, handles `globalization` redirection. |
6 | | -`versioner` - function to create lambda function version. |
| 5 | +`forwarder` - rewrites incoming CloudFront URIs to the correct S3 object keys for the Angular i18n locale builds. |
| 6 | +`versioner` - creates a numbered Lambda version ARN that CloudFront requires for Lambda@Edge associations. |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +### i18n / Angular Build Output Dependency |
| 11 | + |
| 12 | +The `forwarder` function is **tightly coupled** to the Angular build output directory structure. Breaking this coupling causes S3 `AccessDenied` (403) errors surfaced as raw XML to end users. |
| 13 | + |
| 14 | +#### How Angular i18n builds are deployed |
| 15 | + |
| 16 | +`projects/v3` is compiled with `"localize": true` in `angular.json`, producing one subfolder per locale: |
| 17 | + |
| 18 | +| Angular version | Build output path | S3 object key prefix | |
| 19 | +|-----------------|-------------------|----------------------| |
| 20 | +| 17 / 18 (webpack builder) | `dist/v3/{locale}/` | `/{locale}/` | |
| 21 | +| **19+ (application builder)** | `dist/v3/browser/{locale}/` | `/browser/{locale}/` | |
| 22 | + |
| 23 | +The `aws s3 sync dist/v3/ s3://$BUCKET --delete` step (CI/CD step 22) mirrors this structure directly into S3, so the S3 key prefix always matches the build output. |
| 24 | + |
| 25 | +#### What the forwarder does |
| 26 | + |
| 27 | +CloudFront does **not** forward query strings to S3 (`QueryString: false`). When a user visits a deep-link such as `/en-US?auth_token=…`, CloudFront calls the forwarder with `request.uri = "/en-US"`. The forwarder: |
| 28 | + |
| 29 | +1. Extracts the first path segment as the locale (`en-US`, `ja`, `ms`, `es`). |
| 30 | +2. For unknown locales or bare `/`, falls back to the default locale. |
| 31 | +3. For SPA routes (no file extension), rewrites to `/{prefix}/{locale}/index.html`. |
| 32 | +4. For static assets (with file extension), rewrites to `/{prefix}{original_uri}`. |
| 33 | +5. Passes `version.json` requests through unchanged (whitelist). |
| 34 | + |
| 35 | +#### Supported locales |
| 36 | + |
| 37 | +The locale whitelist in `forwarder/index.js` must stay in sync with the locales configured in `angular.json`: |
| 38 | + |
| 39 | +```javascript |
| 40 | +const locales = ["en-US", "ja", "ms", "es"]; |
| 41 | +``` |
| 42 | + |
| 43 | +To add a new locale: update both `angular.json` (`i18n.locales`) **and** the `locales` array in `forwarder/index.js`. |
| 44 | + |
| 45 | +#### ⚠️ What to check on every Angular major version upgrade |
| 46 | + |
| 47 | +When upgrading Angular major versions, verify the build output structure has not changed before deploying: |
| 48 | + |
| 49 | +```bash |
| 50 | +# after building, check what subdirectories are produced |
| 51 | +ls dist/v3/ |
| 52 | +# Angular 19+: should show browser/ |
| 53 | +# Angular 17/18: should show en-US/ ja/ ms/ es/ |
| 54 | +``` |
| 55 | + |
| 56 | +If the output structure changes, update the path prefix in `forwarder/index.js` **before** merging to trunk so both changes deploy together in the same CI/CD run. |
| 57 | + |
| 58 | +#### Incident history |
| 59 | + |
| 60 | +| Date | Trigger | Symptom | Fix | |
| 61 | +|------|---------|---------|-----| |
| 62 | +| March 2026 | Angular 18 → 19 upgrade | S3 `AccessDenied` XML shown to all users on `app.p2-stage.practera.com` | Added `/browser/` prefix to all rewritten URIs in `forwarder/index.js` | |
| 63 | + |
| 64 | +--- |
7 | 65 |
|
8 | 66 | ### Deployment |
9 | 67 |
|
10 | | -Once `AWS` credentials is ready, just run `deploy.sh`. Make sure you installed [sam](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) on your machine. |
| 68 | +Once `AWS` credentials are ready, run `deploy.sh`. Requires [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html). |
| 69 | + |
| 70 | +In CI/CD (`p2-stage-appv3.yml`) the deploy sequence is: |
| 71 | +1. Build Angular app (`ng build v3`) |
| 72 | +2. Deploy Lambda@Edge (`bash lambda/deploy.sh`) → exports `HandlerVersionArn` |
| 73 | +3. Deploy CloudFormation/Serverless stack (picks up new `HandlerVersionArn`) |
| 74 | +4. Sync `dist/v3/` to S3 |
| 75 | + |
| 76 | +Both the Lambda function and the S3 content must reflect the same output path structure. |
0 commit comments