This repository contains the frontend for the BRASA at UofT website.
It is a React + TypeScript single-page application (SPA) with:
- Cognito authentication through AWS Amplify
- Integration with a backend API (NestJS exposed via API Gateway + Lambda)
- Internationalization support for English and Portuguese
- React 18 + TypeScript
- Vite
- React Router
- AWS Amplify (Auth)
- Tailwind CSS, Material UI, Ant Design, styled-components
The codebase is organized by feature and role:
src/pages: Route-level screens (Home, Contact, Login, Register, Account, etc.)src/components: Reusable UI componentssrc/contexts: Global state/providers (auth and locale)src/services: API integration layer (users, auth registration bridge, contact)src/resources: Translation dictionaries (en-US,pt-BR)src/types: Domain and shared TypeScript typessrc/seo: Per-route metadata, structured data, and sitemap generation
src/seo/routes.ts is the single source of truth for per-route SEO. Each entry
carries the page title, meta description, breadcrumb label and whether the page
may be indexed.
Adding a route to src/App.tsx means adding an entry there too — a test in
src/seo/seo.test.ts fails if the two drift apart. Everything else follows from
that table:
useSeo(mounted once inApp.tsx) sets the title, description, canonical URL, Open Graph/Twitter tags and robots directives on every navigation.Breadcrumbsrenders the visible trail, anduseSeoemits the matchingBreadcrumbListstructured data.- A Vite plugin writes
sitemap.xmlandrobots.txtintodist/at build time. They are generated, not stored inpublic/— edit the route table instead.
Sitewide Organization and WebSite structured data lives statically in
index.html so crawlers that do not execute JavaScript can still read it.
The site is a client-rendered SPA: every URL is served the same index.html,
and per-page metadata is only applied after React mounts. Googlebot executes
JavaScript and sees the correct tags, but link previewers that do not — Facebook,
LinkedIn, WhatsApp, Slack, iMessage — only ever see the static defaults in
index.html. Fixing that properly means prerendering each route to its own HTML
file at build time.
At runtime, the app flow is:
src/index.tsxbootstraps the app and initializes Amplify config fromsrc/aws.ts.LocaleProviderprovides text dictionary access and locale persistence.AuthProvidermanages Cognito session lifecycle and authenticated requests.- Route pages call service functions in
src/servicesto reach backend endpoints.
Authentication is handled with AWS Cognito via aws-amplify/auth.
High-level signup/login flow:
- User signs up in Cognito (
signUp) with standard and custom attributes. - User confirms account with verification code (
confirmSignUp). - Frontend signs user in and retrieves ID token (
fetchAuthSession). - Frontend calls backend
/users/registerwithAuthorization: Bearer <idToken>. - App fetches user profile from
/users/me.
This keeps identity managed by Cognito while user profile/domain data lives in the backend.
This frontend is designed to work with a backend API that:
- Is implemented in NestJS
- Is deployed behind AWS API Gateway
- Runs as AWS Lambda functions
- Validates Cognito JWT tokens for protected endpoints
Current frontend API usage includes:
GET /users/mePOST /users/registerPOST /contact
The backend base URL is configured with environment variables.
Configured in src/aws.ts through Amplify Auth:
- User Pool ID
- App Client ID
These values are read from environment variables and used by auth flows in src/contexts/auth.
The frontend sends Cognito bearer tokens to protected endpoints. The API is responsible for token verification and authorization rules.
Recommended hosting model for this SPA:
- Build static assets with
npm run build - Upload
dist/artifacts to an S3 bucket - Serve through CloudFront distribution
- Configure SPA fallback (rewrite/redirect to
index.html) for client-side routes
Typical production behavior:
- Immutable static assets served from CloudFront edge cache
index.htmlserved with shorter cache policy- API requests routed directly to API Gateway domain
Create a .env file at the project root:
VITE_AWS_COGNITO_USER_POOL_ID=your_user_pool_id
VITE_AWS_COGNITO_CLIENT_ID=your_cognito_app_client_id
VITE_USERS_API_BASE_URL=https://your-api-id.execute-api.region.amazonaws.comNotes:
- Preferred prefix is
VITE_. REACT_APP_variables are still accepted for backward compatibility.- Do not commit secrets.
- Node.js 18+
- npm
npm installnpm startApp runs at http://localhost:5173 by default.
npm start: run development servernpm run dev: run development servernpm run build: create production buildnpm run preview: preview production build locallynpm test: run tests
Before production deployment:
- Verify Cognito IDs and API base URL are set for the target environment.
- Ensure backend CORS allows your frontend domain.
- Confirm CloudFront/S3 SPA fallback to
index.htmlis configured. - Validate login, register, account load, and contact form flows.