Jiemin (Jenny) Zhang

All work

AlphaMind (ft_transcendence)

A multi-agent AI research platform for retail investors. I was product owner and backend lead: the three services including the AI service, the database layer, the tests and the CI/CD.

The problem

ft_transcendence is the last project of the 42 core curriculum. The team chooses its own product and must meet a fixed list of requirements. We built AlphaMind: users create organisations, share notes and portfolios, edit together in real time, and ask AI agents to analyse stocks.

What I built

  • Three FastAPI services (auth, core, ai) behind an HTTPS gateway that a teammate built. The whole stack, 17 containers, starts with one command. Services never import each other and share no foreign keys. They talk through an internal REST API and Redis events.
  • Account security: bcrypt, short-lived JWT access tokens, rotating refresh tokens stored as hashes with replay detection, TOTP two-factor login, OAuth with state and PKCE, role-based permissions and rate limits.
  • Redis holds "live" user state, so a ban or role change takes effect at once even though JWTs are stateless.
  • Event delivery that survives failures: the important events (document upload and delete, portfolio delete) go through Redis Streams with consumer groups and retries, with an outbox table in the core service, and events are published only after the database commit.
  • Real time: WebSocket with authentication and permission checks, and server-sent events for streaming LLM output.
  • AI service: a LangGraph pipeline with eight specialist agents (market, news, sentiment, filings, fundamentals, technicals, risk, macro) plus a portfolio agent when the analysis has holdings. They run ReAct loops, a bull and a bear agent debate, and a reflection step checks the result and can send it back for another try.
  • Retrieval: hybrid search (BM25 plus vectors in Qdrant, merged with Reciprocal Rank Fusion), a knowledge graph the agents can query, and query expansion. LLM calls are tiered by cost and accuracy, with fallback models.
  • Agent memory in layers: a per-ticker track record of earlier calls and how they turned out, tool-use patterns that worked for each agent role, and finished reports archived into the search index. Quality gates on what is written back keep weak output out of later runs.
  • I tested the AI service the way you test a flaky system: repeated batch runs, log review, a golden set for retrieval, and fixes for the systematic errors that showed up (for example repeated figures between reflection rounds and duplicate documents in the index).
  • Quality and operations: health checks and structured logs with request IDs in every service, tests against real PostgreSQL and Redis, and CI gates. The repo passes mypy --strict and flake8. Monitoring, alerts and backups were built by a teammate and run alongside the services.

Decisions and trade-offs

Separate schemas, no cross-service foreign keys
Services stay independent and can change on their own. The cost is that referential integrity depends on events and tests instead of the database.
Transactions owned by the request, not the service
One dependency commits or rolls back per request. Services only flush. That keeps transaction boundaries easy to find.
Publish events after commit
Subscribers never see data that was later rolled back. A failed email or broadcast does not fail the request.

Limits and next steps

Known limits, documented in the README: tokens are signed with one shared HS256 secret, and Redis and Qdrant rely on the private Docker network instead of passwords.