Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions docs/architecture/adr/ADR-0005-vendor-naming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ADR-0005: Use Vendor as the Marketplace Seller Entity

- Status: Proposed
- Date: 2026-09-10

## Context

Nexo is being developed as a single multi-vendor marketplace for aljebal-albeedos. The marketplace contains independent sellers who share one storefront.

ADR-0002 established the use of the existing `Tenant` model and terminology for the previous multi-tenant SaaS architecture. That decision was made in the context of an existing live SaaS database.

The current Vendor domain is being established as part of the greenfield marketplace design. The marketplace concept is a seller, not an isolated tenant or storefront.

## Decision

The new marketplace domain will use explicit `Vendor` terminology for the seller entity.

A Vendor has its own stable identity and lifecycle and exists independently of user accounts. Vendor-owned data will reference the Vendor explicitly where required.

The design will use `Vendor` consistently in new marketplace domain concepts, documentation, relationships, and application code.

## Why

Using `Vendor` reflects the actual business meaning of the entity and makes the marketplace architecture easier to understand.

Continuing to use `Tenant` would carry terminology from the retired multi-tenant SaaS model into the new marketplace model and could imply that each Vendor owns an isolated storefront.

The greenfield design does not have the historical database constraint that originally motivated ADR-0002.

## Consequences

### Positive

- The domain language matches the marketplace business model.
- Vendor ownership and isolation boundaries are explicit.
- New developers can distinguish Vendors from marketplace-wide shoppers and Platform Operators.
- The design avoids speculative multi-marketplace or multi-tenant abstractions.

### Negative

- Existing SaaS-era `Tenant` terminology may need to be removed or renamed where it is no longer applicable.
- Future migration work may require additional changes if existing SaaS structures are reused.

## Alternatives Considered

### Continue using Tenant

Rejected because `Tenant` represents an isolated SaaS store, while the current product is one shared marketplace containing multiple Vendors.

### Support both Tenant and Vendor

Rejected because it would introduce unnecessary complexity and two concepts for the same marketplace seller boundary.

## Scope

This decision applies to the new Vendor domain design. It does not implement database migrations, onboarding, authorization, payments, or other Vendor functionality.
206 changes: 206 additions & 0 deletions docs/architecture/vendor-domain-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# Vendor Domain Design

## 1. What is a Vendor?

A Vendor is an independent seller operating within the aljebal-albeedos marketplace. A Vendor is a first-class domain entity with its own stable identity and lifecycle, independent of any user account. Vendor-team users may later belong to a Vendor, but the Vendor itself exists independently and represents the seller responsible for its own marketplace operations.

The Vendor is treated as a marketplace seller rather than a user or storefront because aljebal-albeedos is a single shared marketplace where multiple independent vendors sell through one storefront.

## 2. What Identifies a Vendor?

A Vendor should have a stable internal primary key that uniquely identifies the vendor within the system. The primary key should be generated by the database and should not change during the Vendor's lifetime.

In addition to the internal primary key, each Vendor should have a unique public slug. The slug provides a human-readable identifier that can be used in URLs and other public-facing contexts. The slug should remain unchanged during the Vendor's normal lifecycle, including approval, suspension, and reactivation. Changes to the Vendor name should not require the slug to change.

The Vendor name is the human-readable display name of the seller. It is not used as a unique identifier because different vendors may have similar or identical names.

The proposed identity fields are:

* `id` — stable primary key.
* `slug` — unique public identifier that remains stable during the Vendor's normal lifecycle.
* `name` — human-readable Vendor name.

The database should enforce uniqueness for the primary key and slug.


## 3. What Information Must Not Live on Vendor?

The Vendor entity should contain only information that defines the Vendor's identity, lifecycle, and core business status. Data belonging to other domains should not be stored directly on Vendor.

The following information should not live on Vendor:

