docs: update company-vendor management documentation

- Document all admin UI pages (list, detail, edit)
- Document transfer ownership modal with user search
- Add user management API endpoints section
- Update ownership transfer description
- Fix encoding issue in marketplace-integration.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-02 19:40:00 +01:00
parent 9879c5b4bb
commit 945ddd3852
4 changed files with 335 additions and 1 deletions

View File

@@ -0,0 +1,331 @@
# Company-Vendor Management Architecture
## Overview
The Wizamart platform implements a hierarchical multi-tenant architecture where **Companies** are the primary business entities and **Vendors** are storefronts/brands that operate under companies.
```
Company (Business Entity)
├── Owner (User)
├── Contact Information
├── Business Details
└── Vendors (Storefronts/Brands)
├── Vendor 1
├── Vendor 2
└── Vendor N
```
## Key Concepts
### Company
A **Company** represents a business entity on the platform. It contains:
- **Owner**: A user account that has full control over the company
- **Contact Information**: Business email, phone, website
- **Business Details**: Address, tax number
- **Status**: Active/Inactive, Verified/Pending
### Vendor
A **Vendor** (also called storefront or brand) represents a specific storefront operating under a company. A company can have multiple vendors.
- **Unique Identity**: Vendor code and subdomain
- **Marketplace Integration**: CSV URLs for product feeds (FR, EN, DE)
- **Status**: Active/Inactive, Verified/Pending
- **Products**: Each vendor has its own product catalog
## Data Model
### Company Model
```python
class Company:
id: int
name: str
description: str | None
# Owner (at company level)
owner_user_id: int # FK to User
# Contact Information
contact_email: str
contact_phone: str | None
website: str | None
# Business Details
business_address: str | None
tax_number: str | None
# Status
is_active: bool
is_verified: bool
# Timestamps
created_at: datetime
updated_at: datetime
# Relationships
owner: User # Company owner
vendors: list[Vendor] # Storefronts under this company
```
### Vendor Model
```python
class Vendor:
id: int
company_id: int # FK to Company
vendor_code: str # Unique identifier (e.g., "TECHSTORE")
subdomain: str # URL subdomain (e.g., "tech-store")
name: str
description: str | None
# Marketplace URLs (brand-specific)
letzshop_csv_url_fr: str | None
letzshop_csv_url_en: str | None
letzshop_csv_url_de: str | None
# Status
is_active: bool
is_verified: bool
# Timestamps
created_at: datetime
updated_at: datetime
# Relationships
company: Company # Parent company (owner is accessed via company.owner)
```
## Key Design Decisions
### 1. Owner at Company Level Only
Previously, each vendor had its own `owner_user_id`. This has been refactored:
- **Before**: `Vendor.owner_user_id` - each vendor had a separate owner
- **After**: `Company.owner_user_id` - ownership is at company level
**Rationale**: A business entity (company) should have a single owner who can manage all storefronts. This simplifies:
- User management
- Permission handling
- Ownership transfer operations
### 2. Contact Information at Company Level
Business contact information (email, phone, website, address, tax number) is now stored at the company level:
- **Before**: Vendors had contact fields
- **After**: Contact info on Company model, vendors reference parent company
**Rationale**: Business details are typically the same across all storefronts of a company.
### 3. Clean Architecture
The `Vendor.owner_user_id` field has been completely removed:
- Ownership is determined solely via the company relationship
- Use `vendor.company.owner_user_id` to get the owner
- Use `vendor.company.owner` to get the owner User object
## API Endpoints
### Company Management (Admin)
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/admin/companies` | Create company with owner |
| GET | `/api/v1/admin/companies` | List all companies |
| GET | `/api/v1/admin/companies/{id}` | Get company details |
| PUT | `/api/v1/admin/companies/{id}` | Update company |
| PUT | `/api/v1/admin/companies/{id}/verification` | Toggle verification |
| PUT | `/api/v1/admin/companies/{id}/status` | Toggle active status |
| POST | `/api/v1/admin/companies/{id}/transfer-ownership` | Transfer ownership |
| DELETE | `/api/v1/admin/companies/{id}` | Delete company |
### Vendor Management (Admin)
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/admin/vendors` | Create vendor under company |
| GET | `/api/v1/admin/vendors` | List all vendors |
| GET | `/api/v1/admin/vendors/{id}` | Get vendor details |
| PUT | `/api/v1/admin/vendors/{id}` | Update vendor |
| PUT | `/api/v1/admin/vendors/{id}/verification` | Toggle verification |
| PUT | `/api/v1/admin/vendors/{id}/status` | Toggle active status |
| DELETE | `/api/v1/admin/vendors/{id}` | Delete vendor |
### User Management (Admin)
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/admin/users` | List all users |
| GET | `/api/v1/admin/users/search?q={query}` | Search users by name/email |
| PUT | `/api/v1/admin/users/{id}/status` | Toggle user status |
| GET | `/api/v1/admin/users/stats` | Get user statistics |
## Service Layer
### CompanyService (`app/services/company_service.py`)
Primary service for company operations:
- `create_company_with_owner()` - Creates company and owner user account
- `get_company_by_id()` - Get company with vendors loaded
- `get_companies()` - Paginated list with filtering
- `update_company()` - Update company fields
- `toggle_verification()` - Verify/unverify company
- `toggle_active()` - Activate/deactivate company
- `transfer_ownership()` - Transfer to new owner
- `delete_company()` - Delete company (requires no vendors)
### AdminService (`app/services/admin_service.py`)
Admin-specific vendor operations:
- `create_vendor()` - Create vendor under existing company
- `get_all_vendors()` - Paginated list with company relationship
- `update_vendor()` - Update vendor fields
- `verify_vendor()` - Toggle verification
- `toggle_vendor_status()` - Toggle active status
- `delete_vendor()` - Delete vendor
### VendorService (`app/services/vendor_service.py`)
Self-service vendor operations (for company owners):
- `create_vendor()` - Create vendor (requires company_id, validates ownership)
- `get_vendors()` - Get vendors with access control
- `get_vendor_by_code()` - Get single vendor
## Creating a New Company with Vendors
### Via Admin API
```python
# 1. Create company with owner
POST /api/v1/admin/companies
{
"name": "Tech Solutions Ltd",
"owner_email": "owner@techsolutions.com",
"contact_email": "info@techsolutions.com",
"contact_phone": "+352 123 456",
"website": "https://techsolutions.com",
"business_address": "123 Tech Street, Luxembourg",
"tax_number": "LU12345678"
}
# Response includes temporary password for owner
# 2. Create vendor under company
POST /api/v1/admin/vendors
{
"company_id": 1,
"vendor_code": "TECHSTORE",
"subdomain": "tech-store",
"name": "Tech Store",
"description": "Consumer electronics storefront"
}
```
## Ownership Transfer
Ownership transfer is a critical operation available at the company level:
1. **Admin initiates transfer** via `/api/v1/admin/companies/{id}/transfer-ownership`
2. **Company owner changes** - `Company.owner_user_id` updated
3. **All vendors affected** - Vendors inherit new owner via company relationship
4. **Audit trail** - Transfer reason logged
```python
POST /api/v1/admin/companies/1/transfer-ownership
{
"new_owner_user_id": 42,
"confirm_transfer": true,
"transfer_reason": "Business acquisition"
}
```
## Admin UI Pages
### Company List Page (`/admin/companies`)
- Lists all companies with owner, vendor count, and status
- **Actions**: View, Edit, Delete (disabled if company has vendors)
- Stats cards showing total, verified, active companies
### Company Detail Page (`/admin/companies/{id}`)
- **Quick Actions** - Edit Company, Delete Company
- **Status Cards** - Verification, Active status, Vendor count, Created date
- **Information Sections** - Basic info, Contact info, Business details, Owner info
- **Vendors Table** - Lists all vendors under this company with links
- **More Actions** - Create Vendor button
### Company Edit Page (`/admin/companies/{id}/edit`)
- **Quick Actions** - Verify/Unverify, Activate/Deactivate
- **Edit Form** - Company details, contact info, business details
- **Statistics** - Vendor counts (readonly)
- **More Actions** - Transfer Ownership, Delete Company
### Vendor Detail Page (`/admin/vendors/{code}`)
- **Quick Actions** - Edit Vendor, Delete Vendor
- **Status Cards** - Verification, Active status, Created/Updated dates
- **Information Sections** - Basic info, Contact info, Business details, Owner info
- **More Actions** - View Parent Company link, Customize Theme
### Transfer Ownership Modal
A modal dialog for transferring company ownership:
- **User Search** - Autocomplete search by username or email
- **Selected User Display** - Shows selected user with option to clear
- **Transfer Reason** - Optional field for audit trail
- **Confirmation Checkbox** - Required before transfer
- **Validation** - Inline error messages for missing fields
## Best Practices
### Creating Vendors
Always use `company_id` when creating vendors:
```python
# Correct
vendor_data = VendorCreate(
company_id=company.id,
vendor_code="MYSTORE",
subdomain="my-store",
name="My Store"
)
# Incorrect (old pattern - don't use)
vendor_data = VendorCreate(
owner_email="owner@example.com", # No longer supported
...
)
```
### Accessing Owner Information
Use the company relationship:
```python
# Get owner User object
owner = vendor.company.owner
# Get owner details
owner_email = vendor.company.owner.email
owner_id = vendor.company.owner_user_id
```
### Checking Permissions
For vendor operations, check company ownership:
```python
def can_manage_vendor(user, vendor):
if user.role == "admin":
return True
return vendor.company.owner_user_id == user.id
```
## Migration Notes
The `Vendor.owner_user_id` column has been removed. If you have an existing database:
1. Run the migration: `alembic upgrade head`
2. This will drop the `owner_user_id` column from vendors table
3. Ownership is now determined via `vendor.company.owner_user_id`
If migrating from an older vendor-centric model:
1. Create companies for existing vendors (group by owner)
2. Assign vendors to companies via `company_id`
3. Copy contact info from vendors to companies
4. Run the migration to drop the old owner_user_id column
## Related Documentation
- [Multi-Tenant Architecture](multi-tenant.md)
- [Authentication & RBAC](auth-rbac.md)
- [Models Structure](models-structure.md)
- [Admin Integration Guide](../backend/admin-integration-guide.md)

View File

@@ -163,7 +163,7 @@ All three frontends share the same core technologies:
| Backend | FastAPI | REST API + routing |
| Templates | Jinja2 | Server-side rendering |
| Interactivity | Alpine.js 3.x | Client-side reactivity |
| Styling | Tailwind CSS 2.x | Utility-first CSS (CDN + fallback) |
| Styling | Tailwind CSS 2.2.x | Utility-first CSS (CDN + fallback) - [Build Guide](tailwind-css.md) |
| Icons | Heroicons | SVG icon system |
| HTTP Client | Fetch API | API requests |
| State Management | Alpine.js reactive | No external state lib |

View File

@@ -30,6 +30,7 @@ nav:
- Architecture:
- Overview: architecture/overview.md
- Architecture Patterns: architecture/architecture-patterns.md
- Company-Vendor Management: architecture/company-vendor-management.md
- Multi-Tenant System: architecture/multi-tenant.md
- Middleware Stack: architecture/middleware.md
- Request Flow: architecture/request-flow.md
@@ -82,6 +83,8 @@ nav:
- Frontend Development:
- Overview: frontend/overview.md
- CDN Fallback Strategy: frontend/cdn-fallback-strategy.md
- Tailwind CSS Build: frontend/tailwind-css.md
- Tailwind v3 Migration Plan: frontend/tailwind-migration-plan.md
- Shared Components:
- UI Components: frontend/shared/ui-components.md
- UI Components Quick Reference: frontend/shared/ui-components-quick-reference.md