---
title: "Entities"
description: "Organization profiles with industry presets, tiered visibility, verification queue, My Entities, and DatabaseService-backed CRUD — core Ring product loop for founders and integrators"
locale: "en"
---
# Entities

Entities are the organization profiles at the center of Ring’s product loop: discover or create a profile, invite members, post opportunities, optionally activate a store, and keep discovery fresh after every mutation.

> **Info**
> Use **Founder** / **Developer** tabs in the docs sidebar to filter this page. Sidebar article visibility is controlled by `lib/docs/audience-curated-docs.ts` (Layer1); this page is curated for both audiences.

Entities are not a business-directory page bolted on later — they are the primary **organization** record that opportunities, vendor stores, verification procedures, and Tunnel discovery hang off.

| Concern | What Ring ships |
|---------|-----------------|
| Industry catalog | Vertical preset via `ring-config` `entities.preset` (`platform` = 26 types; `agricultural` = alternate catalog) |
| Visibility | `public` · `subscriber` · `member` · `confidential` (+ `isConfidential` flag) |
| Verification | Queue statuses `none` → `pending` / `under_review` → `verified` / `rejected` via `POST /api/entities/{id}/verify` |
| Team | `addedBy` owner + `members[]` user IDs; invite by existing-user email |
| Freshness | `syncEntityDiscovery()` — cache tags, `revalidatePath`, Tunnel `entity:*` |
| Data plane | PostgreSQL JSONB through `DatabaseService`; UI reads `SerializedEntity` (ISO dates) |

### For founders

## Why entities matter for your clone

Your settlers and operators need a trusted organization surface: who we are, which industry we claim, who can see us, and how we collaborate. Entities give each organization that surface without a separate CRM.

  
- **[Create & showcase](/docs/features/entities.md)** — Members create profiles at /entities/add; public and role-gated listings at /entities.

  
- **[My Entities desk](/docs/features/entities.md)** — /entities/my tabs: All (owned), Store (owned + storeActivated), Member of.

  
- **[Opportunities](/docs/features/opportunities.md)** — Jobs and partnerships attach to an entity — verified presence improves trust in matching.

  
- **[Store activation](/docs/features/store.md)** — An entity can become a vendor; store metrics appear on entity analytics for owners/members.

### Typical scenarios

- **Local business ring** — SMBs create public entities, invite staff, post local opportunities.
- **Confidential partner desk** — elevated roles create `visibility: confidential` entities for restricted collaboration (`/confidential/entities`).
- **Vendor onboarding** — entity owner activates store; My Entities **Store** tab surfaces those profiles.
- **Vertical clone** — set `entities.preset` to `agricultural` (or a clone overlay preset) so industry pickers match the niche instead of the default 26 platform industries.

> **Tip**
> Platform verification is a **review queue**, not a marketing badge ladder. Owners/admins request review; platform staff resolve via verification procedures (`subjectType: entity_identity`).

### Operator checklist

1. Confirm clone `entities.preset` in `ring-config.json` (empire org overlay uses `platform`).
2. Ensure creators have **member** (or higher) platform role — confidential create needs confidential access.
3. Walk /entities/add → profile → optional verify + invite → post first opportunity.
4. Use /entities/my to separate owned, store-enabled, and membership views.

### For developers

## Implementation

### Product loop

```mermaid
flowchart LR
  Create[createEntity / POST /api/entities/create]
  DB[(entities JSONB)]
  Sync[syncEntityDiscovery]
  UI["/entities · /entities/my · detail"]
  Tunnel[Tunnel entity:*]
  Opp[opportunities.organizationId]
  Store[storeActivated vendor]

  Create --> DB --> Sync
  Sync --> UI
  Sync --> Tunnel
  DB --> Opp
  DB --> Store
```

### Module map (Layer1 `ring/web`)

| Area | Path |
|------|------|
| Types / `SerializedEntity` | `features/entities/types/index.ts` |
| Presets (`platform` / `agricultural`) | `features/entities/presets/` + `getEntityTypes()` |
| DB mapping | `features/entities/lib/entity-db-mapper.ts` |
| Permissions / visibility | `features/entities/lib/entity-permissions.ts`, `entity-visibility-filter.ts` |
| Mutation sync | `features/entities/lib/entity-mutation-sync.ts` → `lib/discovery/sync-discovery.ts` |
| Create / update / delete | `features/entities/services/create-entity.ts`, `update-entity.ts`, `delete-entity.ts` |
| Invite / verify / analytics | `invite-entity-member.ts`, `request-entity-verification.ts`, `get-entity-analytics.ts` |
| My Entities views | `features/entities/lib/my-entities-views.ts` (`all` \| `store` \| `member`) |
| Server Actions | `app/_actions/entities.ts` |
| Ownership gate | `features/entities/lib/assert-entity-owner.ts` (`addedBy` or platform admin) |

Empire overlay (`ring-platform-org`) does not fork entity services in `web/` for this feature — compose Layer1; locales/config may overlay via merge.

### App routes

| Route | Purpose |
|-------|---------|
| `/[locale]/entities` | Discovery list |
| `/[locale]/entities/add` | Create form |
| `/[locale]/entities/my` | Owned / store / member tabs |
| `/[locale]/entities/[id]` | Showcase / detail |
| `/[locale]/entities/[id]/edit` | Edit |
| `/[locale]/entities/[id]/delete` | Delete confirm UI |
| `/[locale]/confidential/entities` | Confidential listing |
| `/[locale]/entities/status/[action]/[status]` | Status feedback page |

