371 lines
No EOL
14 KiB
Markdown
371 lines
No EOL
14 KiB
Markdown
# FaceAI Integration Plan
|
|
|
|
## Goal
|
|
|
|
Integrate a new face-ID search application at `faceai.regalamiunsorriso.it` with the legacy site at `www.regalamiunsorriso.it`, while keeping changes to the legacy site small and preserving the current download/account rules.
|
|
|
|
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
|
|
|
|
## What Exists Today
|
|
|
|
Relevant current integration points in the legacy site:
|
|
|
|
- The race photo page still uses a `select` with id `tipoPuntoFoto` in `www/fotoCR.jsp` and `www/fotoCR-en.jsp`.
|
|
- The client-side navigation for race photo search is built in `www/_js/rus-ecom-240621.js` through `searching()`, `searchingTPF()`, `searchingPF()`, `goPage()`, and `mostraFoto()`.
|
|
- The logged-in user is exposed from the Java session as `utenteLogon` and related session beans in shared JSP includes such as `www/_inc_header.jsp`.
|
|
- The current photo modal and download gate are driven by `www/fotoView.jsp`, where download access is checked with `user.puoScaricareFoto()` or free-race logic.
|
|
- The actual download link still goes through the existing legacy file path and business rules, so photo-credit subtraction should remain on the legacy side instead of being reimplemented in Node.
|
|
|
|
## Important Constraint
|
|
|
|
There is one hard technical constraint to make explicit:
|
|
|
|
The legacy site identity is held in the Java web session, not in PHP. That means a pure PHP-only bridge on `www` cannot securely determine who the user is from the existing session cookie unless there is already an external shared auth service.
|
|
|
|
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.
|
|
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.
|
|
|
|
## Recommended Architecture
|
|
|
|
Use three deployable parts:
|
|
|
|
1. Legacy site at `www.regalamiunsorriso.it`
|
|
2. New user-facing app at `faceai.regalamiunsorriso.it`
|
|
3. Separate async processing service for face matching, deployed independently and fed through a queue
|
|
|
|
### 1. Legacy site responsibilities
|
|
|
|
- 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.
|
|
- Continue to serve original photo downloads so existing counters and permissions remain unchanged.
|
|
|
|
### 2. FaceAI app responsibilities
|
|
|
|
- Read the handoff token or FaceAI session cookie.
|
|
- Show the legacy-like header and navigation.
|
|
- 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.
|
|
- Preserve the page the user came from and offer a one-click return.
|
|
|
|
### 3. Processing service responsibilities
|
|
|
|
- Receive a race-scoped search job.
|
|
- 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.
|
|
|
|
## Authentication And Cookie Strategy
|
|
|
|
## Recommendation
|
|
|
|
Do not try to make the Node app directly trust the legacy `JSESSIONID` cookie.
|
|
|
|
Even if the cookie domain is widened to `.regalamiunsorriso.it`, the Node app still cannot safely resolve that session unless both apps share the same session store and session format. That would be more invasive than a handoff bridge.
|
|
|
|
Instead:
|
|
|
|
1. User clicks the new FaceAI button on the legacy race page.
|
|
2. Legacy site creates a short-lived signed token with:
|
|
- legacy user id
|
|
- email
|
|
- display name
|
|
- language
|
|
- access flags for FaceAI
|
|
- race id
|
|
- race slug or descriptor
|
|
- current page URL as `returnUrl`
|
|
- expiry time, ideally 1 to 5 minutes
|
|
3. Browser is redirected to `https://faceai.regalamiunsorriso.it/auth/callback?token=...`
|
|
4. FaceAI validates the token and sets its own cookie on `.regalamiunsorriso.it`, for example `rus_faceai_session`
|
|
5. FaceAI uses its own session cookie afterward
|
|
|
|
This gives the new app shared-domain cookies while avoiding direct dependency on the Java session internals.
|
|
|
|
## 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.
|
|
|
|
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.
|
|
|
|
## Minimal Changes To The Old Site
|
|
|
|
The smallest practical change set on the legacy site is:
|
|
|
|
### Frontend change
|
|
|
|
Do not replace the dropdown in JSP markup first.
|
|
|
|
Instead, update `www/_js/rus-ecom-240621.js` so that on the race page it:
|
|
|
|
- detects `#tipoPuntoFoto`
|
|
- hides or disables that select for eligible races
|
|
- inserts a `Face ID` button in the same area
|
|
- builds the launch URL using the current race context and current page URL
|
|
|
|
This avoids fragile JSP layout edits and keeps the change deployable as a single JS asset update.
|
|
|
|
### Server-side bridge change
|
|
|
|
Add one minimal auth bridge endpoint on the legacy stack. It can be:
|
|
|
|
- a JSP-backed endpoint
|
|
- a servlet endpoint
|
|
- or an existing controller action if the platform already has one suitable for custom commands
|
|
|
|
That endpoint should:
|
|
|
|
- read the current legacy session
|
|
- verify the user and 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.
|
|
|
|
## 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.
|
|
|
|
Suggested structure:
|
|
|
|
```text
|
|
faceai/
|
|
app/
|
|
frontend/ # Vue UI
|
|
backend/ # Node API for auth/session/job orchestration
|
|
shared/ # shared types and config
|
|
docker/
|
|
Dockerfile
|
|
nginx.conf
|
|
docs/
|
|
api-contracts/
|
|
```
|
|
|
|
## 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.
|
|
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.
|
|
|
|
## Result And Download Strategy
|
|
|
|
Do not duplicate 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.
|
|
|
|
This keeps the business rule in one place and avoids mismatched counters.
|
|
|
|
## Matching Result Model
|
|
|
|
The processing service should return at least:
|
|
|
|
- `raceId`
|
|
- `requestId`
|
|
- `status`
|
|
- `submittedAt`
|
|
- `completedAt`
|
|
- `matches[]`
|
|
|
|
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
|
|
|
|
Race scope is mandatory. The service must never search globally by default.
|
|
|
|
## Async Processing Design
|
|
|
|
Use an API plus worker model.
|
|
|
|
### Public FaceAI backend API
|
|
|
|
- `POST /api/auth/callback` or `GET /auth/callback?token=...`
|
|
- `GET /api/session`
|
|
- `POST /api/searches`
|
|
- `GET /api/searches/:id`
|
|
- `GET /api/searches/:id/results`
|
|
- `POST /api/searches/:id/cancel` optional
|
|
|
|
### Internal worker API or queue contract
|
|
|
|
Input job:
|
|
|
|
- request id
|
|
- race id
|
|
- selfie storage path
|
|
- user id
|
|
- email
|
|
- timeout policy
|
|
|
|
Output job:
|
|
|
|
- success or failure
|
|
- match list
|
|
- logs
|
|
- processing duration
|
|
- email-required flag
|
|
|
|
### Queue choice
|
|
|
|
Any of these are reasonable:
|
|
|
|
- Redis plus BullMQ for simpler Docker deployment
|
|
- RabbitMQ if stronger broker semantics are preferred
|
|
- orchestrator-native job queue if the platform already provides it
|
|
|
|
For this use case, Redis plus BullMQ is the most pragmatic default.
|
|
|
|
## Email Fallback
|
|
|
|
If the job stays queued too long or exceeds a synchronous timeout:
|
|
|
|
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 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
|
|
|
|
## Database Usage
|
|
|
|
Keep database usage minimal.
|
|
|
|
Recommended storage responsibilities:
|
|
|
|
- Legacy DB remains authoritative for users, membership state, photo ownership/rules, and download counters.
|
|
- FaceAI DB stores only:
|
|
- face search requests
|
|
- job status
|
|
- uploaded selfie metadata
|
|
- result references to legacy photo ids
|
|
- audit fields and email status
|
|
|
|
Avoid copying full user profiles or photo business state into the FaceAI database.
|
|
|
|
## Legacy Look And Navigation
|
|
|
|
The FaceAI app should feel like part of the existing site, but it should not depend on JSP includes at runtime.
|
|
|
|
Recommended approach:
|
|
|
|
- Copy the visual structure of `www/_inc_header.jsp` into a Vue header component.
|
|
- Keep the same main logo, colors, and top navigation destinations.
|
|
- Show account actions based on FaceAI session state.
|
|
- Add a prominent `Back to race results` link using the captured `returnUrl`.
|
|
|
|
This is safer than trying to embed the old JSP header directly into a Node app.
|
|
|
|
## Security Requirements
|
|
|
|
- Handoff token must be signed and short-lived.
|
|
- FaceAI session cookie must be `HttpOnly`, `Secure`, and `SameSite=Lax` unless a stricter policy breaks the flow.
|
|
- 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.
|
|
|
|
## Rollout Plan
|
|
|
|
### Phase 1: spike and contracts
|
|
|
|
- Confirm whether a minimal legacy 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.
|
|
|
|
### Phase 2: legacy launch integration
|
|
|
|
- Update `www/_js/rus-ecom-240621.js` to replace the dropdown with a FaceAI button in the browser.
|
|
- Add the legacy auth bridge endpoint.
|
|
- Pass `raceId`, `lang`, and `returnUrl` into the FaceAI launch.
|
|
|
|
### Phase 3: FaceAI app shell
|
|
|
|
- Create `faceai/` app structure.
|
|
- Implement auth callback and FaceAI session cookie.
|
|
- Build the legacy-style header and return navigation.
|
|
- Add selfie upload UI and request status page.
|
|
|
|
### Phase 4: processing service
|
|
|
|
- Add queue and worker.
|
|
- Integrate the external face-recognition program.
|
|
- Return matched legacy photo ids and previews.
|
|
|
|
### Phase 5: download integration
|
|
|
|
- Deep-link results back to legacy photo view/download endpoints.
|
|
- Verify that photo-credit subtraction still happens only on successful legacy downloads.
|
|
|
|
### Phase 6: async completion and email
|
|
|
|
- Add timeout-based fallback.
|
|
- Send race-scoped result emails with photo names and a link back to FaceAI.
|
|
|
|
## 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?
|
|
|
|
## 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`
|
|
- all downloads still served by the legacy site
|
|
- one lightweight auth bridge only
|
|
|
|
This version gives the new experience without moving the fragile parts of the old platform. |