feat(crm): frontend del CRM (clientes API, navegación, dashboard + Kanban) y rebrand
- Clientes API tipados por entidad en src/lib/api/crm - Navegación CRM en el sidebar - Páginas: panel (KPIs + embudo), cuentas, contactos, prospectos, actividades - Kanban de oportunidades con drag & drop (mueve entre etapas) y siembra de embudo - Rebrand plantilla → CRM (.env, docker-compose name, package.json, README) - Fix: CORE_DB_HOST=postgres (coincide con el servicio del compose) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
198
README.md
198
README.md
@@ -1,8 +1,11 @@
|
||||
# Plantilla Workspace — Aduanasoft
|
||||
# CRM — Aduanasoft
|
||||
|
||||
Plantilla base para nuevos proyectos del ecosistema **Workspace de Aduanasoft**.
|
||||
Incluye autenticación SSO con Keycloak/Hub, arquitectura multi-tenant, y un dashboard
|
||||
funcional listo para extender.
|
||||
Sistema CRM construido sobre la **plantilla Workspace de Aduanasoft** (SvelteKit 5 +
|
||||
FastAPI + PostgreSQL, multi-tenant con Keycloak/Hub). Gestiona cuentas, contactos,
|
||||
prospectos, oportunidades (pipeline Kanban) y actividades comerciales.
|
||||
|
||||
> Base: `plantillas-proyectos`. Este repo conserva el core de la plantilla (auth,
|
||||
> tenants, permisos, licencias) y agrega el dominio **CRM** en backend y frontend.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,147 +13,110 @@ funcional listo para extender.
|
||||
|
||||
| Capa | Tecnología |
|
||||
|---|---|
|
||||
| Frontend | SvelteKit 5 + Tailwind CSS |
|
||||
| Backend | FastAPI + SQLAlchemy + PostgreSQL |
|
||||
| Auth | Keycloak (OpenID Connect) vía Workspace Hub |
|
||||
| Frontend | SvelteKit 5 (runes) + Tailwind + shadcn-svelte |
|
||||
| Backend | FastAPI + SQLAlchemy 2.0 + Pydantic v2 |
|
||||
| Auth | Keycloak (OIDC) vía Workspace Hub |
|
||||
| Base de datos | PostgreSQL (schema `crm`) |
|
||||
| Cache / Queue | Valkey (Redis) + Celery |
|
||||
| Storage | MinIO (S3-compatible) |
|
||||
| Contenedores | Docker Compose |
|
||||
|
||||
---
|
||||
|
||||
## Estructura del proyecto
|
||||
## Módulo CRM
|
||||
|
||||
```
|
||||
├── backend/
|
||||
│ ├── api/v1/modules/
|
||||
│ │ ├── core/ # Auth, usuarios, tenants, permisos, licencias
|
||||
│ │ └── example/ # Módulo de referencia — copia y renombra
|
||||
│ ├── core/ # Config, seguridad, DB, middleware
|
||||
│ └── alembic/ # Migraciones (solo esquema core)
|
||||
│
|
||||
├── frontend/
|
||||
│ ├── src/routes/
|
||||
│ │ ├── auth/ # Callback OAuth2, SSO, logout
|
||||
│ │ ├── login/ # Login local (dev) o redirect al workspace
|
||||
│ │ └── dashboard/ # Shell + rutas stub
|
||||
│ └── src/lib/
|
||||
│ ├── server/ # workspace-auth, workspace-apps, api SSR
|
||||
│ └── stores/ # company, system, workspace-apps
|
||||
│
|
||||
└── scripts/
|
||||
└── auth-mode.sh # Alterna entre modo local y workspace
|
||||
```
|
||||
Esquema dedicado `crm` con 7 tablas multi-tenant (`tenant_id` + `company_id`, soft delete):
|
||||
|
||||
| Entidad | Tabla | Descripción |
|
||||
|---|---|---|
|
||||
| Cuentas | `crm.accounts` | Empresas cliente/prospecto (importador, IMMEX, agencia aduanal, transportista). Incluye RFC y patente aduanal. |
|
||||
| Contactos | `crm.contacts` | Personas asociadas a una cuenta. |
|
||||
| Prospectos | `crm.leads` | Leads sin calificar; se convierten en cuenta + contacto + oportunidad. |
|
||||
| Embudos | `crm.pipelines` | Embudos de venta por compañía. |
|
||||
| Etapas | `crm.pipeline_stages` | Columnas del Kanban (con probabilidad y etapas terminales ganada/perdida). |
|
||||
| Oportunidades | `crm.opportunities` | Negocios que avanzan por el embudo. |
|
||||
| Actividades | `crm.activities` | Llamadas, reuniones, tareas, correos y notas. |
|
||||
|
||||
### Endpoints (prefijo `/v1/crm`)
|
||||
|
||||
Todos reciben `company_id` como query param y validan permisos vía Keycloak/`PermissionService`.
|
||||
|
||||
- `GET|POST /accounts`, `GET|PATCH|DELETE /accounts/{id}`
|
||||
- `GET|POST /contacts`, `GET|PATCH|DELETE /contacts/{id}`
|
||||
- `GET|POST /leads`, `GET|PATCH|DELETE /leads/{id}`, `POST /leads/{id}/convert`
|
||||
- `GET|POST /pipelines`, `PATCH|DELETE /pipelines/{id}`
|
||||
- `GET|POST /stages`, `PATCH|DELETE /stages/{id}`
|
||||
- `GET|POST /opportunities`, `GET|PATCH|DELETE /opportunities/{id}`, `PATCH /opportunities/{id}/move`
|
||||
- `GET|POST /activities`, `GET|PATCH|DELETE /activities/{id}`, `PATCH /activities/{id}/complete`
|
||||
- `GET /metrics` — KPIs y embudo por etapa para el dashboard
|
||||
|
||||
### Permisos
|
||||
|
||||
Se registran en el `PermissionRegistry` al arrancar (25 permisos: `crm.access` +
|
||||
`crm.{account,contact,lead,opportunity,pipeline,activity}.{view,create,edit,delete}`).
|
||||
Para persistirlos en BD: `POST /v1/core/permissions/sync` (o el CLI de sincronización).
|
||||
|
||||
---
|
||||
|
||||
## Inicio rápido
|
||||
|
||||
### 1. Clonar y configurar
|
||||
## Inicio rápido (dev)
|
||||
|
||||
```bash
|
||||
git clone https://git.aduanasoft.com/ADUANASOFT/plantillas-proyectos.git mi-proyecto
|
||||
cd mi-proyecto
|
||||
```
|
||||
|
||||
Renombrar el proyecto en `.env` y `docker-compose.yml`:
|
||||
- `CORE_DB_NAME=app_core` → `mi_proyecto_core`
|
||||
- `name: app` en `docker-compose.yml` → `mi-proyecto`
|
||||
|
||||
### 2. Levantar en modo local (sin workspace)
|
||||
|
||||
```bash
|
||||
./scripts/auth-mode.sh local
|
||||
cp .env.example .env # ajustar CORE_DB_NAME, Keycloak, etc.
|
||||
./scripts/auth-mode.sh local # login local sin workspace
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Abre `http://localhost:5173` → click **"Entrar como dev"**.
|
||||
Abre `http://localhost:5173` → **CRM** en el sidebar.
|
||||
|
||||
### 3. Conectar al workspace
|
||||
### Migraciones
|
||||
|
||||
```bash
|
||||
./scripts/auth-mode.sh workspace
|
||||
# Pregunta:
|
||||
# URL del workspace → https://workspace.aduanasoft.com
|
||||
# Keycloak Realm → master
|
||||
# Keycloak Client ID → nombre-del-client
|
||||
```
|
||||
|
||||
> El equipo del Hub debe registrar la app y agregar el redirect URI:
|
||||
> `http://localhost:5173/auth/callback`
|
||||
|
||||
---
|
||||
|
||||
## Variables de entorno
|
||||
|
||||
El `.env` usa una sola URL base para derivar toda la configuración del workspace:
|
||||
|
||||
```env
|
||||
# Una variable, todo se deriva de aquí
|
||||
WORKSPACE_URL=https://workspace.aduanasoft.com
|
||||
KEYCLOAK_REALM=master
|
||||
KEYCLOAK_CLIENT_ID=mi-app-frontend
|
||||
|
||||
# Auth local (desarrollo sin workspace)
|
||||
DEV_LOCAL_AUTH=False # True = botón "Entrar como dev"
|
||||
SECRET_KEY=... # Se genera automáticamente con auth-mode.sh local
|
||||
```
|
||||
|
||||
El `docker-compose.yml` construye automáticamente:
|
||||
- `HUB_URL` = `${WORKSPACE_URL}`
|
||||
- `VITE_KEYCLOAK_URL` = `${WORKSPACE_URL}/kcauth`
|
||||
|
||||
---
|
||||
|
||||
## Agregar un módulo nuevo
|
||||
|
||||
### Backend
|
||||
|
||||
Copia `backend/api/v1/modules/example/` y renombra:
|
||||
|
||||
```
|
||||
my_module/
|
||||
├── __init__.py
|
||||
├── models.py # SQLAlchemy — hereda TenantScopedMixin + TimestampMixin
|
||||
├── dto.py # Pydantic v2 — Request / Response separados
|
||||
├── service.py # Lógica de negocio, recibe db + tenant_id + company_id
|
||||
└── routes.py # FastAPI router, usa Depends(get_current_user)
|
||||
```
|
||||
|
||||
Registrar en `backend/api/v1/router.py`:
|
||||
|
||||
```python
|
||||
from .modules.my_module.routes import router as my_router
|
||||
router.include_router(my_router, prefix="/my-module", tags=["my-module"])
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
Crear `frontend/src/routes/dashboard/my-module/+page.svelte` y agregar al sidebar en
|
||||
`frontend/src/lib/components/sidebar/modules.ts`:
|
||||
|
||||
```typescript
|
||||
{ title: 'Mi módulo', url: '/dashboard/my-module', icon: MyIcon }
|
||||
cd backend
|
||||
alembic upgrade head # crea el schema crm y sus tablas (revisión f1a2b3c4d5e6)
|
||||
alembic downgrade -1 # revierte el CRM (down() probado)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Script auth-mode
|
||||
## Pruebas
|
||||
|
||||
Backend (servicios CRM):
|
||||
|
||||
```bash
|
||||
./scripts/auth-mode.sh status # Ver modo actual
|
||||
./scripts/auth-mode.sh local # Activar login local (dev sin workspace)
|
||||
./scripts/auth-mode.sh workspace # Configurar y conectar al workspace
|
||||
cd backend
|
||||
pytest tests/ -q # 24 pruebas de servicios (SQLite en memoria)
|
||||
```
|
||||
|
||||
Al cambiar de modo el script pregunta si reiniciar los contenedores automáticamente.
|
||||
En CI/PostgreSQL, define `TEST_DATABASE_URL` para ejercitar el esquema real y las
|
||||
políticas RLS (ver `docs/ARCHITECTURE.md`).
|
||||
|
||||
---
|
||||
|
||||
## Estructura del CRM
|
||||
|
||||
```
|
||||
backend/api/v1/modules/crm/
|
||||
├── router.py # agrega submódulos bajo /crm (y registra permisos)
|
||||
├── permissions.py # alta de permisos CRM en el registry
|
||||
├── accounts/ contacts/ leads/ pipelines/ opportunities/ activities/ metrics/
|
||||
│ └── models.py · dto.py · service.py · routes.py
|
||||
backend/alembic/versions/f1a2b3c4d5e6_crm_schema.py
|
||||
|
||||
frontend/src/
|
||||
├── lib/api/crm/ # clientes API tipados por entidad
|
||||
├── lib/components/crm/ # helpers de formato/etiquetas
|
||||
└── routes/dashboard/crm/
|
||||
├── +page.svelte # panel (KPIs + embudo)
|
||||
├── cuentas/ contactos/ prospectos/ actividades/ # CRUD
|
||||
└── oportunidades/ # Kanban con drag & drop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Convenciones
|
||||
|
||||
- **Commits**: Conventional Commits (`feat:`, `fix:`, `refactor:`, `chore:`)
|
||||
- **Branches**: `feature/DESC`, `fix/DESC`
|
||||
- **Nombres en código**: inglés; comentarios de lógica de negocio en español
|
||||
- **Backend**: Pydantic v2, async por default, routers por dominio
|
||||
- **Frontend**: SvelteKit 5 runes (`$state`, `$derived`, `$effect`), Tailwind utility-first
|
||||
- **Ramas**: `feature/AS-###-desc`, `fix/AS-###-desc`
|
||||
- **Código**: nombres en inglés, comentarios de negocio en español
|
||||
- **Backend**: Pydantic v2, routers por dominio, filtros multi-tenant explícitos
|
||||
- **Frontend**: runes (`$state`, `$derived`, `$effect`, `$props`), Tailwind utility-first
|
||||
|
||||
Reference in New Issue
Block a user