- User accounts and authentication data — these belong to the user and authentication domain.
- Products — products belong to the product/catalog domain and are associated with a Vendor through an explicit relationship.
- Inventory quantities — inventory belongs to the inventory domain.
- Orders and order details — orders belong to the order domain.
- Payments, Stripe accounts, transfers, and commissions — these belong to the payment and marketplace financial domains.
- Customer information — customers are marketplace-wide identities and should not be owned by a single Vendor.
- Vendor-team roles and permissions — these belong to the authorization and user-management domain.

Keeping these concerns outside Vendor prevents the entity from becoming a large container for unrelated data and keeps the domain boundaries clear.

## 4. Vendor Lifecycle States and Transitions

The Vendor lifecycle represents the operational state of a Vendor after a Vendor record has been created.

### Proposed Lifecycle States

| State | Meaning |
| ----------- | ----------------------------------------------------------------------------------------------------------------------- |
| `pending` | The Vendor record exists but has not yet been approved by the Platform Operator. The Vendor is not eligible to operate. |
| `approved` | The Vendor has been approved and is eligible to operate, subject to other required marketplace conditions. |
| `suspended` | The Vendor remains in the system but is temporarily prevented from operating. |

These three states are sufficient to represent the Vendor's operational lifecycle:

* `pending` represents a Vendor that exists but has not yet received platform approval.
* `approved` represents a Vendor that has received approval and may operate when other required conditions are satisfied.
* `suspended` represents a previously approved Vendor that is temporarily prevented from operating.

A rejected application is not represented as a separate Vendor lifecycle state. Rejection is an onboarding/application outcome rather than an operational state of an active Vendor. The application may be rejected without allowing the prospective seller to become an approved Vendor. If the marketplace later requires persistent application history, that outcome should be represented in the onboarding/application domain rather than adding another Vendor lifecycle state.

### Proposed Transitions

| From | To | Triggered By | Meaning |
| ----------- | ----------- | ----------------- | ----------------------------------------------------------------- |
| `pending` | `approved` | Platform Operator | The Vendor has been reviewed and approved. |
| `approved` | `suspended` | Platform Operator | The Vendor is temporarily prevented from operating. |
| `suspended` | `approved` | Platform Operator | The suspension has been removed and the Vendor may operate again. |

Invalid transitions must be rejected by the domain/application layer. The Vendor's current status must remain unchanged when an invalid transition is attempted.

A Vendor should not be physically deleted as part of a normal lifecycle transition. Suspension preserves the Vendor's identity and historical relationships while preventing further operation.


## 5. Who May Manage a Vendor?

Vendor lifecycle management should be performed by the Platform Operator. The Platform Operator is responsible for reviewing Vendor applications, creating Vendor records, approving Vendors, and suspending Vendors.

### Vendor Creation

A prospective seller submits an application before a Vendor record exists. Submitting an application does not directly create a Vendor record.

The Platform Operator reviews the application. If the application is accepted, the Platform Operator explicitly creates the Vendor through the Vendor management boundary.

The `pending` state begins when the Vendor record is created. A newly created Vendor starts as `pending` and must then be explicitly approved through the defined lifecycle transition before it can operate.

Vendor-team users belong to exactly one Vendor and may manage vendor-specific operational activities within their permitted scope, but they should not control the Vendor's platform-level lifecycle.

Although authentication and authorization are outside the scope of this task, the design should establish an explicit application boundary for Vendor management. Later, authorization rules can enforce that only authorized Platform Operators can execute lifecycle-changing operations.

This separation ensures that Vendor lifecycle changes are controlled by the marketplace platform rather than by individual Vendor users.

## 6. Vendor Invariants

The Vendor domain must preserve the following invariants:

