VitaSip is a full-stack web application developed as a team software engineering project. It combines a public-facing health-check and AI chat experience with an administrator console for questionnaire management, document ingestion, and analytics. The repository contains a Next.js frontend, a FastAPI backend, a PostgreSQL + pgvector database setup, Docker orchestration, migrations, seed scripts, and supporting documentation.
Important
To run backend tests locally, make sure to set up a test database and provide DATABASE_URL in shell.
e.g. export DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/test_db pytest
- Project Title: VitaSip
- Software Name: VitaSip
The following team members contributed to the development of VitaSip:
- Haoxuan (Kevin) Xu (k23164121) @kevhxx
- Jiafan (Lee) Li (k23114945) @Lee212222
- Jingyu (Jack) Wang (k24030314) @JAAAACCCCCCKKKK
- Marcell Németh (K23152672) @nemeth06
- Ruiyuan (Austin) Ma (k23114237) @Austin-152
- Tingzhang (Tony) Huang (k23032316) @binaryYuki @tz379(actions runtime only)
- Xirui (Harry) Dong (k23037057) @UniDesiranCX
- Xinyue (Betty) Wang (k23052756) @Nol4ovo
- Yihan (Mia) Shen (k23109965) @Mia7979
This submission includes all major software components required to build, run, and evaluate the system:
frontend/- Next.js 16 / React 19 frontend for the public user flow and the admin consolebackend/- FastAPI backend with REST APIs, WebSocket chat, admin auth, analytics, and document ingestioncompose.yaml- multi-service local orchestration for frontend, backend, and PostgreSQL with pgvectorbackend/alembic/- database migration configurationbackend/scripts/- seed scripts for demo quiz data, admin credentials, and sample PDF documentsdocs/- supplementary Docker and WebSocket documentation.github/workflows/- CI workflows for frontend and backend checks
This repository is structured so that the marking team and future developers can reproduce the application locally from source, without needing generated build artefacts to be committed.
VitaSip is a full-stack health-assessment and AI-assisted product education platform. It combines a public-facing questionnaire and chat experience with an administrator console for content management, document ingestion, and analytics.
The system is organised around two main user roles:
- access the application anonymously without manual sign-up
- receive a persistent device-based session
- complete a published health questionnaire
- submit answers and receive a calculated health score and result summary
- use an AI chat assistant through a WebSocket-based interface
- sign in with email and password
- create, update, publish, archive, and delete questionnaires
- manage quiz versions, questions, and options
- upload and remove PDF documents used by the document-ingestion pipeline
- access analytics endpoints and dashboard views
- Next.js frontend plus FastAPI backend
- PostgreSQL persistence with
pgvectorsupport for AI-related retrieval workflows - REST APIs plus a dedicated WebSocket endpoint for streaming AI chat
- support for both same-origin and hybrid multi-domain deployment strategies
- optional single-image container deployment with an internal reverse proxy
- Swagger/OpenAPI documentation at
/docsfor local backend inspection - validation and permission checks for invalid input, unauthorized access, unsupported uploads, and ownership-sensitive operations
- automated tests for selected frontend and backend modules
VitaSip supports both a conventional multi-service local setup and a single-image mono deployment. In the multi-service layout, the frontend and backend run as separate services. In the mono layout, a reverse proxy exposes a unified public entrypoint and routes frontend, backend API, and WebSocket traffic internally.
The implemented system includes the following significant functionality:
- Anonymous authentication with automatic session creation and persistent device IDs
- Published questionnaire retrieval, answer submission, scoring, and result retrieval
- AI-assisted chat with cookie-authenticated WebSocket streaming
- Administrator login and protected admin routes
- Questionnaire CRUD-style management for quizzes, versions, questions, and options
- PDF document upload, listing, retrieval, and deletion for the admin knowledge base
- Backend analytics endpoints and admin dashboard support
- Docker-based local setup with automated migration and seed steps
- Frontend and backend automated test support
The application should be assessed primarily through its deployed version.
- Frontend URL:
https://vitasip.catyuki.com - Backend/API behaviour: in production, ordinary HTTP API requests are typically routed through the frontend deployment, while chat WebSocket traffic may use a dedicated backend-facing public endpoint depending on deployment topology
- Local API documentation fallback:
http://localhost:8000/docswhen running the multi-service local setup, or the backend container docs endpoint when using the mono image for debugging
VitaSip supports two production-oriented deployment styles:
A reverse proxy exposes a single public origin and routes:
/to the frontend/api/*to the backend/api/v1/ws/chatto the backend WebSocket endpoint
This mode is the cleanest from the browser's perspective because page delivery, HTTP API access, and WebSocket access all appear under one public origin.
The frontend and backend may also be exposed on different public domains. In this arrangement:
- most ordinary HTTP requests still enter through the frontend domain
- the Next.js server proxies or rewrites selected API routes to the backend
- the AI chat WebSocket endpoint may connect directly to the backend/API domain
This means HTTP and WebSocket traffic may follow different public routes even though they are part of the same application.
- Open the deployed frontend URL.
- If the deployment asks for preview access credentials, use the preview credentials listed below.
- Use the public flow immediately; no standard-user sign-up is required.
- If you need protected/admin functionality, sign in through
/admin/login. - If you need to inspect backend behaviour in a reproducible environment, run one of the local setup methods described later in this README.
If the hosted preview is protected by deployment-level access control, use:
- Username:
vitasip - Password:
Vitasip26
These credentials are for access to the deployed preview environment and are separate from the application's anonymous end-user flow.
- No manual sign-up is required.
- The frontend creates an anonymous session automatically on first use.
- A device identifier is stored locally so the user session can persist across visits.
For a locally reproduced instance created through the provided seed scripts, the recommended admin credentials are:
- Email / Username: The env variable
ADMIN_EMAILis required for startup, the seeded admin email will match the value you set inbackend/.env. - Password:
admin123by default, or the value ofADMIN_PWif you set it inbackend/.envbefore startup.
Important:
ADMIN_EMAILmust be set inbackend/.envbefore startup; the backend checks for it at launch.- If
ADMIN_PWis omitted, the seed script falls back toadmin123. - If your deployed system uses different admin credentials, replace the values above before final submission.
If the deployed environment is unavailable, the system can be reproduced locally using either:
- nix develop
- the multi-service Docker Compose setup (
compose.yaml) - the single-image mono deployment described in this README
- manual frontend/backend startup without Docker
The application uses the following endpoint groups:
- Health:
GET /api/status - Authentication:
/api/auth/login,/api/auth/login/admin,/api/auth/logout,/api/auth/session,/api/auth/register/admin - Public quiz flow:
/api/v1/quiz/latest,/api/v1/quiz/{quiz_version_id}/questions,/api/v1/quiz/{quiz_id}/versions/{version}/questions,/api/v1/quiz/{quiz_version_id}/submit,/api/v1/quiz/attempt/{attempt_id}/result - Admin quiz management:
/api/v1/quiz/all,/api/v1/quiz/create,/api/v1/quiz/update,/api/v1/quiz/delete,/api/v1/version/create,/api/v1/version/detail,/api/v1/version/pub,/api/v1/version/arch,/api/v1/question/create,/api/v1/question/update,/api/v1/question/delete,/api/v1/option/create,/api/v1/option/update - Document management:
/documents,/documents/all,/documents/{doc_id},/documents/{doc_id}/file,/documents/{doc_id}withDELETE - Preset prompts:
/api/v1/preset-prompt/all,/api/v1/preset-prompt/create,/api/v1/preset-prompt/update,/api/v1/preset-prompt/delete - Analytics:
/api/v1/events,/api/v1/admin/analytics/overview,/api/v1/admin/analytics/funnel,/api/v1/admin/analytics/gap/distribution,/api/v1/admin/analytics/dosage/split,/api/v1/admin/analytics/ai/top-queries,/api/v1/admin/analytics/ai/missed - WebSocket chat:
/api/v1/ws/chatwith requiredattempt_idquery parameter
All third-party software, libraries, and source material reused in VitaSip is listed below. The exact pinned versions are recorded in frontend/package.json and backend/pyproject.toml.
| Library / framework | Version | How it is used | Source |
|---|---|---|---|
| Next.js | ^16.1.6 | Frontend framework, file-based routing, server components, API route proxying | https://nextjs.org |
| React | ^19.2.4 | UI rendering, state management, hooks | https://react.dev |
| Tailwind CSS | ^4.2.0 | Utility-class styling throughout all components | https://tailwindcss.com |
| shadcn/ui | — | Pre-built accessible component recipes (button, dialog, select, card, etc.) copied into frontend/components/ui/ |
https://ui.shadcn.com |
| Radix UI | ^1.x–^2.x | Headless primitives underlying shadcn/ui (accordion, dialog, dropdown, select, tooltip, etc.) | https://www.radix-ui.com/primitives |
| Framer Motion | ^12.34.3 | Page transitions, card entry animations, animated score gauge, chat bubble spring animations | https://www.framer.com/motion |
| Recharts | ^3.7.0 | Bar, line, funnel, and pie charts in the admin analytics dashboard | https://recharts.org |
| Lucide React | ^0.574.0 | Icon set used throughout the admin console and quiz UI | https://lucide.dev |
| SWR | ^2.4.1 | Data fetching with cache and revalidation for the analytics dashboard | https://swr.vercel.app |
| React Hook Form | ^7.71.1 | Form state management in admin login and registration flows | https://react-hook-form.com |
| @hookform/resolvers | ^5.2.2 | Zod schema integration for React Hook Form | https://github.com/react-hook-form/resolvers |
| Zod | ^4.3.6 | Runtime schema validation for form inputs | https://zod.dev |
| class-variance-authority | ^0.7.1 | Variant-based className composition used by shadcn/ui components | https://cva.style |
| clsx + tailwind-merge | ^2.1.1 / ^3.4.1 | Conditional and conflict-free className merging | https://github.com/lukeed/clsx and https://github.com/nickvdyck/tailwind-merge |
| next-themes | ^0.4.6 | Theme provider wiring (light/dark mode support) | https://github.com/pacocoursey/next-themes |
| sonner | ^2.0.7 | Toast notification system | https://sonner.emilkowal.ski |
| date-fns | ^4.1.0 | Date formatting utilities in the analytics date range picker | https://date-fns.org |
| Vitest | ^4.0.18 | Frontend unit and component test runner | https://vitest.dev |
| @testing-library/react | ^16.3.2 | Component rendering and interaction utilities for tests | https://testing-library.com/react |
| @testing-library/user-event | ^14.6.1 | Simulated user interactions in frontend tests | https://testing-library.com/user-event |
| @vitest/coverage-v8 | ^4.0.18 | V8-based coverage instrumentation for frontend tests | https://vitest.dev/guide/coverage |
| ESLint + eslint-config-next | ^9 / ^16.1.6 | Linting and code quality enforcement | https://eslint.org and https://nextjs.org/docs/app/building-your-application/configuring/eslint |
| Library / framework | Version | How it is used | Source |
|---|---|---|---|
| FastAPI | 0.129.0 | REST API framework, dependency injection, request routing, WebSocket support | https://fastapi.tiangolo.com |
| Starlette | 0.52.1 | ASGI foundation underlying FastAPI; session middleware, WebSocket handling | https://www.starlette.io |
| Pydantic + pydantic-settings | 2.12.5 / 2.13.0 | Request/response schema validation and environment variable loading | https://docs.pydantic.dev |
| SQLAlchemy | 2.0.46 | Async ORM, model definitions, query construction | https://www.sqlalchemy.org |
| Alembic | 1.18.4 | Database migration management | https://alembic.sqlalchemy.org |
| asyncpg | 0.31.0 | Async PostgreSQL driver used by SQLAlchemy | https://magicstack.github.io/asyncpg |
| pgvector | 0.4.2 | PostgreSQL vector type support for embedding storage and similarity search | https://github.com/pgvector/pgvector-python |
| PostgreSQL 16 | — | Primary relational persistence layer | https://www.postgresql.org |
| openai | 2.26.0 | OpenAI-compatible SDK for LLM chat completion and text embedding | https://github.com/openai/openai-python |
| azure-ai-inference | 1.0.0b9 | Alternative Azure AI provider for LLM and embedding workflows | https://github.com/Azure/azure-sdk-for-python |
| PyMuPDF (fitz) | 1.26.0 | PDF binary parsing, page extraction, and text extraction for document ingestion | https://pymupdf.readthedocs.io |
| langchain-text-splitters + langchain-core | 1.1.1 / 1.2.18 | Recursive character-based text chunking of extracted PDF content | https://python.langchain.com |
| tiktoken | 0.12.0 | Token counting for LLM prompt budgeting | https://github.com/openai/tiktoken |
| bcrypt | 5.0.0 | Password hashing and verification for admin authentication | https://github.com/pyca/bcrypt |
| slowapi | 0.1.9 | Rate limiting middleware applied to public API endpoints | https://github.com/laurentS/slowapi |
| itsdangerous | 2.2.0 | Signed cookie session management | https://itsdangerous.palletsprojects.com |
| aiofiles | 25.1.0 | Async file I/O for temporary PDF storage during ingestion | https://github.com/Tinche/aiofiles |
| httpx + httpx-ws | 0.28.1 / 0.8.2 | Async HTTP client used in tests and WebSocket test harness | https://www.python-httpx.org |
| python-multipart | 0.0.22 | Multipart form data parsing for PDF file uploads | https://github.com/andrew-d/python-multipart |
| python-dotenv | 1.2.2 | Loading environment variables from .env files in development |
https://github.com/theskumar/python-dotenv |
| uvicorn | 0.41.0 | ASGI server for running the FastAPI application | https://www.uvicorn.org |
| pytest + pytest-asyncio + pytest-cov | 9.0.2 / 1.3.0 / 7.0.0 | Backend test runner, async test support, and coverage reporting | https://docs.pytest.org and https://pytest-asyncio.readthedocs.io |
| coverage | 7.13.4 | Code coverage measurement for backend tests | https://coverage.readthedocs.io |
| beautifulsoup4 | 4.14.3 | HTML parsing utility used in document processing helpers | https://www.crummy.com/software/BeautifulSoup |
| numpy | 2.4.3 | Numerical array operations used in embedding and vector utilities | https://numpy.org |
| Tool | How it is used | Source |
|---|---|---|
| Nix + flake-utils | Reproducible development environment, dependency pinning, build isolation | https://nixos.org and https://github.com/numtide/flake-utils |
| bun2nix | Pre-fetches JavaScript dependencies for the Nix build sandbox | https://github.com/nix-community/bun2nix |
| process-compose-flake + services-flake | Orchestrates PostgreSQL, backend, and frontend as native OS processes under nix run .#run |
https://github.com/Platonic-Systems/process-compose-flake |
| Docker + Docker Compose | Container-based local orchestration (compose.yaml) |
https://docs.docker.com |
| Bun | JavaScript runtime and package manager for the frontend | https://bun.sh |
| uv | Python package manager and virtual environment tool for the backend | https://docs.astral.sh/uv |
AI Assistance Declaration
Generative AI tools (primarily GitHub Copilot and Claude) were used in a limited and supportive capacity during this project, in accordance with the module’s guidance on AI use.
AI assistance was used for:
- brainstorming implementation approaches and generating boilerplate code for selected FastAPI handlers and DTOs
- suggesting initial pytest test structures
- identifying opportunities for refactoring and improving readability
- assisting with Tailwind CSS and Framer Motion configuration
- refining wording in documentation
AI assistance was not used for:
- core architecture and system design decisions
- critical backend endpoint and WebSocket logic
- database schema and migration strategy
- core business logic, including quiz scoring, RAG retrieval, and analytics aggregation
All AI-assisted outputs were critically reviewed, modified, tested, and integrated by the team.
- Docker Engine / Docker Desktop with the Compose plugin
- Bun (for frontend local development)
- Python 3.12+ (the backend
pyproject.tomlrequires>=3.12) uvfor backend dependency management- PostgreSQL with
pgvectorsupport if running the backend without Docker
The repository includes templates for required local environment files:
backend/.env.examplefrontend/.env.local.example
| Variable | Required | Purpose | Notes |
|---|---|---|---|
APP_ENV |
Recommended | Application runtime mode | Common values: dev, prod |
DATABASE_URL |
Yes | PostgreSQL connection string | Must use postgresql+asyncpg://... |
SECRET_KEY |
Yes | Session signing / authentication | Use a strong value of at least 32 characters |
ADMIN_EMAIL |
Yes | Required for admin account creation and startup validation | Example: admin@vitasip.local |
ADMIN_PW |
Recommended | Password for seeded admin account | If omitted, seed script uses admin123 |
OPENAI_API_KEY |
Yes for AI features | Provider token for LLM/embedding features | Required unless AI features are intentionally disabled |
OPENAI_BASE_URL |
Sometimes | Provider endpoint | Keep https://api.openai.com/v1 for official OpenAI |
OPENAI_MODEL |
Recommended | Chat model name | Example: gpt-4.1 |
OPENAI_EMBEDDING_MODEL |
Recommended | Embedding model name | Example: text-embedding-3-small |
ANONYMOUS_DAILY_QUOTA |
Optional | Daily quota for anonymous AI chat usage | Example: 10 |
CORS_ALLOWED_ORIGINS |
Optional | Explicit CORS allowlist override | Comma-separated list; useful for split-origin deployments |
- In production, if
CORS_ALLOWED_ORIGINSis unset, the backend falls back to the known public frontend domains. - In development, it falls back to local frontend origins such as
http://127.0.0.1:3000andhttp://localhost:3000. - In same-origin deployments, explicit CORS configuration is often simpler because browser requests remain under one public origin.
| Variable | Required | Purpose | Notes |
|---|---|---|---|
NEXT_PUBLIC_CHAT_WS_URL |
Optional | Explicit browser-facing WebSocket URL | Use this for split/hybrid multi-domain deployments |
NEXT_PUBLIC_USE_SAME_ORIGIN_WS |
Recommended | Whether the frontend should derive the WS endpoint from the current page origin | true for same-origin setups; false for split-domain WS |
BACKEND_URL |
Yes for proxy/server-side requests | Internal backend base URL used by Next.js rewrites/proxy and server-side requests | In mono deployments this is usually http://127.0.0.1:8000; in Compose it is often http://backend:8000 |
NEXT_PUBLIC_*variables are exposed to browser code.BACKEND_URLis server-side only and should point to a backend target that the Next.js server can actually reach.- In same-origin deployments,
NEXT_PUBLIC_CHAT_WS_URLcan often be left empty and the frontend can derive the WebSocket URL fromwindow.location. - In hybrid multi-domain deployments,
NEXT_PUBLIC_CHAT_WS_URLshould usually be set explicitly to the public backend WebSocket endpoint.
AI-assisted features depend on an OpenAI-compatible provider.
To configure this:
- Create an account with your chosen provider.
- Generate an API token.
- Add
OPENAI_API_KEYtobackend/.env. - If you use the official OpenAI API, also set:
OPENAI_BASE_URL=https://api.openai.com/v1Without a provider token, the backend will refuse to start.
Note
Required for all setups: create backend/.env before running the backend.
cp backend/.env.example backend/.envThen edit backend/.env and fill in at least:
SECRET_KEYADMIN_EMAILOPENAI_API_KEYDATABASE_URL
See Section 9 for a full description of the variables.
The easiest way to run the complete system locally in a conventional multi-service layout is from the repository root using compose.yaml.
cp backend/.env.example backend/.env
cp frontend/.env.local.example frontend/.env.local
docker compose up --buildTypical local endpoints after startup:
- Frontend:
http://localhost:3000 - Backend health endpoint:
http://localhost:8000/api/status - Backend API docs:
http://localhost:8000/docs
The backend container entrypoint automatically performs:
alembic upgrade headpython scripts/seed_quiz.pypython scripts/seed_admin.pypython scripts/seed_file.pypython scripts/seed_demo.py
As a result, a fresh Docker startup produces:
- a migrated database schema
- a published demo questionnaire
- a seeded admin account
- seeded demo analytics data for dashboard visualisation
- sample PDF documents for document-ingestion workflows
To recreate the local database from scratch:
docker compose down -v
docker compose up --buildThis removes the PostgreSQL volume and reruns migrations and seed scripts on the next startup.
The repository also supports a single-image deployment mode in which the frontend, backend, and reverse proxy are packaged together into one container.
This mode is useful for:
- same-origin local testing
- deployment platforms that prefer a single service
- reproducing the production-style reverse-proxy layout more closely
A typical mono run uses:
- an internal Next.js frontend process
- an internal FastAPI backend process
- an internal Nginx reverse proxy exposed publicly
Example:
docker build -t vitasip-mono .
docker run --rm \
--env-file frontend/.env \
--env-file backend/.env \
-e AUTO_MIGRATE=1 \
-e AUTO_SEED=1 \
-p 8080:8080 \
vitasip-monoTypical mono endpoint after startup:
- Unified app entrypoint:
http://localhost:8080
In this mode, the public browser traffic enters through the reverse proxy, which routes frontend page requests, backend API requests, and WebSocket traffic internally.
A typical frontend configuration for mono same-origin mode is:
NEXT_PUBLIC_CHAT_WS_URL=
NEXT_PUBLIC_USE_SAME_ORIGIN_WS=true
BACKEND_URL=http://127.0.0.1:8000This allows the browser to derive the chat WebSocket endpoint from the current page origin while keeping the internal Next.js-to-backend communication pointed at the backend loopback address.
Note
Please make sure you have uv installed for backend dependency management, and Bun for frontend development.
The dev.sh script provides a convenient way to start both the frontend and backend in development mode without Docker. It also includes options for resetting the database and seeding demo data.
# Start both frontend and backend with automatic migration and seeding
chmod +x dev.sh
./dev.sh --seedcd frontend
cp .env.local.example .env.local
bun install
bun run devTypical dev frontend URL:
http://localhost:3000
cd backend
cp .env.example .env
uv sync --locked
uv run alembic upgrade head
uv run python scripts/seed_quiz.py
uv run python scripts/seed_admin.py
uv run python scripts/seed_file.py
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadTypical dev backend URLs:
- Health:
http://localhost:8000/api/status - API docs:
http://localhost:8000/docs
When running locally without Docker:
- ensure
DATABASE_URLpoints to a PostgreSQL instance withpgvectoravailable - ensure frontend
BACKEND_URLor dev proxy settings point to a reachable backend instance - set
NEXT_PUBLIC_USE_SAME_ORIGIN_WS=falseandNEXT_PUBLIC_CHAT_WS_URL=ws://127.0.0.1:8000/api/v1/ws/chatif the browser should connect directly to the local backend WebSocket endpoint
cd frontend
bun run lint
bun run test
bun run test:run
bun run test:coveragecd backend
uv run pytest -v
uv run pytest tests --cov=app --cov-report=term-missing --cov-report=xml --cov-report=htmlIf this doesn't work, make sure you have a test database set up and DATABASE_URL in backend/.env points to it.
Or try DATABASE_URL=$DB_URL uv run pytest tests(Make sure your DB_URL starts with postgresql+asyncpg://)
CI workflows for both frontend and backend are stored under .github/workflows/ and include coverage-related steps.
.
├── .github/workflows/ # frontend and backend CI workflows
├── backend/ # FastAPI backend, migrations, tests, seed scripts
├── docker/ # mono deployment helper scripts and reverse-proxy config
├── docs/ # supplementary project documentation
├── frontend/ # Next.js frontend and admin console
├── scripts/ # repository-level helper scripts
├── compose.yaml # multi-service Docker Compose orchestration
├── Dockerfile # optional single-image mono deployment
├── dev.sh # local development helper
└── README.md # root project documentation
For component-level details, see: