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)

View File

@@ -0,0 +1,55 @@
# Proposal: add-toldo-poc-capacitor
## Why
The Circuito de Economía Solidaria de Támesis (CESTA) needs a software solution to facilitate registration and control of products and expenses at Sunday markets held in the main park of the municipality.
Key business flows:
- Team rotation for managing the "Toldo" (canopy) each Sunday
- Initial inventory that should match previous week's final inventory, recording differences if any
- Sales registration (product, quantity, unit price, total value, payment method: cash or QR code)
- Expense registration during the day (tape, pens, bags, transportation, etc.)
- End-of-day cash reconciliation considering starting cash, sales, expenses
- End-of-day inventory that should match initial inventory minus sold products
- Reports by producer: inventory differences, initial inventory (real), inventory movements from sales, sales value, total per producer
- Cash reconciliation report with date/time, concept, income, expenses, balance; separate for cash and QR payments; track cash discrepancies and QR/bank differences; total sales (cash + QR)
- Ability to adjust initial inventory, sales, cash discrepancies, QR discrepancies with required change reason tracked in final report
- Store daily records with consolidated reports by date range, week, or month
- Add products mid-week/bodega restocks (register product, quantity, person who received)
- Products linked to a producer; same product name from different producers = different products (e.g., "Café molido 250gr Santa Ana" vs "Café molido 250gr Familia Gonzalez")
## Constraints
- Must work well offline (poor internet at park)
- Only a lightweight HTTP server to serve static files OR run as APK on Android tablet
- Data stored in browser storage (IndexedDB/localStorage) if web-based
- No user authentication required initially
- Must be able to export data to import on another device
- Must be Free/Libre Software
- Single git repo, possibility to add more folders/modules in future
## What Changes
Implement a Capacitor + Vite + TypeScript POC with:
- **Architecture**: Clean layered architecture (core/domain, data/infrastructure, services/application, ui/presentation) following SOLID principles
- **Storage**: Dexie.js over IndexedDB for structured offline storage
- **Packaging**: Capacitor to generate Android APK for tablet use; maintain web-first for static serving if needed
- **Testing**: TDD with Vitest, @testing-library, fake-indexeddb; mock Capacitor plugins
- **Export/Import**: Versioned JSON format for data portability between devices
- **Offline-first**: All assets bundled in APK, no backend required
## Impact
- **New apps**: `apps/toldo-app/` (Vite + Capacitor app)
- **New packages**: `packages/core/` (domain, pure TS), `packages/data/` (Dexie repos), `packages/services/` (use cases), `packages/ui/` (reusable components)
- **OpenSpec**: New change with specs
- **Agent Skills**: New skills for architecture, domain modeling, TDD, export/import
- **Android**: Capacitor Android platform configuration
## Non-Goals
- Real-time multi-device synchronization (CouchDB/PouchDB sync) - manual export/import is sufficient
- Barcode scanner integration (not requested in README)
- User authentication/authorization (explicitly not required initially)
- Complex PDF generation in first iteration (can be added later)
- TWA packaging (Capacitor direct APK preferred)

View File