- **Stable identity:** A Vendor must have a stable primary identifier that does not change during its lifetime.
- **Unique public identifier:** Each Vendor must have a unique slug.
- **Valid lifecycle:** A Vendor must always have a valid lifecycle status.
- **Valid transitions:** Vendor status changes must follow the defined lifecycle transitions. Invalid transitions must be rejected.
- **Vendor isolation:** Vendor-owned data must remain associated with the correct Vendor and must not be accessible across Vendors without an explicit platform-level reason.
- **Ownership:** A Vendor is independent of user accounts. A Vendor may have vendor-team users associated with it, while a Platform Operator does not belong to any Vendor.
- **Operating eligibility:** A Vendor with `pending` or `suspended` status is not eligible to operate. An `approved` status is required but is not necessarily sufficient for operation; any additional marketplace conditions required for operation must also be satisfied.

## 7. Database Constraints vs Application/Domain Code

Database constraints should enforce structural rules that must always be true, while application and domain code should enforce business rules and behavior.

### Database Constraints

The database should enforce:

* Primary key uniqueness for `id`.
* Non-null constraints for required fields.
* Unique constraint for `slug`.
* A constraint on `status` that permits only the defined lifecycle values: `pending`, `approved`, and `suspended`.
* Appropriate foreign key constraints when relationships to other entities are introduced.
* Valid data types for stored values.

These constraints protect data integrity even if data is written through a different application path.

The database constraint on `status` prevents invalid lifecycle values from being stored. The exact database mechanism, such as a `CHECK` constraint or an equivalent database-supported constraint, may depend on the selected database technology.

### Application and Domain Code

Application and domain code should enforce:

* Valid Vendor lifecycle transitions.
* Who is allowed to perform lifecycle changes.
* Whether a Vendor is allowed to operate based on its current status and other required marketplace conditions.
* Business rules that require context or behavior rather than simple structural validation.

For example, the database can ensure that `status` contains only a defined lifecycle value, while the domain layer determines whether a transition from `suspended` to `approved` is permitted.

Using both layers provides stronger protection: the database protects structural integrity, while the application and domain layers protect business behavior.


## 8. Meaning of Suspended and Non-Active States

A `suspended` Vendor remains a valid Vendor in the marketplace but is temporarily prevented from starting new marketplace activity. Suspension does not remove the Vendor's identity or historical data.

A `pending` Vendor has not yet been approved by the Platform Operator and therefore cannot operate as an approved seller.

An `approved` Vendor is eligible to operate, subject to other marketplace conditions such as required payment onboarding.

### Suspended Vendor Permissions

A suspended Vendor remains able to access historical information and complete existing operational obligations, but cannot perform new selling activities.

| Action | Suspended Vendor |
|---|---|
| View historical orders | Allowed |
| Fulfill existing orders | Allowed |
| View historical earnings | Allowed |
| Edit existing products | Blocked |
| Create new products | Blocked |
| Receive new orders | Blocked |

A suspended Vendor remains identifiable and its historical records are preserved. Suspension blocks new marketplace activity without removing existing historical data or obligations.

Operating ability should therefore be derived from the Vendor's lifecycle status and other explicitly defined marketplace conditions rather than from a separate `is_active` field.
## 9. Proposed Vendor Schema

The proposed Vendor schema contains only fields required for Vendor identity, lifecycle, and core platform management.

| Column | Type | Null | Default | Unique | Index | Delete Behavior | Storage |
| ------------ | --------------- | ---- | ----------------- | ------ | ------- | --------------- | ---------- |
| `id` | BIGINT UNSIGNED | No | Auto-generated | Yes | Primary | N/A | Persistent |
| `slug` | VARCHAR(255) | No | None | Yes | Yes | N/A | Persistent |
| `name` | VARCHAR(255) | No | None | No | No | N/A | Persistent |
| `status` | VARCHAR(50) | No | `pending` | No | Yes | N/A | Persistent |
| `created_at` | TIMESTAMP | No | Current timestamp | No | No | N/A | Persistent |
| `updated_at` | TIMESTAMP | No | Current timestamp | No | No | N/A | Persistent |

### Field Justification

