mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 07:19:35 +00:00
Full-stack AI-powered sales automation platform for Saudi SMEs: Backend (FastAPI + PostgreSQL): - Multi-tenant architecture with row-level isolation - JWT auth with RBAC (owner/manager/agent/admin) - Lead, Customer, Deal, Pipeline, Activity, Message, Proposal models - Dashboard analytics API (overview, pipeline, revenue) - WhatsApp Business API, Email (SMTP/SendGrid), SMS (Unifonic) integrations - Celery + Redis workers for automated follow-ups and scheduled messages - Property model for Real Estate module (Riyadh districts) - Hijri date utilities, Arabic/English localization Frontend (Next.js + Tailwind): - Professional Arabic RTL landing page with 10 sections - Brand identity: SalesMatic (سيلزماتك) with custom SVG logo - Color system: Trust Blue #0F4C81, Growth Teal #00BFA6, CTA Orange #FF6B35 - IBM Plex Sans Arabic + Inter typography - Responsive design, dark hero section, pricing table, FAQ Industry Templates: - Healthcare/Clinics: pipeline stages, WhatsApp message templates, auto-workflows - Real Estate Riyadh: 20 districts, property tours, payment plans, matching Infrastructure: - Docker Compose (PostgreSQL, Redis, Backend, Celery, Frontend, Nginx) - Nginx reverse proxy config - Makefile for common operations https://claude.ai/code/session_01LLR7jzpyNRwDA9kojtT3CW
117 lines
3.5 KiB
Python
117 lines
3.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
from uuid import UUID
|
|
from datetime import datetime
|
|
from app.database import get_db
|
|
from app.api.deps import get_current_user, require_role
|
|
from app.models.user import User
|
|
from app.utils.security import hash_password
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
email: str
|
|
full_name: Optional[str]
|
|
full_name_ar: Optional[str]
|
|
role: str
|
|
phone: Optional[str]
|
|
is_active: bool
|
|
last_login: Optional[datetime]
|
|
created_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
email: str
|
|
password: str
|
|
full_name: str
|
|
full_name_ar: Optional[str] = None
|
|
role: str = "agent"
|
|
phone: Optional[str] = None
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
full_name: Optional[str] = None
|
|
full_name_ar: Optional[str] = None
|
|
role: Optional[str] = None
|
|
phone: Optional[str] = None
|
|
is_active: Optional[bool] = None
|
|
|
|
|
|
@router.get("", response_model=list[UserResponse])
|
|
async def list_users(
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(select(User).where(User.tenant_id == current_user.tenant_id).order_by(User.created_at))
|
|
return [UserResponse.model_validate(u) for u in result.scalars().all()]
|
|
|
|
|
|
@router.post("", response_model=UserResponse, status_code=201)
|
|
async def create_user(
|
|
data: UserCreate,
|
|
current_user: User = Depends(require_role("owner", "admin", "manager")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
existing = await db.execute(select(User).where(User.email == data.email, User.tenant_id == current_user.tenant_id))
|
|
if existing.scalar_one_or_none():
|
|
raise HTTPException(status_code=400, detail="Email already exists in this company")
|
|
|
|
user = User(
|
|
tenant_id=current_user.tenant_id,
|
|
email=data.email,
|
|
password_hash=hash_password(data.password),
|
|
full_name=data.full_name,
|
|
full_name_ar=data.full_name_ar,
|
|
role=data.role,
|
|
phone=data.phone,
|
|
)
|
|
db.add(user)
|
|
await db.flush()
|
|
await db.refresh(user)
|
|
return UserResponse.model_validate(user)
|
|
|
|
|
|
@router.put("/{user_id}", response_model=UserResponse)
|
|
async def update_user(
|
|
user_id: UUID,
|
|
data: UserUpdate,
|
|
current_user: User = Depends(require_role("owner", "admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(select(User).where(User.id == user_id, User.tenant_id == current_user.tenant_id))
|
|
user = result.scalar_one_or_none()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
|
|
for field, value in data.model_dump(exclude_none=True).items():
|
|
setattr(user, field, value)
|
|
|
|
await db.flush()
|
|
await db.refresh(user)
|
|
return UserResponse.model_validate(user)
|
|
|
|
|
|
@router.delete("/{user_id}", status_code=204)
|
|
async def delete_user(
|
|
user_id: UUID,
|
|
current_user: User = Depends(require_role("owner", "admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(select(User).where(User.id == user_id, User.tenant_id == current_user.tenant_id))
|
|
user = result.scalar_one_or_none()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
if user.id == current_user.id:
|
|
raise HTTPException(status_code=400, detail="Cannot delete yourself")
|
|
|
|
user.is_active = False
|
|
await db.flush()
|