---
title: "Rooftops and the dealer group"
description: "Dealer group and rooftop entities, the public rooftop map, and who can see a lead"
locale: "en"
---
# Rooftops and the dealer group

A dealer clone's organizations are a parent group and the stores it owns. `entities.preset` is `automotive-dealer`. The public way to find a store is `/rooftops`, not the login-gated directory.

> **Info**
> This page is the dealer-pack overlay of the entities article. The Layer 1 entity record, member roles, and `parentEntityId` are unchanged. The catalog and the public map are the pack.

## Catalog

| Type id | What it is |
|---|---|
| `dealer_group` | Parent company. Partner applications are addressed here when a group exists. |
| `dealer_rooftop` | A physical store with its own inventory and staff. |
| `service_center` | Service drive, attached or standalone. |
| `body_shop` | Collision repair in the group. |
| `finance_partner` | A lender the group works with. Not a credit application on the website. |
| `insurance_partner` | An insurance desk partner. |

### For founders

## What visitors see

Visitors open `/rooftops`, search by city or name, and can ask the browser for nearby stores. Each pin shows the rooftop, a phone link when you published one, directions, and a count of vehicles in stock. Inventory links go to `/store`, not into a private office.

Staff still live on the entity. A lead is visible to the shopper who created it, platform admins, and members of that rooftop or its parent group. Choosing "Independent dealer" or "Parts supplier" under How I shop does not add that person to the rooftop.

  
- **[Public map](/docs/features/entities.md)** — `/rooftops` and `GET /api/dealer/rooftops`. No login.

  
- **[Inventory](/docs/features/store.md)** — Each vehicle carries `rooftopId` or `ownerEntityId`.

  
- **[Leads](/docs/features/opportunities.md)** — The rooftop team is who gets the messenger thread.

### For developers

## Files

| Piece | Path |
|---|---|
| Catalog | `features/entities/presets/automotive-dealer.ts` |
| Preset export | `features/entities/presets/index.ts` |
| Public reader | `features/dealer/services/rooftops.ts` |
| Map page | `app/[locale]/rooftops/page.tsx` |
| Map UI | `features/dealer/components/rooftops-map.tsx` |
| API | `app/api/dealer/rooftops/route.ts` |
| Who may see a lead | `features/entities/lib/entity-roles.ts` (`loadViewerEntityAccessIds` on Layer 1) |

`listPublicRooftops` returns name, location, phone, email, geo, group id, and a vehicle count. It does not return owner ids or member lists.

`GET /api/dealer/audience` and `PUT /api/dealer/audience` write `users.data.dealerAudience` only (`shopper`, `independent_dealer`, `parts_supplier`, `other`). They never write `users.data.role` and never call `assertEntityRole` to grant membership.

When the audience is `independent_dealer` or `parts_supplier`, the route resolves the first `dealer_group` (or, if none, the first `dealer_rooftop`) and calls `createDealerLead` with `kind: 'partner_application'`. An open application for that user is reused.

The page is `app/[locale]/(protected)/profile/audience/page.tsx`. Desktop nav id `audience` points at `/profile/audience`. It is not on the landing page or the store.

## Frequently asked questions

### Impact

#### Can a guest open the entity directory?

`/entities` stays login-gated on Layer 1. Send guests to `/rooftops`.

#### Does a partner application make someone a manager?

No. It is an entity-visible lead to the group. Staff invite members the same way as any other entity.

### Ops

#### What if there is no dealer group yet?

The audience save still stores the note. The application is created only when a `dealer_group` or `dealer_rooftop` row exists.

  
- [features/store](/docs/features/store.md) — Next-step: the inventory those rooftops publish.

  
- [features/opportunities](/docs/features/opportunities.md) — Same workflow: leads addressed to a rooftop or the group.