* `id` provides a stable internal identity for the Vendor.
* `slug` provides a unique, human-readable public identifier.
* `name` stores the Vendor's display name and does not need to be unique.
* `status` stores the Vendor's lifecycle state. The proposed default is `pending` so a newly created Vendor cannot operate before approval.
* `created_at` and `updated_at` provide standard record timestamps and support auditing of changes.

The Vendor table should not use soft deletion as part of the initial lifecycle design. Vendor suspension is represented explicitly through `status`, rather than by deleting or hiding the Vendor record.

A Vendor should not be physically deleted as part of its normal lifecycle. If deletion is ever required for an administrative or legal reason, it must be treated as a separate data-management decision and must account for the Vendor's historical relationships and referential integrity. Deletion is therefore not a Vendor lifecycle transition.

Relationships to products, orders, users, payments, and other domains should be introduced through their respective entities rather than adding unrelated fields to Vendor.

Database constraints should enforce the primary key, required fields, unique slug, and valid lifecycle status. Indexes should be added where they support lifecycle or public-identifier lookups.


## 10. ADR Decision: Tenant Naming vs Vendor Naming

The greenfield Nexo marketplace should use explicit `Vendor` terminology rather than continuing the `Tenant` naming from ADR-0002.

ADR-0002 was created for an existing live SaaS database where the `tenants` table and `Tenant` model were already used across multiple models. That historical constraint does not apply to the greenfield marketplace domain.

In aljebal-albeedos, the domain meaning is different. The system is a single marketplace with multiple independent sellers, so the correct business concept is a Vendor rather than a Tenant.

Using explicit Vendor naming makes the domain model clearer and avoids carrying SaaS multi-tenancy terminology into a marketplace architecture. Vendor is also the explicit data-isolation and ownership boundary described by the current marketplace architecture.

Therefore, the proposed design is to use `Vendor` consistently for the new marketplace domain, including the model, table, relationships, and documentation.

### Proposed ADR

This decision should be documented in a new ADR explaining the divergence from ADR-0002 and establishing `Vendor` as the marketplace domain terminology.
43 changes: 43 additions & 0 deletions docs/product/requirements/platform/vendor-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Platform Vendor Management Requirements

## Draft Requirements

### REQ-VENDOR-MGMT-001 — Vendor Visibility

The system shall allow the Platform Operator to view Vendor records and their current lifecycle status.

### REQ-VENDOR-MGMT-002 — Vendor Approval

The system shall allow the Platform Operator to approve Vendors in the `pending` state.

### REQ-VENDOR-MGMT-003 — Vendor Suspension

The system shall allow the Platform Operator to suspend Vendors in the `approved` state.

### REQ-VENDOR-MGMT-004 — Vendor Reactivation

The system shall allow the Platform Operator to reactivate a suspended Vendor by returning it to the `approved` state.

### REQ-VENDOR-MGMT-005 — Lifecycle Enforcement

The system shall prevent Vendor lifecycle changes that are not defined by the approved Vendor lifecycle.

### REQ-VENDOR-MGMT-006 — Vendor Identity Preservation

The system shall preserve a Vendor's stable identity throughout its lifecycle, including while suspended.

### REQ-VENDOR-MGMT-007 — Vendor Isolation

The system shall maintain Vendor boundaries so that Vendor-owned data cannot be accessed or modified through another Vendor's context.

### REQ-VENDOR-MGMT-008 — Operator Vendor Management

The system shall provide a platform-level management boundary for Vendor lifecycle operations so that authorization can later restrict these operations to Platform Operators.

### REQ-VENDOR-MGMT-009 — Auditability

The system shall produce an auditable record for material Vendor lifecycle changes, including approval and suspension.

### REQ-VENDOR-MGMT-010 — Vendor Operating Status

The system shall determine whether a Vendor may operate from its lifecycle status and other explicitly defined marketplace conditions.
Loading
Loading