> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/bloom-housing/bloom/llms.txt
> Use this file to discover all available pages before exploring further.

# Public Portal

> The applicant-facing Next.js site where housing seekers browse listings, submit applications, and manage their accounts.

The Public Portal is the reference implementation of the Bloom Housing applicant-facing site. It runs as a Next.js application on port 3000 and provides housing seekers with everything they need to discover affordable housing opportunities, apply through a multi-step Common Application, and track submitted applications.

## Features

<CardGroup cols={2}>
  <Card title="Browse listings" icon="list">
    View open and closed listings with filtering. Closed listings are capped at a configurable maximum via `MAX_BROWSE_LISTINGS`.
  </Card>

  <Card title="Common Application" icon="file-pen">
    Multi-step application flow covering contact, household, financial, community types, preferences, programs, and review.
  </Card>

  <Card title="Account management" icon="user">
    Create an account, sign in, and access a dashboard showing all submitted applications and saved favorites.
  </Card>

  <Card title="Finder tool" icon="magnifying-glass">
    Guided questionnaire that matches housing seekers to relevant listings based on their situation.
  </Card>

  <Card title="Get assistance" icon="circle-question">
    Connects applicants with local housing counselor services configured via `HOUSING_COUNSELOR_SERVICE_URL`.
  </Card>

  <Card title="FAQ" icon="comments">
    Frequently asked questions page, shown when the `SHOW_PUBLIC_LOTTERY` feature flag is enabled.
  </Card>
</CardGroup>

## Page structure

All pages live under `sites/public/src/pages/`.

<AccordionGroup>
  <Accordion title="Top-level pages">
    | File                          | Route                      | Description                     |
    | ----------------------------- | -------------------------- | ------------------------------- |
    | `index.tsx`                   | `/`                        | Homepage with featured listings |
    | `listings.tsx`                | `/listings`                | All open listings               |
    | `listings-closed.tsx`         | `/listings-closed`         | Closed/waitlisted listings      |
    | `finder.tsx`                  | `/finder`                  | Listing finder questionnaire    |
    | `get-assistance.tsx`          | `/get-assistance`          | Housing counselor service       |
    | `faq.tsx`                     | `/faq`                     | FAQ (feature-flagged)           |
    | `create-account.tsx`          | `/create-account`          | New account registration        |
    | `sign-in.tsx`                 | `/sign-in`                 | Sign-in page                    |
    | `forgot-password.tsx`         | `/forgot-password`         | Password reset request          |
    | `reset-password.tsx`          | `/reset-password`          | Password reset confirmation     |
    | `verify.tsx`                  | `/verify`                  | Email verification              |
    | `disclaimer.tsx`              | `/disclaimer`              | Site disclaimer                 |
    | `privacy.tsx`                 | `/privacy`                 | Privacy policy                  |
    | `additional-resources.tsx`    | `/additional-resources`    | Additional housing resources    |
    | `create-advocate-account.tsx` | `/create-advocate-account` | Advocate account registration   |
  </Accordion>

  <Accordion title="Listing pages (/listing)">
    | File               | Route               | Description             |
    | ------------------ | ------------------- | ----------------------- |
    | `listing/[id].tsx` | `/listing/[id]`     | Listing detail page     |
    | `listing/[id]/`    | `/listing/[id]/...` | Nested listing subpages |
  </Accordion>

  <Accordion title="Application pages (/applications)">
    The Common Application is a multi-step flow. Each step is a separate page under `applications/`:

    | Directory                       | Step                                        |
    | ------------------------------- | ------------------------------------------- |
    | `applications/start/`           | Eligibility screening and application entry |
    | `applications/contact/`         | Applicant contact information               |
    | `applications/household/`       | Household members and details               |
    | `applications/financial/`       | Income and financial information            |
    | `applications/community-types/` | Community type preferences                  |
    | `applications/preferences/`     | Local preference selections                 |
    | `applications/programs/`        | Program eligibility                         |
    | `applications/review/`          | Final review and submission                 |
    | `applications/view.tsx`         | View a submitted application                |
  </Accordion>

  <Accordion title="Account pages (/account)">
    | File                        | Route                       | Description                           |
    | --------------------------- | --------------------------- | ------------------------------------- |
    | `account/dashboard.tsx`     | `/account/dashboard`        | Overview of submitted applications    |
    | `account/edit.tsx`          | `/account/edit`             | Edit account profile                  |
    | `account/application/[id]/` | `/account/application/[id]` | View a specific submitted application |
    | `account/applications/`     | `/account/applications`     | List of all submitted applications    |
    | `account/favorites/`        | `/account/favorites`        | Saved/favorited listings              |
  </Accordion>
