Architecture v1 ยท draft for review

AI Job Risk Architecture

How the web app, API, background worker and database fit together for the flow we agreed: sign in, pick a role, confirm duties, analyze in the background, then results, recommendations and sharing.

System map

Browser or phone Responsive web app, nothing to install Next.js frontend Landing, sign in, analysis steps Status, result, recommendations Public share page at /s/token Sign-in providers Google sign-in Email magic link FastAPI Checks the session token on every call Roles, analyses, job status Recommendations, shares, delete account Claude API Messages with the web search tool API key lives only on the worker Never reachable from the browser MongoDB Atlas users, analyses, jobs, shares occupations (with search index) tools and certifications catalogs Region chosen for data residency Worker (Python) Runs one job step at a time Build role profiles, rate custom duties, write up when needed Separate process, same codebase HTTPS sign in REST + session token read, write, queue a job poll jobs save steps prompts + search
The browser never talks to FastAPI or Claude directly. FastAPI only queues work and reads results, and most requests never reach the worker. Every Claude call happens in the worker, so a slow or failed call never blocks a web request, and the API key stays out of reach.

How one analysis moves

queued building role personalizing awaiting answers writing up done dashed = skipped when not needed
Most analyses skip every dashed step and go from queued to done. Each step saves its output before the next begins. Any step can fail, and Retry resumes from the last saved step instead of repeating earlier work. The tab can be closed at any point and reopened to the same state.
StateWhat runsSkipped when
queuedThe job is inserted once the user confirms duties and optional tools. Page shows "waiting".Never
building roleGather evidence, then build the shared role profile. If another user is already building it, wait for that build.A fresh profile already exists
personalizingCompare the user's duties with the stock ones, route each, and run checks or ratings only where needed. Then recompute the risk band.Every duty matched a stock duty closely
awaiting answersOne round of up to 3 questions.The router did not escalate the case
writing upPersonal summary, adjacent roles and practices.The shared write-up fits, so it is reused
doneResult viewable. Tools gap and next steps are computed from the catalogs when the page opens. Saving and sharing are enabled.Never

Data in MongoDB

CollectionHoldsNotes
usersAccount, sign-in method, country (optional)Deleting a user deletes their analyses and shares
occupationsStandard roles with their typical duties and an embeddingText index for suggestions, vector index for matching
analysesRole (typed and matched), the user's own duties with their vectors, tools, routing log, personal resultStamped with date, model and prompt version
role_evidenceSourced findings for a role, evidence strength, dateWritten by the worker, never contains user text
role_dutiesOne document per stock duty: text, tag, rating, embedding, model versionVector index filtered by role id, used to compare user duties
role_profilesStock duties, ratings, verdict, tags for a roleShared by all users, versioned, top roles reviewed
usage_countersPer-user abuse limits and monthly spendDrives the limits and the spend breaker
jobsState, current step, attempts, error, ownerWorker claims one at a time
sharesRandom token, analysis id, what to hide, revoked flagOwner can revoke at any time
tools_catalogAI and work tools users can pick fromEditable without a deploy
certifications_catalogReviewed courses and certifications, with cost and typeThe model picks from this list and does not invent names

Rules the design enforces

Every record belongs to a userEach query filters by the signed-in user, so nobody can open another person's analysis by guessing an id.
Shares are an allow-listThe public page returns only the fields the owner chose to show. Email and free-text answers stay private by default.
User text is data, not instructionsJob titles and answers are passed to the model as quoted data, and outputs are validated before they are saved.
Limits protect the billPer-user caps on analyses per day, and a maximum of one question round per analysis.

To confirm before building

  1. Job runner. Mongo-backed jobs with a polling worker (simple, my default) or a dedicated queue such as Redis. Start simple and swap later if volume needs it.
  2. Token handoff. Next.js handles sign-in and passes a signed token that FastAPI verifies. We need to pick the exact library and token lifetime.
  3. PDF export. Render the share page to PDF in the worker, or let the browser export it. Server-side gives consistent output but adds a rendering dependency.
  4. Hosting and Atlas region. Where the three pieces run (frontend, API, worker), and which region holds the data. This decides data residency for your global users.
  5. Catalog upkeep. Who reviews certifications and tools, and how often. A stale catalog is the quickest way to lose trust.