chore: archivar cambio add-toldo-poc-capacitor, mover spec a openspec/specs
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user