@@ -0,0 +1,193 @@
# Spec: toldo-poc
## Capability: Inventario
### Requirement: Registrar inventario inicial
The system SHALL allow registering initial inventory for products at the start of market day.
#### Scenario: Registro de inventario inicial
- **GIVEN** products exist for producers
- **WHEN** user registers initial inventory with quantities for each product
- **THEN** movements of type INGRESO_INICIAL are recorded
- **AND** initial inventory is stored for the day
### Requirement: Detectar diferencias de inventario
The system SHALL detect and record differences between expected inventory (from previous day) and actual inventory.
#### Scenario: Diferencia detectada
- **GIVEN** there is a previous day's final inventory
- **WHEN** current inventory count differs from expected
- **THEN** the difference is recorded and visible in reports
- **AND** the real inventory is used going forward
### Requirement: Registrar ingresos entre semana
The system SHALL allow registering product restocks during the week to warehouse/bodega.
#### Scenario: Ingreso en semana
- **GIVEN** a product needs restocking
- **WHEN** user registers ingreso with product, quantity, and person who received
- **THEN** movement of type INGRESO_SEMANA is recorded with receivedBy
- **AND** inventory is updated
## Capability: Ventas
### Requirement: Registrar ventas
The system SHALL allow registering sales with product lines, quantities, prices, and payment method.
#### Scenario: Venta en efectivo
- **GIVEN** products with stock available
- **WHEN** user creates a sale with product lines paying in EFECTIVO
- **THEN** venta and ventaLineas are recorded
- **AND** inventory is decremented
- **AND** sale is counted in cash total
#### Scenario: Venta con QR
- **GIVEN** products with stock available
- **WHEN** user creates a sale with product lines paying in QR
- **THEN** sale is recorded with formaPago QR
- **AND** sale is counted in QR total separately
### Requirement: Productos distintos por productor
The system SHALL treat products from different producers as different products even if same name.
#### Scenario: Mismo nombre diferente productor
- **GIVEN** "Café molido 250gr" exists for Productor A and Productor B
- **WHEN** selling
- **THEN** they are different productos with different IDs
- **AND** reported separately by producer
## Capability: Gastos
### Requirement: Registrar gastos
The system SHALL allow registering expenses during the day.
#### Scenario: Gasto registrado
- **GIVEN** an expense occurs
- **WHEN** user registers gasto with concepto and monto
- **THEN** gasto is recorded with fecha
- **AND** included in cash reconciliation
## Capability: Cuadre de Caja
### Requirement: Realizar cuadre de caja
The system SHALL allow end-of-day cash reconciliation.
#### Scenario: Cuadre completo
- **GIVEN** base inicial, ventas (cash/QR), gastos (cash/QR) recorded
- **WHEN** user performs cuadre
- **THEN** saldoEsperadoEfectivo is calculated (base + ventas efectivo - gastos efectivo)
- **AND** user can enter saldoRealEfectivo
- **AND** descuadreEfectivo is calculated
- **AND** QR totals compared (registrado vs banco)
- **AND** totalVentas = ventas efectivo + ventas QR
### Requirement: Detectar descuadres
The system SHALL track and report discrepancies.
#### Scenario: Descuadre en efectivo
- **GIVEN** saldoEsperadoEfectivo != saldoRealEfectivo
- **WHEN** cuadre is saved
- **THEN** descuadreEfectivo is recorded
- **AND** visible in cuadre report
## Capability: Ajustes
### Requirement: Ajustes requieren motivo
The system SHALL require a reason for any adjustment.
#### Scenario: Ajustar inventario con motivo
- **GIVEN** need to adjust inventory
- **WHEN** user creates ajuste with producto, cantidadNueva, and motivo
- **THEN** ajuste is saved with motivo (non-empty)
- **AND** marked as modified/changed
- **AND** motivo appears in final report
### Requirement: Ajustes trazables
The system SHALL track all adjustments with before/after values.
#### Scenario: Trazabilidad de ajuste
- **GIVEN** an adjustment is made
- **THEN** cantidadAnterior, cantidadNueva, diferencia recorded
- **AND** fecha and motivo recorded
- **AND** appears in reports marked as changed
## Capability: Reportes
### Requirement: Reporte por productor
The system SHALL generate reports by producer.
#### Scenario: Reporte por productor completo
- **GIVEN** sales and inventory data for the day
- **WHEN** generating report by producer
- **THEN** shows inventory differences vs previous day
- **AND** shows initial inventory (real)
- **AND** shows inventory movements from sales (salidas)
- **AND** shows sales value for producer's products
- **AND** shows total per producer
### Requirement: Reporte de cuadre de caja
The system SHALL generate cash reconciliation report.
#### Scenario: Reporte cuadre
- **GIVEN** cuadre data
- **WHEN** generating report
- **THEN** shows fecha/hora, concepto, ingreso, gastos, saldo
- **AND** separate sections for efectivo and QR
- **AND** shows descuadres if any
- **AND** shows totalVentas (efectivo + QR)
### Requirement: Reporte consolidado
The system SHALL generate consolidated reports by date range, week, or month.
#### Scenario: Consolidado por rango
- **GIVEN** multiple days of data
- **WHEN** generating consolidated report for date range
- **THEN** aggregates sales, expenses, adjustments
- **AND** shows totals by producer
## Capability: Persistencia y Exportar/Importar
### Requirement: Exportar datos
The system SHALL export all data in versioned JSON format.
#### Scenario: Exportar
- **GIVEN** data exists in the app
- **WHEN** user exports
- **THEN** JSON file is generated with schemaVersion, appVersion, exportedAt, data
- **AND** file can be saved/shared
### Requirement: Importar datos
The system SHALL import data with validation and migration support.
#### Scenario: Importar válido
- **GIVEN** a valid exported JSON file
- **WHEN** user imports
- **THEN** schemaVersion is validated
- **AND** data is migrated if needed or imported directly
- **AND** data is stored in local DB
#### Scenario: Importar incompatible
- **GIVEN** JSON with incompatible schemaVersion
- **WHEN** user imports
- **THEN** clear error message is shown
- **AND** import is rejected
## Capability: Offline y Empaquetado
### Requirement: Funcionar offline
The system SHALL work completely offline.
#### Scenario: Modo avión
- **GIVEN** app installed/running with no network
- **WHEN** performing all operations (inventory, sales, expenses, reports)
- **THEN** all operations work correctly
- **AND** data persists locally
### Requirement: Empaquetado APK
The system SHALL be buildable as Android APK via Capacitor.
#### Scenario: Generar APK
- **GIVEN** built web assets
- **WHEN** running cap sync android
- **THEN** Android project is updated
- **AND** APK can be built and installed on Android tablet

