feat: Add FaceAI integration with handoff and return functionality
- Introduced a new workspace for FaceAI in package.json. - Implemented FaceAI handoff logic in faceai_handoff.php, including identity verification and token signing. - Created faceai_return.php to handle return requests from FaceAI, validating tokens and forwarding results. - Developed faceai_simulator.php and faceai_simulator_view.php for simulating the FaceAI interface with demo photos. - Enhanced rus-ecom-240621.js to support new FaceAI features, including dynamic URL building and button integration. - Added faceai_config.php for configuration management, including environment variable handling and utility functions. - Updated HTML structure and styles in simulator view for better user experience.
This commit is contained in:
parent
f65a85dcc9
commit
da362c201f
31 changed files with 4511 additions and 60 deletions
|
|
@ -9,9 +9,10 @@ The new app will:
|
|||
- start from the race photo view page
|
||||
- search only within the current race
|
||||
- accept a selfie upload
|
||||
- show matched race photos with previews
|
||||
- let the user open and download photos through the existing legacy download flow
|
||||
- fall back to email delivery when the queue is long or processing is slow
|
||||
- process the request inside FaceAI
|
||||
- return the user to the original race page with the results filtered to only the matched images
|
||||
- keep photo opening and downloading entirely on the legacy site
|
||||
- use polling only in v1 if processing takes time
|
||||
|
||||
## What Exists Today
|
||||
|
||||
|
|
@ -31,11 +32,15 @@ The legacy site identity is held in the Java web session, not in PHP. That means
|
|||
|
||||
Because of that, the recommended plan needs one of these two options:
|
||||
|
||||
1. Preferred: a very small server-side bridge on the legacy Java side, or at the reverse proxy level with app support, to mint a trusted handoff token for FaceAI.
|
||||
1. Preferred: a very small server-side bridge on the legacy Java or JSP side, or at the reverse proxy level with app support, to mint a trusted handoff token for FaceAI.
|
||||
2. Fallback: a separate login flow for FaceAI.
|
||||
|
||||
If the requirement is strict single sign-on based on the current site session, option 1 is the only realistic path.
|
||||
|
||||
There is also an operational constraint from the implementation side:
|
||||
|
||||
The bridge should be designed so it can be deployed without setting up a full local Java development environment and without recompiling the existing application locally. That makes a tiny JSP-based handoff endpoint or a minimal existing-controller extension preferable to adding new compiled Java modules.
|
||||
|
||||
## Recommended Architecture
|
||||
|
||||
Use three deployable parts:
|
||||
|
|
@ -49,6 +54,7 @@ Use three deployable parts:
|
|||
- Keep authentication, membership checks, and download-credit subtraction as the source of truth.
|
||||
- Launch the FaceAI app from the race page.
|
||||
- Issue a short-lived signed handoff token that identifies the user and race context.
|
||||
- Accept the final FaceAI match result and turn it into a legacy race-page filter.
|
||||
- Continue to serve original photo downloads so existing counters and permissions remain unchanged.
|
||||
|
||||
### 2. FaceAI app responsibilities
|
||||
|
|
@ -58,7 +64,8 @@ Use three deployable parts:
|
|||
- Let the user upload a selfie.
|
||||
- Create a race-scoped search request.
|
||||
- Poll job status or show queued state.
|
||||
- Render matched photos and route download/open actions back to legacy endpoints.
|
||||
- Return a stable list of matched legacy photo identifiers.
|
||||
- Redirect the user back to the legacy race page with a filter payload that reproduces the matched set.
|
||||
- Preserve the page the user came from and offer a one-click return.
|
||||
|
||||
### 3. Processing service responsibilities
|
||||
|
|
@ -67,7 +74,7 @@ Use three deployable parts:
|
|||
- Queue requests and process them one by one.
|
||||
- Run the external face-recognition program.
|
||||
- Return match results with confidence and photo ids or file identifiers.
|
||||
- Mark long-running jobs for async completion and email fallback.
|
||||
- Return a completed result set usable by the legacy filter handoff.
|
||||
|
||||
## Authentication And Cookie Strategy
|
||||
|
||||
|
|
@ -96,6 +103,16 @@ Instead:
|
|||
|
||||
This gives the new app shared-domain cookies while avoiding direct dependency on the Java session internals.
|
||||
|
||||
### Preferred bridge implementation shape
|
||||
|
||||
Given the local environment constraint, the bridge should preferably be one of these:
|
||||
|
||||
- a tiny JSP endpoint that reads the existing session beans and performs a redirect
|
||||
- a minimal addition to an already-existing legacy action/controller endpoint
|
||||
- a reverse-proxy-assisted signed redirect if the platform already supports auth subrequests
|
||||
|
||||
Avoid a plan that requires introducing new compiled Java packages as the first step.
|
||||
|
||||
## Access Check
|
||||
|
||||
The handoff token should already include whether the feature is allowed. That check should be done on the legacy side where the real account state already exists.
|
||||
|
|
@ -104,8 +121,6 @@ Minimal validation inputs:
|
|||
|
||||
- logged-in user exists
|
||||
- account is active enough to use the feature
|
||||
- race is eligible for FaceAI
|
||||
- optional plan or quota flag for face search access
|
||||
|
||||
To avoid unnecessary database reads, compute this from already-loaded session/account state when possible. Only hit the database if the existing session object does not contain enough information.
|
||||
|
||||
|
|
@ -115,14 +130,15 @@ The smallest practical change set on the legacy site is:
|
|||
|
||||
### Frontend change
|
||||
|
||||
Do not replace the dropdown in JSP markup first.
|
||||
Remove the old `tipoPuntoFoto` select from the user flow and replace it with the FaceAI launch button.
|
||||
|
||||
Instead, update `www/_js/rus-ecom-240621.js` so that on the race page it:
|
||||
The lowest-risk way to do that is to update `www/_js/rus-ecom-240621.js` so that on the race page it:
|
||||
|
||||
- detects `#tipoPuntoFoto`
|
||||
- hides or disables that select for eligible races
|
||||
- removes that select from the rendered UI
|
||||
- inserts a `Face ID` button in the same area
|
||||
- builds the launch URL using the current race context and current page URL
|
||||
- carries `raceId`, race description or slug, language, and exact `returnUrl`
|
||||
|
||||
This avoids fragile JSP layout edits and keeps the change deployable as a single JS asset update.
|
||||
|
||||
|
|
@ -137,12 +153,23 @@ Add one minimal auth bridge endpoint on the legacy stack. It can be:
|
|||
That endpoint should:
|
||||
|
||||
- read the current legacy session
|
||||
- verify the user and access
|
||||
- verify the user and active-membership access
|
||||
- generate the signed handoff token
|
||||
- redirect to FaceAI
|
||||
|
||||
If this endpoint truly cannot be added, then single sign-on should be considered blocked and the plan should switch to a separate login flow.
|
||||
|
||||
### Legacy return filter change
|
||||
|
||||
The old site needs one small return-integration path so FaceAI can send the user back to the race page showing only the matched images.
|
||||
|
||||
That should be implemented as one of these:
|
||||
|
||||
- a new legacy endpoint that accepts a signed FaceAI result token and loads the matched photo set into the request or session before rendering the race page
|
||||
- an extension of the existing photo search flow so it can accept a FaceAI result id and fetch the matched photo ids server-side
|
||||
|
||||
This is preferable to putting the matched ids directly in the browser URL, because the result set may be long and should remain tamper-resistant.
|
||||
|
||||
## FaceAI App Structure
|
||||
|
||||
The requested target folder is `faceai/`. It does not currently exist in this workspace, so this plan assumes it will be created as a new app.
|
||||
|
|
@ -165,31 +192,47 @@ faceai/
|
|||
## FaceAI User Flow
|
||||
|
||||
1. User opens a race photo page on `www`.
|
||||
2. The old `tipoPuntoFoto` dropdown is replaced in the browser by a `Face ID` button.
|
||||
2. The old `tipoPuntoFoto` dropdown is removed from the visible UI and replaced by a `Face ID` button.
|
||||
3. User clicks the button.
|
||||
4. Legacy bridge validates session and redirects to FaceAI with signed context.
|
||||
5. FaceAI shows a page styled like the old site, including a matching header and a clear `Back to race page` action.
|
||||
6. User uploads a selfie.
|
||||
7. FaceAI creates a search job with `userId`, `raceId`, `requestId`, and selfie file reference.
|
||||
8. If the queue is short, FaceAI waits and then shows results.
|
||||
9. If processing is long, FaceAI tells the user the request will complete by email and stores the result for later retrieval.
|
||||
10. User opens a matched photo detail or download action.
|
||||
11. That action goes back through the legacy photo view/download endpoints so the current account checks and photo-count subtraction still apply.
|
||||
8. FaceAI polls until the processing job completes.
|
||||
9. Once the result is ready, FaceAI redirects the browser back to the original race page on `www`.
|
||||
10. The legacy site resolves the matched photo ids and renders the race page filtered to those photos only, similar in spirit to the existing pettorale-based flow.
|
||||
11. User opens and downloads photos exactly as they do today, through the legacy site.
|
||||
|
||||
## Result And Download Strategy
|
||||
|
||||
Do not duplicate the download-credit logic in FaceAI.
|
||||
Do not duplicate either the final photo listing view or the download-credit logic in FaceAI.
|
||||
|
||||
Instead:
|
||||
|
||||
- FaceAI should store and display legacy photo identifiers, not its own download copies.
|
||||
- When the user clicks a matched photo, FaceAI should open either:
|
||||
- the existing legacy photo detail modal/page endpoint, or
|
||||
- a dedicated legacy deep link for that photo
|
||||
- When the user downloads, the request must end on the legacy side where `user.puoScaricareFoto()` and the existing decrement rules already live.
|
||||
- FaceAI should store legacy photo identifiers, not its own download copies.
|
||||
- FaceAI v1 should not become a second gallery UI for final results.
|
||||
- When matching is complete, FaceAI should hand the result back to the legacy site.
|
||||
- The legacy site should render the final matched-photo page using its existing race photo UI and existing photo modal/download endpoints.
|
||||
|
||||
This keeps the business rule in one place and avoids mismatched counters.
|
||||
|
||||
### Recommended handoff model for match results
|
||||
|
||||
Use a signed result reference instead of passing the whole match list in the browser.
|
||||
|
||||
Recommended flow:
|
||||
|
||||
1. FaceAI stores the match result under a `resultId`.
|
||||
2. FaceAI redirects to something like `https://www.regalamiunsorriso.it/faceai-return?...` with:
|
||||
- `resultId`
|
||||
- `raceId`
|
||||
- signed token
|
||||
3. Legacy endpoint validates the token.
|
||||
4. Legacy endpoint fetches the matched legacy photo ids from FaceAI or from a shared temporary store.
|
||||
5. Legacy endpoint renders the normal race page constrained to that id set.
|
||||
|
||||
This avoids URL-length issues and reduces tampering risk.
|
||||
|
||||
## Matching Result Model
|
||||
|
||||
The processing service should return at least:
|
||||
|
|
@ -204,11 +247,12 @@ The processing service should return at least:
|
|||
Each match should contain:
|
||||
|
||||
- `photoId` compatible with legacy photo endpoints
|
||||
- `previewUrl` or enough file info to derive the thumbnail
|
||||
- `score` or confidence
|
||||
- `capturedAt` if known
|
||||
- `puntoFoto` or checkpoint info if available
|
||||
|
||||
For v1, `photoId` is the most important field. If the legacy page is the final renderer, thumbnails can remain a legacy concern after redirect.
|
||||
|
||||
Race scope is mandatory. The service must never search globally by default.
|
||||
|
||||
## Async Processing Design
|
||||
|
|
@ -222,6 +266,7 @@ Use an API plus worker model.
|
|||
- `POST /api/searches`
|
||||
- `GET /api/searches/:id`
|
||||
- `GET /api/searches/:id/results`
|
||||
- `GET /api/searches/:id/redirect`
|
||||
- `POST /api/searches/:id/cancel` optional
|
||||
|
||||
### Internal worker API or queue contract
|
||||
|
|
@ -241,7 +286,7 @@ Output job:
|
|||
- match list
|
||||
- logs
|
||||
- processing duration
|
||||
- email-required flag
|
||||
- legacy-renderable result reference
|
||||
|
||||
### Queue choice
|
||||
|
||||
|
|
@ -253,23 +298,23 @@ Any of these are reasonable:
|
|||
|
||||
For this use case, Redis plus BullMQ is the most pragmatic default.
|
||||
|
||||
## Email Fallback
|
||||
## Polling And Timeout Strategy For V1
|
||||
|
||||
If the job stays queued too long or exceeds a synchronous timeout:
|
||||
V1 should use polling only and should not send email.
|
||||
|
||||
1. FaceAI stores the request in `queued` or `processing` state.
|
||||
2. Worker completes later.
|
||||
3. System emails the user with:
|
||||
- race name
|
||||
- request id
|
||||
- summary of result count
|
||||
- list of photo names or identifiers for the race, as requested
|
||||
- optional direct link back to the FaceAI results page
|
||||
Recommended behavior:
|
||||
|
||||
1. FaceAI submits the job.
|
||||
2. Browser polls `GET /api/searches/:id`.
|
||||
3. While waiting, FaceAI shows a queue or processing state.
|
||||
4. When complete, FaceAI redirects to the legacy filtered-result page.
|
||||
|
||||
Recommended timeout split:
|
||||
|
||||
- up to 15 to 30 seconds: keep user on the page with polling
|
||||
- beyond that: switch to email fallback and let the user leave
|
||||
- up to 30 seconds: keep the user on the page with polling
|
||||
- beyond 30 seconds: keep polling but show a clear long-running state and a manual retry or refresh path
|
||||
|
||||
Email can be revisited in a later phase after the core handoff flow is stable.
|
||||
|
||||
## Database Usage
|
||||
|
||||
|
|
@ -283,7 +328,7 @@ Recommended storage responsibilities:
|
|||
- job status
|
||||
- uploaded selfie metadata
|
||||
- result references to legacy photo ids
|
||||
- audit fields and email status
|
||||
- audit fields
|
||||
|
||||
Avoid copying full user profiles or photo business state into the FaceAI database.
|
||||
|
||||
|
|
@ -298,6 +343,8 @@ Recommended approach:
|
|||
- Show account actions based on FaceAI session state.
|
||||
- Add a prominent `Back to race results` link using the captured `returnUrl`.
|
||||
|
||||
For v1, the header should be a very close copy, not just a lightweight brand reference. The goal is that the user should feel they are still inside the same site family during the upload and waiting flow.
|
||||
|
||||
This is safer than trying to embed the old JSP header directly into a Node app.
|
||||
|
||||
## Security Requirements
|
||||
|
|
@ -307,22 +354,24 @@ This is safer than trying to embed the old JSP header directly into a Node app.
|
|||
- Uploaded selfies should have a short retention period.
|
||||
- Face search results must be visible only to the requesting user.
|
||||
- Queue jobs must be race-scoped and tied to the authenticated user.
|
||||
- Email contents should avoid exposing direct raw file paths.
|
||||
- Result handoff back to legacy must be signed and must not trust raw photo ids coming from the browser.
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
### Phase 1: spike and contracts
|
||||
|
||||
- Confirm whether a minimal legacy auth bridge endpoint is possible.
|
||||
- Confirm that a minimal JSP or existing-controller auth bridge endpoint is possible.
|
||||
- Define the signed token payload.
|
||||
- Define the worker input and output contract.
|
||||
- Confirm which legacy photo id is stable enough to use in FaceAI results.
|
||||
- Define how legacy will accept a FaceAI result reference and render a filtered race page.
|
||||
|
||||
### Phase 2: legacy launch integration
|
||||
|
||||
- Update `www/_js/rus-ecom-240621.js` to replace the dropdown with a FaceAI button in the browser.
|
||||
- Update `www/_js/rus-ecom-240621.js` to remove the dropdown from the UI and insert the FaceAI button.
|
||||
- Add the legacy auth bridge endpoint.
|
||||
- Pass `raceId`, `lang`, and `returnUrl` into the FaceAI launch.
|
||||
- Add the legacy return endpoint or result-aware race filter path.
|
||||
|
||||
### Phase 3: FaceAI app shell
|
||||
|
||||
|
|
@ -330,42 +379,43 @@ This is safer than trying to embed the old JSP header directly into a Node app.
|
|||
- Implement auth callback and FaceAI session cookie.
|
||||
- Build the legacy-style header and return navigation.
|
||||
- Add selfie upload UI and request status page.
|
||||
- Implement polling-only job completion flow.
|
||||
|
||||
### Phase 4: processing service
|
||||
|
||||
- Add queue and worker.
|
||||
- Integrate the external face-recognition program.
|
||||
- Return matched legacy photo ids and previews.
|
||||
- Return matched legacy photo ids and a stored result reference suitable for legacy rendering.
|
||||
|
||||
### Phase 5: download integration
|
||||
### Phase 5: legacy filtered-results integration
|
||||
|
||||
- Deep-link results back to legacy photo view/download endpoints.
|
||||
- Redirect results back to the legacy race page.
|
||||
- Verify that the legacy page can render only the matched id set.
|
||||
- Verify that photo-credit subtraction still happens only on successful legacy downloads.
|
||||
|
||||
### Phase 6: async completion and email
|
||||
### Phase 6: optional future enhancements
|
||||
|
||||
- Add timeout-based fallback.
|
||||
- Send race-scoped result emails with photo names and a link back to FaceAI.
|
||||
- Add email or offline completion flow if polling-only v1 proves insufficient.
|
||||
- Add richer FaceAI-side previews only if needed after the legacy handoff works reliably.
|
||||
|
||||
## Open Questions To Resolve Early
|
||||
|
||||
1. Can the legacy site accept one minimal Java or JSP bridge endpoint for SSO handoff?
|
||||
2. Which exact account rule should control FaceAI access: active membership only, extra entitlement, race flag, or download quota?
|
||||
3. Which legacy endpoint is the best deep link for opening one photo from FaceAI results?
|
||||
4. Is the existing session cookie already scoped to `.regalamiunsorriso.it`, or is it host-only today?
|
||||
5. Should FaceAI results include only downloadable photos, or also visible-but-not-downloadable photos?
|
||||
6. What is the acceptable selfie retention period for privacy compliance?
|
||||
7. Should the email contain only photo names, or also signed result links?
|
||||
1. Which existing legacy endpoint is the best place to implement the FaceAI return filter flow?
|
||||
2. Should the return flow fetch matched photo ids directly from FaceAI, or from a shared short-lived store?
|
||||
3. What is the acceptable selfie retention period for privacy compliance?
|
||||
4. Should long-running polling survive page refresh via persisted request id in the FaceAI session?
|
||||
5. Does the legacy race page need an explicit visual label that the current listing comes from FaceAI results?
|
||||
|
||||
## Recommended First Implementation
|
||||
|
||||
For the first version, keep the scope strict:
|
||||
|
||||
- launch from one race page only
|
||||
- synchronous search if the queue is short
|
||||
- email fallback if it exceeds the timeout
|
||||
- result cards with preview plus `Open on Regalami un Sorriso`
|
||||
- remove `tipoPuntoFoto` from the user-facing race search UI
|
||||
- polling only, no email
|
||||
- final results rendered on the legacy race page, not inside FaceAI
|
||||
- all downloads still served by the legacy site
|
||||
- one lightweight auth bridge only
|
||||
- one lightweight return-filter bridge only
|
||||
|
||||
This version gives the new experience without moving the fragile parts of the old platform.
|
||||
Loading…
Add table
Add a link
Reference in a new issue