feat: estructura base OpenSpec + Skills + arquitectura limpia Capacitor+Dextie

This commit is contained in:
mono
2026-10-24 20:49:29 -05:00
parent 2e6262b5a5
commit 0c7cf651ce
1659 changed files with 265883 additions and 0 deletions

View File

@@ -0,0 +1,205 @@
# Design: add-toldo-poc-capacitor
## Architecture Overview
This project follows a clean, layered architecture to ensure testability, maintainability, and ease of evolution.
```
┌─────────────────────────────────────────────────────────────┐
│ apps/toldo-app │
│ (Vite + Capacitor UI) │
└─────────────────────────┬───────────────────────────────────┘
│ depends on
┌─────────────────────────▼───────────────────────────────────┐
│ packages/ui │
│ (Reusable, small UI components) │
└─────────────────────────┬───────────────────────────────────┘
│ depends on
┌─────────────────────────▼───────────────────────────────────┐
│ packages/services │
│ (Application use cases/orchestration) │
└─────────────┬───────────────────────────┬───────────────────┘
│ depends on │ depends on
┌─────────────▼───────────┐ ┌───────────▼───────────────────┐
│ packages/data │ │ packages/core │
│ (Dexie, repositories) │ │ (Domain, entities, rules) │
└─────────────────────────┘ └───────────────────────────────┘
```
### Dependency Rules (Critical)
- **core/**: NO dependencies on data/, services/, ui/, apps/, @capacitor/*, or any framework. Pure TypeScript only.
- **data/**: Depends only on core/. Implements repository interfaces defined in core/ or data/contracts.
- **services/**: Depends on core/ and data/. Contains application logic/use cases. No direct UI dependencies.
- **ui/**: Depends on core/ and services/ via interfaces/contracts. No direct Dexie or Capacitor imports.
- **apps/toldo-app/**: Assembles everything, configures DI/composition root, handles Capacitor plugins (mockable), UI composition only here.
## SOLID Principles
- **Single Responsibility (SRP)**: Each class/function/module has one reason to change. Components are small and focused.
- **Open/Closed (OCP)**: Open for extension, closed for modification. Use interfaces and composition.
- **Liskov Substitution (LSP)**: Subtypes must be substitutable for base types.
- **Interface Segregation (ISP)**: Many specific interfaces over one general interface. Repository interfaces are granular.
- **Dependency Inversion (DIP)**: Depend on abstractions, not concretions. core defines interfaces, data implements them.
## Domain Model
### Core Entities
```typescript
// Producer
interface Productor {
id: string;
nombre: string;
activo: boolean;
createdAt: Date;
}
// Product - different per producer even if same name
interface Producto {
id: string;
productorId: string;
nombrePresentacion: string; // e.g., "Café molido 250gr Santa Ana"
precioUnitario: number;
activo: boolean;
createdAt: Date;
}
// Initial inventory / movements
interface MovimientoInventario {
id: string;
fecha: Date;
tipo: 'INGRESO_INICIAL' | 'INGRESO_SEMANA' | 'AJUSTE' | 'VENTA';
productoId: string;
cantidad: number;
motivo?: string; // required for AJUSTE
recibidoPor?: string;
referenciaId?: string; // links to venta/ajuste
createdAt: Date;
}
// Sale
interface Venta {
id: string;
fecha: Date;
lineas: VentaLinea[];
subtotal: number;
total: number;
createdAt: Date;
}
interface VentaLinea {
id: string;
ventaId: string;
productoId: string;
cantidad: number;
precioUnitario: number;
subtotal: number;
formaPago: 'EFECTIVO' | 'QR';
}
// Expense
interface Gasto {
id: string;
fecha: Date;
concepto: string;
monto: number;
formaPago?: 'EFECTIVO' | 'QR';
createdAt: Date;
}
// Adjustment with reason
interface Ajuste {
id: string;
fecha: Date;
productoId: string;
cantidadAnterior: number;
cantidadNueva: number;
diferencia: number;
motivo: string; // REQUIRED
modificadoPor?: string;
createdAt: Date;
}
// Cash reconciliation
interface CuadreCaja {
id: string;
fecha: Date;
baseInicial: number;
totalVentasEfectivo: number;
totalVentasQR: number;
totalGastosEfectivo: number;
totalGastosQR: number;
saldoEsperadoEfectivo: number;
saldoRealEfectivo?: number;
descuadreEfectivo?: number;
totalQRRegistrado?: number;
totalQRBanco?: number;
descuadreQR?: number;
totalVentas: number;
observaciones?: string;
createdAt: Date;
}
```
### Critical Rules
1. **Products unique by producer**: `producto` is uniquely identified by `(productorId, nombrePresentacion)`. Same name from different producers = different products.
2. **Adjustments require reason**: All adjustments must have a non-empty `motivo`. Adjustments are tracked separately and marked as changed in reports.
3. **Inventory reconciliation**: Initial inventory vs real differences must be recorded. End-of-day inventory should match initial inventory minus sold products.
4. **Cash vs QR separation**: Track cash and QR separately in sales, expenses, and reconciliation. Compare QR registered vs bank.
5. **Traceability**: All modifications (adjustments to inventory/sales/cash discrepancies/QR discrepancies) must be logged with reason.
6. **Movements**: Track inventory movements both on market day and during the week (week restocks).
## Data Layer (Dexie)
### Schema Versioning
- Database schema versioned with Dexie migrations
- Export/import JSON has `schemaVersion`, `appVersion`, `exportedAt`
- Import validates versions and migrates or rejects with clear message
### Tables
```typescript
db.version(1).stores({
productores: 'id, nombre, activo',
productos: 'id, productorId, nombrePresentacion, [productorId+nombrePresentacion]',
movimientosInventario: 'id, fecha, tipo, productoId',
ventas: 'id, fecha',
ventaLineas: 'id, ventaId, productoId, formaPago',
gastos: 'id, fecha',
ajustes: 'id, fecha, productoId',
cuadres: 'id, fecha'
});
```
### Repository Pattern
All data access goes through repository interfaces in core/contracts or data/contracts. Implementations in packages/data using Dexie.
## Testing Strategy
| Layer | Tool | Approach |
|-------|------|----------|
| Core (domain/rules) | Vitest | **TDD mandatory** - write tests first, pure unit tests, no mocks needed |
| Data (repos) | Vitest + fake-indexeddb | Integration tests with in-memory IndexedDB |
| Services (use cases) | Vitest | Unit tests with mocked repositories |
| UI components | Vitest + @testing-library/* | Test behavior, not implementation; user interactions |
| Capacitor plugins | vi.mock | Always mock @capacitor/* in unit tests |
## Build & Distribution
- **Dev**: `vite` dev server
- **Web build**: `vite build` outputs to `dist/`, servable by static HTTP server
- **Capacitor sync**: `npx cap sync android` copies web assets and updates native project
- **APK**: Build via Android Studio or `./gradlew assembleDebug` in android/ folder
- **Offline**: All assets bundled in APK, IndexedDB persists data, no network required
## Quality Gates
- TypeScript strict mode enabled
- All core logic tested (TDD)
- Components small and focused (< ~150 lines when possible)
- Linting passes
- Type checking passes
- Tests pass
- Build succeeds
- SOLID principles followed (validated by architecture skill)