View File

@@ -0,0 +1,71 @@
# Tasks: add-toldo-poc-capacitor
## 1. Setup & Scaffolding
- [ ] 1.1 Create mono-repo structure (apps/, packages/, openspec/, skills/, docs/)
- [ ] 1.2 Initialize Vite + TypeScript in apps/toldo-app
- [ ] 1.3 Create packages/core, packages/data, packages/services, packages/ui with package.json
- [ ] 1.4 Configure TypeScript path aliases for all packages
- [ ] 1.5 Setup Vitest, jsdom, @testing-library dependencies
- [ ] 1.6 Initialize Capacitor (@capacitor/core, @capacitor/cli) and add Android platform
- [ ] 1.7 Configure capacitor.config.ts (webDir: dist)
- [ ] 1.8 Setup linting (eslint) and basic scripts
## 2. Domain Layer (packages/core) - TDD First
- [ ] 2.1 Define types/interfaces for all entities (Productor, Producto, Venta, etc.)
- [ ] 2.2 Create value objects (Money, Quantity) if needed
- [ ] 2.3 Write tests for business rules (productos by productor uniqueness)
- [ ] 2.4 Write tests for adjustment rules (require motivo)
- [ ] 2.5 Write tests for inventory calculations
- [ ] 2.6 Write tests for cuadre calculations
- [ ] 2.7 Implement pure domain logic to pass tests
- [ ] 2.8 Define repository interfaces in core/contracts
## 3. Data Layer (packages/data) - Integration Tests
- [ ] 3.1 Install Dexie.js
- [ ] 3.2 Define Dexie schema with version 1
- [ ] 3.3 Write tests for repositories using fake-indexeddb
- [ ] 3.4 Implement repository implementations
- [ ] 3.5 Add schema migrations support
- [ ] 3.6 Test CRUD operations for all entities
## 4. Services Layer (packages/services) - Use Cases
- [ ] 4.1 Write tests for InventarioService (initial inventory, differences, week restocks)
- [ ] 4.2 Implement InventarioService
- [ ] 4.3 Write tests for VentasService
- [ ] 4.4 Implement VentasService
- [ ] 4.5 Write tests for GastosService
- [ ] 4.6 Implement GastosService
- [ ] 4.7 Write tests for AjustesService (require motivo)
- [ ] 4.8 Implement AjustesService
- [ ] 4.9 Write tests for CuadreService (cash/QR calculations)
- [ ] 4.10 Implement CuadreService
- [ ] 4.11 Write tests for ReportesService
- [ ] 4.12 Implement ReportesService
- [ ] 4.13 Write tests for ExportImportService (versioned JSON)
- [ ] 4.14 Implement ExportImportService with validation/migrations
## 5. UI Layer (packages/ui + apps/toldo-app)
- [ ] 5.1 Create base UI components (Button, Input, Card, etc.) - small and reusable
- [ ] 5.2 Write tests for UI components with Testing Library
- [ ] 5.3 Create composables/hooks for business logic (separate from presentation)
- [ ] 5.4 Build pages: Dashboard, Inventario, Ventas, Gastos, Cuadre, Reportes, Ajustes, Config/Export-Import
- [ ] 5.5 Ensure components follow SRP, small size, no direct DB/Capacitor imports
- [ ] 5.6 Add routing
## 6. Capacitor & Android Integration
- [ ] 6.1 Configure capacitor.config.ts properly
- [ ] 6.2 Add @capacitor/android platform files
- [ ] 6.3 Setup app icons/splash (basic)
- [ ] 6.4 Test build: npm run build && npx cap sync android
- [ ] 6.5 Verify offline functionality
- [ ] 6.6 Document APK build process
## 7. Quality Gates & Documentation
- [ ] 7.1 Run typecheck - all packages pass
- [ ] 7.2 Run lint - no errors
- [ ] 7.3 Run tests - all pass
- [ ] 7.4 Build succeeds
- [ ] 7.5 Create ADR 0001 documenting architecture decision
- [ ] 7.6 Update README with setup instructions
- [ ] 7.7 Validate OpenSpec change structure
- [ ] 7.8 Review against all skills/checklists