### REST surface

| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/entities` | List / query |
| `POST` | `/api/entities/create` | Create |
| `GET` | `/api/entities/{id}` | Detail |
| `PUT` | `/api/entities/{id}` | Full update |
| `PATCH` | `/api/entities/{id}` | Partial (Zod `entityPatchSchema`) |
| `DELETE` | `/api/entities/{id}` | Body `{ "confirm": true }` required |
| `POST` | `/api/entities/{id}/verify` | Queue verification |
| `POST` | `/api/entities/{id}/invite` | Invite existing user by email |
| `GET` | `/api/entities/{id}/analytics` | Owner / member / platform admin |
| `POST` | `/api/entities/upload` | Authenticated media upload |

MCP mirrors: `/api/mcp/v1/entities`, `/api/mcp/v1/entities/search`, `/api/mcp/v1/entities/{id}`.

### Visibility ladder

Discovery filters use platform roles (`visitor` → `admin`). Confidential rows require `hasConfidentialAccess`. Setting `visibility: confidential` or `isConfidential: true` on create/update is gated the same way.

### Create via service

Authenticate as a user who may create entities (`canCreateEntity` — member+; confidential create needs confidential access).

Call the service (or `POST /api/entities/create`). Required shape centers on `name`, `type`, descriptions, `addedBy`, `locale`, `location`, `visibility`, `members`, `opportunities`.

{`import { createEntity } from '@/features/entities/services/create-entity'

const entity = await createEntity({
  name: 'Innovative Solutions Inc',
  type: 'technologySoftware',
  shortDescription: 'Enterprise software and Ring integrations',
  fullDescription: 'Full-service delivery…',
  addedBy: userId,
  locale: 'en',
  location: 'Cherkasy, UA',
  visibility: 'public',
  isConfidential: false,
  members: [userId],
  opportunities: [],
})
// Triggers syncEntityDiscovery({ event: 'created' })`}

After mutations, rely on `syncEntityDiscovery` — do not invent a separate search-index table; PostgreSQL JSONB is SSOT.

### Invite & verify

{`await fetch(\`/api/entities/\${entityId}/invite\`, {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'teammate@example.com', role: 'MEMBER' }),
})

await fetch(\`/api/entities/\${entityId}/verify\`, {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ note: 'Registered LLC — docs on profile' }),
})`}

> **Warning**
> Invite `role` (`OWNER` \| `ADMIN` \| `MEMBER`) is validated and shown in the notification copy. Persistence today appends the invitee to `members[]`. Manage gates (`assertEntityOwnerOrAdmin`) still key off **`addedBy`** or **platform admin** — do not assume invite `ADMIN` grants entity-admin APIs until a member-role store lands.

### Analytics payload

`GET /api/entities/{id}/analytics` returns `EntityAnalytics`: member count, opportunity id list length, linked opportunities (`organizationId` count), verification / moderation fields, optional `storeMetrics` / `storeVerification`, and `generatedAt`.

## Frequently asked questions

### Impact

#### Will every clone show the same 26 industries?

No. The active catalog comes from `entities.preset`. Default **platform** ships 26 industry ids (`technologySoftware` … `other`). **agricultural** swaps in a wellness/farm vertical catalog. Clones can overlay presets via ringdom-clone-build.

#### Do entities replace LinkedIn company pages?

They are Ring’s native org graph for discovery, opportunities, store, and confidential desks — not a LinkedIn sync product.

### Ops

#### Who can create an entity?

Authenticated users with member privileges (or platform admin / confidential role mapping). Confidential entities require confidential access (`canCreateEntity`).

#### How do I delete safely?

`DELETE /api/entities/{id}` with JSON `{ "confirm": true }`, or the UI delete flow under `/entities/[id]/delete`. Missing confirm returns 400.

#### Why is My Entities empty for store?

The **Store** tab only lists entities where `addedBy === currentUser` **and** `storeActivated === true`. Activate the vendor store first.

#### Does verification auto-approve?

No. `requestEntityVerification` opens/submits a `verification_procedures` record (`entity_identity`) and sets entity `verificationStatus` to pending. Review is an ops/admin workflow.

## Related documentation

  
- [api/entities](/docs/api/entities.md) — Next-step: REST/MCP contract detail for the same CRUD, invite, verify, and analytics routes.

  
- [architecture/discovery-mutation-sync](/docs/architecture/discovery-mutation-sync.md) — Depends-on: how syncEntityDiscovery invalidates caches and publishes Tunnel entity:* events.

  
- [features/opportunities](/docs/features/opportunities.md) — Same-workflow: opportunities attach to entities as organizationId / members post from entity context.

  
- [features/store](/docs/features/store.md) — Next-step: activate storeActivated on an entity and operate the multi-vendor marketplace.

  
- [architecture/security](/docs/architecture/security.md) — See-also: role ladder and confidential access patterns that gate entity visibility.

  
- [getting-started/first-success](/docs/getting-started/first-success.md) — Prerequisite: first clone walkthrough before creating production entity profiles.
