Skip to content

Phase 7: Upgrade AdminPortal from Angular 4 to Angular 18 - #52

Open
devin-ai-integration[bot] wants to merge 2 commits into
devin/1783889887-phase5-backend-upgradefrom
devin/1783891000-phase7-angular-upgrade
Open

devin-ai-integration[bot] wants to merge 2 commits into
devin/1783889887-phase5-backend-upgradefrom
devin/1783891000-phase7-angular-upgrade

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 12, 2026

Copy link
Copy Markdown

Summary

Modernize the AdminPortal SPA from Angular 4 → Angular 18 (stacked on the Phase 5/6 PR #51). Given 14 major versions of drift, this re-scaffolds a fresh Angular 18 standalone CLI project and ports the components/services over (the alternative the plan allowed), rather than an unreliable 14-hop ng update. Behavior and routes are preserved; the legacy @angular/http + RxJS 5 patterns are gone.

Framework / structure

  • Standalone bootstrap: bootstrapApplication(AppComponent, appConfig); app.config.ts provides provideRouter(routes) + provideHttpClient(withXsrfConfiguration({cookieName:'XSRF-TOKEN', headerName:'X-XSRF-TOKEN'})). AppModule/app.routing.ts removed; every component is standalone: true with explicit imports.

HTTP: @angular/http@angular/common/http

-import { Http } from '@angular/http';
-this.http.get(url, { withCredentials: true })  // then JSON.parse(JSON.parse(JSON.stringify(res))._body)
+import { HttpClient } from '@angular/common/http';
+this.http.get<User[]>(url, { withCredentials: true })  // typed body used directly

The old _body string-parsing hack is deleted; services return typed Observable<User[] | Transaction[] | Appointment[]> (new models.ts). Backend base URL centralized in environments/environment*.ts (apiBaseUrl). Security-relevant Phase 4 behavior kept: credentials in encoded POST body (not URL), usernames as path variables, enable/disable via POST.

RxJS 5 → 7 & guard

  • rxjs/add/operator/* imports → pipeable map/catchError/of.
  • AuthGuard implements CanActivate class → functional authGuard: CanActivateFn using inject() (auth.guard.ts), same server-session check against /api/user/all.
  • Data fetching moved from constructors into ngOnInit.

Testing (now a hard CI gate)

  • Unit specs rewritten for Angular 18 TestBed + HttpTestingController (assert URLs/verbs/body — e.g. encoded login body, path-variable transaction URLs). 14 specs pass under ChromeHeadlessCI.
  • Protractor → Playwright: e2e/smoke.spec.ts boots the app and asserts / redirects to /login and renders the form. playwright.config.ts serves the build via webServer.
  • CI: frontend job → Node 20, ng test no longer continue-on-error (blocking); new e2e job runs Playwright.
  • Dropped auth0-js (was never imported).

Security posture

npm audit: 148 vulns (34 critical) → 54 (0 critical). The remaining 8 production highs are Angular-18 framework advisories fixed only in Angular 19+/21 (a breaking bump) — tracked as a follow-up; the rest are dev-only build tooling.

Follow-up / coordination

  • Cross-origin SPA↔backend with the CSRF now enabled in Phase 6: provideHttpClient(withXsrfConfiguration(...)) matches Spring's cookie/header names, but Angular only attaches the token to same-origin requests. The /api/** calls work because Phase 6 exempts that namespace; the /index form login remains the known cross-origin CSRF gap to resolve when frontend/backend origins are unified.

Verified locally: ng build, 14 unit tests headless, Playwright smoke test — all green.

AdminPortal login on Angular 18

Link to Devin session: https://app.devin.ai/sessions/82be2e41fda54343a20a9b73e01c0631
Requested by: @gaelkekatos-jpg


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)

Re-scaffold as a fresh Angular 18 standalone CLI project and port the
components/services over:

- Standalone bootstrap (bootstrapApplication + app.config.ts), provideRouter,
  provideHttpClient with XSRF config; drop NgModule/app.module.ts
- Migrate @angular/http (HttpModule/Http) to @angular/common/http HttpClient;
  responses are typed and used directly (drop the JSON.parse(_body) hack)
- RxJS 5 -> RxJS 7 pipeable operators (map/catchError/of)
- Convert AuthGuard to a functional CanActivateFn (auth.guard.ts)
- Introduce typed models (User/Transaction/Appointment) for strict templates
- Move data fetching from constructors into ngOnInit
- Centralize backend base URL in environments (apiBaseUrl)
- Replace Protractor e2e with Playwright (smoke test) and add typed specs;
  unit tests migrated to Angular 18 TestBed with HttpTestingController
- CI: Node 20, unit tests are now a hard gate (ChromeHeadlessCI), plus a
  Playwright e2e job; drop auth0-js (unused)

npm audit: 148 vulns (34 critical) -> 54 (0 critical). Remaining prod-highs are
Angular 18 framework advisories fixed only in 19+/21 (breaking bump, follow-up).

Verified: ng build, 14 unit tests pass headless, Playwright smoke test passes.
Co-Authored-By: Gael Kekatos <gael.kekatos@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

The previous lockfile was produced by an npm install that npm ci rejected
(chokidar/readdirp tree inconsistency), failing CI on 'npm ci'. Regenerated a
consistent lockfile; verified npm ci passes under both npm 10 and 11.

Co-Authored-By: Gael Kekatos <gael.kekatos@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

E2E test results — Angular 18 SPA against live Spring Boot 3.3 backend

Ran AdminPortal (ng serve :4200) against a live UserFront (Spring Boot 3.3.5 / Java 17 / Spring Security 6) on H2 :8080, seeded with a test-only admin + 2 users + transactions + 1 appointment. Drove the full admin workflow through the real browser.

All 7 UI tests passed.

# Test Result
T1 //login; Angular 18 login page renders
T2 Route guard redirects unauthenticated /userAccount/login
T3 Admin login via SPA (POST /index, creds in body)
T4 User list loads from /api/user/all
T5 Primary transactions load (/primaryTransaction/john)
T6 Disable + Enable user round-trip via POST
T7 Appointment listing + Confirm (false→true)
Key evidence — user listing + admin actions working via HttpClient

User list from /api/user/all (john: Primary 1750.5, Savings 800, Enabled true):

user list

Disable user via POST (mary Enabled → false, action → "Enable"):

disable

Appointment confirmed (false → true, Confirm link removed):

appointment confirmed

Findings to address (not blockers for this PR)
  • F1 — SPA login blocked as-is by CSRF. With committed csrf.ignoringRequestMatchers("/api/**"), cross-origin POST /index from the SPA returns 403. I used a test-only, uncommitted /index exemption to proceed. This is the known Phase 7 follow-up (full SPA CSRF-token handling).
  • F2 — No admin creatable via UI. All /api/** require ROLE_ADMIN, but signup only grants ROLE_USER; admin was seeded directly (test-only). Confirmed ROLE_USER correctly gets 403 on /api/user/all.
  • Env: MySQL unavailable on the box → backend run on H2. All test-only changes (H2 scope, seeder, CSRF exemption) reverted; working tree clean.

Devin session

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.

0 participants