Regalamiunsorriso/FACEAI_INTEGRATION_PLAN.md
2026-04-07 18:02:17 +02:00

14 KiB

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.

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.

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:

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?

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.