</AccordionGroup>

## Running locally

<Steps>
  <Step title="Install dependencies">
    From the monorepo root:

    ```bash theme={null}
    yarn install
    ```
  </Step>

  <Step title="Configure environment variables">
    Copy the template and set values for your local environment:

    ```bash theme={null}
    cp sites/public/.env.template sites/public/.env
    ```

    Edit `sites/public/.env` as needed. See the [environment variables](#environment-variables) section below for details on each variable.
  </Step>

  <Step title="Start the backend and public app">
    From the monorepo root, this starts the backend on port 3100 and the public portal on port 3000:

    ```bash theme={null}
    yarn dev:all
    ```

    Alternatively, start only the public portal from within `sites/public`:

    ```bash theme={null}
    yarn dev
    ```
  </Step>

  <Step title="Open the app">
    Navigate to [http://localhost:3000](http://localhost:3000) in your browser.
  </Step>
</Steps>

<Note>
  The backend must be running on port 3100 before starting the public portal. The app will fail to load listings if the API is unreachable.
</Note>

## Environment variables

Copy `.env.template` to `.env` inside `sites/public/`. The following variables control the app's behavior:

<AccordionGroup>
  <Accordion title="API and backend">
    | Variable               | Default                 | Description                                               |
    | ---------------------- | ----------------------- | --------------------------------------------------------- |
    | `BACKEND_API_BASE`     | `http://127.0.0.1:3100` | Base URL for the backend API                              |
    | `BACKEND_API_BASE_NEW` | `http://127.0.0.1:3100` | Alternate base URL (used for new API paths)               |
    | `BACKEND_PROXY_BASE`   | *(empty)*               | If set, routes API calls through this proxy instead       |
    | `LISTINGS_QUERY`       | `/listings`             | Path appended to backend base to query listings           |
    | `API_PASS_KEY`         | `some-key-here`         | Shared passkey; must match the backend's configured value |
  </Accordion>

  <Accordion title="Application behavior">
    | Variable                        | Default                         | Description                                                                      |
    | ------------------------------- | ------------------------------- | -------------------------------------------------------------------------------- |
    | `NEXTJS_PORT`                   | `3000`                          | Port the Next.js app listens on                                                  |
    | `JURISDICTION_NAME`             | `Bloomington`                   | Display name for the jurisdiction                                                |
    | `LANGUAGES`                     | `en,es,zh,vi,tl,bn,ar,ko,hy,fa` | Comma-separated list of supported locales                                        |
    | `IDLE_TIMEOUT`                  | `5`                             | Minutes of inactivity before session timeout                                     |
    | `HOUSING_COUNSELOR_SERVICE_URL` | `/get-assistance`               | URL for housing counselor service page                                           |
    | `MAX_BROWSE_LISTINGS`           | `10`                            | Maximum number of closed listings shown on the closed listings page              |
    | `CACHE_REVALIDATE`              | `30`                            | Seconds to cache listing detail pages server-side (ISR revalidation interval)    |
    | `MAINTENANCE_WINDOW`            | *(empty)*                       | Date range (`YYYY-MM-DD HH:mm Z,YYYY-MM-DD HH:mm Z`) for maintenance mode banner |
    | `SITE_MESSAGE_WINDOW`           | *(empty)*                       | Date range for displaying a site-wide message banner                             |
  </Accordion>

  <Accordion title="Third-party integrations">
    | Variable                    | Default        | Description                                                       |
    | --------------------------- | -------------- | ----------------------------------------------------------------- |
    | `MAPBOX_TOKEN`              | *(empty)*      | Mapbox API token for listing map views                            |
    | `CLOUDINARY_CLOUD_NAME`     | `exygy`        | Cloudinary cloud name for listing images                          |
    | `GA_KEY`                    | `G-2WQMFT5BES` | Google Analytics measurement ID                                   |
    | `GTM_KEY`                   | `GTM-KF22FJP`  | Google Tag Manager container ID                                   |
    | `NEW_RELIC_APP_NAME`        | `Bloom Public` | New Relic application name                                        |
    | `NEW_RELIC_LICENSE_KEY`     | *(empty)*      | New Relic license key                                             |
    | `SENTRY_ORG`                | *(empty)*      | Sentry organization slug; when set, enables Sentry error tracking |
    | `RECAPTCHA_KEY`             | *(empty)*      | Google reCAPTCHA site key                                         |
    | `AXE_DEVELOPER_HUB_API_KEY` | *(empty)*      | Axe DevHub API key for automated accessibility reporting          |
  </Accordion>

  <Accordion title="Feature flags">
    | Variable                      | Default | Description                                                      |
    | ----------------------------- | ------- | ---------------------------------------------------------------- |
    | `SHOW_PUBLIC_LOTTERY`         | `TRUE`  | Enables lottery-related UI and the FAQ page                      |
    | `SHOW_MANDATED_ACCOUNTS`      | `FALSE` | Requires applicants to create an account before applying         |
    | `SHOW_PWDLESS`                | `FALSE` | Enables passwordless (magic link) authentication                 |
    | `SHOW_NEW_SEEDS_DESIGNS`      | `FALSE` | Enables updated UI using the latest ui-seeds design tokens       |
    | `ALLOW_SEO_INDEXING`          | `FALSE` | Set to `TRUE` in production only; enables search engine indexing |
    | `RUN_ACCESSIBILITY_E2E_TESTS` | `FALSE` | Enables accessibility checks in the Cypress E2E suite            |
  </Accordion>
</AccordionGroup>

## Testing

The public portal has two test suites.

<Tabs>
  <Tab title="Cypress (E2E)">
    Run the full end-to-end test suite against a running instance of the app:

    ```bash theme={null}
    yarn test
    ```

    Run from within `sites/public/` with the app already running on port 3000.

    <Info>
      Set `RUN_ACCESSIBILITY_E2E_TESTS=TRUE` in `.env` to also run axe-based accessibility checks during the Cypress suite.
    </Info>
  </Tab>

  <Tab title="Jest (unit/integration)">
    Run unit and integration tests:

    ```bash theme={null}
    yarn test:unit
    ```

    Run with coverage reports:

    ```bash theme={null}
    yarn test:unit:coverage
    ```

    Both commands run from within `sites/public/`.
  </Tab>
</Tabs>

## Styling

The public portal uses **Tailwind CSS** for utility classes combined with **ui-seeds CSS custom properties** for design tokens (colors, spacing, typography). SASS is used for component-level styles.

<Tip>
  If you use VSCode, install the [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=vunguyentuan.vscode-css-variables) extension to get autocompletion for all ui-seeds CSS variables. After installing, add the following to your user settings JSON:

  ```json theme={null}
  {
    "cssVariables.lookupFiles": [
      "**/*.css",
      "**/*.scss",
      "**/*.sass",
      "**/*.less",
      "node_modules/@bloom-housing/ui-seeds/src/**/*.scss"
    ],
    "cssVariables.blacklistFolders": [
      "**/.git",
      "**/node_modules/^(?!@bloom-housing).*/m"
    ]
  }
  ```
</Tip>
