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,97 @@
# Agent Skill: toldo-architecture-solid
## Metadata
```yaml
name: toldo-architecture-solid
description: Guía para mantener arquitectura limpia con SOLID, separación lógica/presentación, componentes pequeños/reutilizables y DI. Aplicar estrictamente en este proyecto.
```
## When to use
Use this skill when:
- Creating new packages/modules
- Designing components or services
- Reviewing code for architectural violations
- Refactoring to improve structure
- Deciding where code should live
## Architecture Layers
### Layer Responsibilities
| Layer | Location | Responsibility | Can Import | Cannot Import |
|-------|----------|----------------|------------|---------------|
| **Domain** | `packages/core/` | Entities, value objects, business rules, repository interfaces | Nothing (pure TS) | data, services, ui, apps, @capacitor/*, frameworks |
| **Infrastructure/Data** | `packages/data/` | Repository implementations, DB schema/migrations, external adapters | core/ | services, ui, apps, @capacitor/* in business logic |
| **Application/Services** | `packages/services/` | Use cases, orchestration, application logic | core/, data/ | ui, apps (business logic), @capacitor/* directly |
| **Presentation/UI** | `packages/ui/` | Reusable UI components, design system | core/, services/ via interfaces | data/ directly, @capacitor/* directly |
| **App/Composition** | `apps/toldo-app/` | Composition root, routing, DI setup, Capacitor integration | All packages | - (can import anything, but keep orchestration here) |
## SOLID Checklist
### Single Responsibility Principle (SRP)
- [ ] Each class/function does one thing
- [ ] Components have single purpose
- [ ] Services handle one domain area or specific use case
- [ ] Files are focused (< ~200 lines ideally, < 150 for components)
### Open/Closed Principle (OCP)
- [ ] Use interfaces for extensibility
- [ ] Prefer composition over inheritance
- [ ] New features via new classes/functions, not modifying existing tested code
### Liskov Substitution Principle (LSP)
- [ ] Implementations are substitutable for interfaces
- [ ] No breaking contracts
### Interface Segregation Principle (ISP)
- [ ] Small, focused interfaces
- [ ] Repositories have specific methods, not "god" interfaces
- [ ] Clients don't depend on unused methods
### Dependency Inversion Principle (DIP)
- [ ] Core defines interfaces (ports)
- [ ] Data/services implement/adapt (adapters)
- [ ] Depend on abstractions, inject dependencies
- [ ] No `new` of concrete implementations deep in business logic
## Component Guidelines
### Component Rules
- **Small and focused**: One responsibility per component
- **Presentation-first**: Minimal logic, delegate to composables/services
- **Props down, events up**: Clear data flow
- **Reusable**: Generic where possible, specific where needed
- **No business rules**: Calculations/validations belong in core/services
- **No direct DB access**: Use services through DI/composition
- **No direct Capacitor imports**: Go through adapters/services
### Composables/Hooks
- Extract reusable logic to composables/hooks
- Keep UI concerns separate from business logic
- Make testable in isolation
## Anti-Patterns to Avoid
- ❌ Importing Dexie directly in UI components
- ❌ Importing @capacitor/* in core/services/ui packages
- ❌ Business logic in Vue/React/Svelte components
- ❌ God classes/components doing too much
- ❌ Circular dependencies
- ❌ `any` types
- ❌ Tight coupling to frameworks in domain
## Review Checklist
Before committing:
- [ ] Dependencies follow layer rules
- [ ] Component < ~150 lines
- [ ] No business logic in presentation
- [ ] Uses interfaces, not concrete classes
- [ ] Tested appropriately
- [ ] TypeScript strict compliant
- [ ] Follows naming conventions
- [ ] No circular deps
## Resources
- See `openspec/changes/add-toldo-poc-capacitor/design.md` for full architecture
- Follow dependency rules strictly
- When in doubt, put logic in core/ or services/, keep UI dumb

View File

@@ -0,0 +1,127 @@
# Agent Skill: toldo-domain-modeling
## Metadata
```yaml
name: toldo-domain-modeling
description: Modelado de dominio CESTA (productos por productor, inventario, ventas, gastos, ajustes con motivo, cuadre QR/efectivo, reportes). Seguir reglas de negocio estrictamente.
```
## When to use
Use this skill when:
- Modeling entities, value objects, or aggregates
- Implementing business rules
- Writing domain logic
- Creating use cases related to CESTA flows
- Validating invariants
## Core Domain Concepts
### Products are unique per producer
**Critical Rule**: Same product name from different producers = DIFFERENT products.
```typescript
// CORRECT
Producto { productorId: "A", nombrePresentacion: "Café molido 250gr Santa Ana" }
Producto { productorId: "B", nombrePresentacion: "Café molido 250gr Familia Gonzalez" }
// WRONG - same entity for different producers
```
Uniqueness constraint: `(productorId, nombrePresentacion)`
### Adjustments require reason
**Critical Rule**: ALL adjustments MUST have a non-empty `motivo`.
- Adjustments to inventory, sales, cash discrepancies, QR discrepancies all require reason
- Adjustments are tracked separately
- Must appear marked as "modificado/cambiado" in reports
- Store `cantidadAnterior`, `cantidadNueva`, `diferencia`, `motivo`
### Inventory Management
- **Initial inventory**: Should match previous day's final inventory
- **Differences**: If different, record difference and use real inventory
- **Week restocks**: Register with producto, cantidad, recibidoPor (person who received)
- **End-of-day**: Should match initial inventory minus sold products
### Sales
- Lines with: productoId, cantidad, precioUnitario, formaPago (EFECTIVO | QR)
- Track separately for cash and QR reconciliation
- Each sale line has subtotal
### Expenses (Gastos)
- Track during day: tape, pens, bags, transportation, etc.
- Include in reconciliation
### Cash Reconciliation (Cuadre)
```typescript
saldoEsperadoEfectivo = baseInicial + totalVentasEfectivo - totalGastosEfectivo
descuadreEfectivo = saldoRealEfectivo - saldoEsperadoEfectivo (or vice versa, track clearly)
totalVentas = totalVentasEfectivo + totalVentasQR
```
- Separate cash and QR
- Compare QR registrado vs QR banco
- Track discrepancies
### Reports by Producer
Must include:
1. Inventory differences vs previous day
2. Initial inventory (real)
3. Inventory movements from sales (salidas)
4. Sales value for producer's products
5. Total per producer
### Consolidated Reports
By date range, week, or month aggregating all data.
## Value Objects
Prefer value objects for primitives that have business meaning:
```typescript
// Money value object
class Money {
constructor(private readonly cents: number) {}
add(other: Money): Money { ... }
subtract(other: Money): Money { ... }
// ...
}
// Quantity
class Quantity {
constructor(private readonly value: number) {}
// ensure non-negative, etc.
}
```
## Domain Invariants
Enforce these invariants:
- [ ] Producto has valid productorId
- [ ] Ajuste always has non-empty motivo
- [ ] Venta has at least one line
- [ ] Cuadre calculations are consistent
- [ ] Inventory movements are traceable
- [ ] Payment methods are only EFECTIVO or QR
## TDD for Domain
**Always write tests first for domain logic:**
1. Write failing test for rule/invariant
2. Implement minimal code to pass
3. Refactor
4. Repeat
Domain tests should be pure, fast, no I/O, no framework dependencies.
## Common Pitfalls
- ❌ Treating same product name as same product across producers
- ❌ Allowing adjustments without motivo
- ❌ Mixing cash and QR totals
- ❌ Not tracking receivedBy for week restocks
- ❌ Forgetting to mark adjustments as changed in reports
- ❌ Losing traceability of modifications
## Resources
- See `openspec/changes/add-toldo-poc-capacitor/specs/toldo-poc/spec.md` for all scenarios
- See `design.md` for full entity definitions
- Follow all business rules strictly

View File

@@ -0,0 +1,160 @@
# Agent Skill: toldo-offline-export-import
## Metadata
```yaml
name: toldo-offline-export-import
description: Exportar/importar JSON versionado, migraciones de esquema, validación e integridad para uso offline/APK. Funciona sin red.
```
## When to use
Use this skill when:
- Implementing export functionality
- Implementing import functionality
- Handling schema migrations
- Versioning data formats
- Ensuring data portability between devices
## Export Format (Versioned JSON)
```typescript
interface ExportData {
schemaVersion: number; // Database/schema version
appVersion: string; // App version
exportedAt: string; // ISO 8601 timestamp
data: {
productores: Productor[];
productos: Producto[];
movimientosInventario: MovimientoInventario[];
ventas: Venta[];
ventaLineas: VentaLinea[];
gastos: Gasto[];
ajustes: Ajuste[];
cuadres: CuadreCaja[];
};
}
```
## Export Requirements
- [ ] Include all entities
- [ ] Use current schemaVersion
- [ ] Include appVersion
- [ ] Include exportedAt timestamp
- [ ] Pretty print or compact JSON (both fine)
- [ ] Filename suggestion: `toldo-export-YYYY-MM-DD-HHMMSS.json`
- [ ] Works offline (no network calls)
## Import Requirements
- [ ] Validate JSON structure
- [ ] Check schemaVersion compatibility
- [ ] Migrate data if schemaVersion is older (supported migration path)
- [ ] Reject if schemaVersion is newer and no migration path (with clear message)
- [ ] Validate required fields
- [ ] Handle errors gracefully with user-friendly messages
- [ ] Option to backup current data before import? (recommended)
- [ ] Works offline
## Migration Strategy
```typescript
function migrateExport(exportData: ExportData): ExportData {
let data = { ...exportData };
// Migrate from older versions
while (data.schemaVersion < CURRENT_SCHEMA_VERSION) {
data = migrateToNextVersion(data);
}
if (data.schemaVersion > CURRENT_SCHEMA_VERSION) {
throw new Error(
`Incompatible schema version: ${data.schemaVersion}. ` +
`Current app supports up to ${CURRENT_SCHEMA_VERSION}. ` +
`Please update the app.`
);
}
return data;
}
function migrateToNextVersion(data: ExportData): ExportData {
// Implement version-specific migrations
// Example: add new fields with defaults
switch (data.schemaVersion) {
case 1:
// migrate v1 -> v2
return { ...data, schemaVersion: 2, data: migratedData };
default:
throw new Error('Unknown schema version');
}
}
```
## Validation
```typescript
function validateExport(data: unknown): data is ExportData {
// Check structure
if (!isObject(data)) throw new Error('Invalid export format');
if (typeof data.schemaVersion !== 'number') throw new Error('Missing schemaVersion');
if (typeof data.appVersion !== 'string') throw new Error('Missing appVersion');
if (!data.exportedAt) throw new Error('Missing exportedAt');
if (!isObject(data.data)) throw new Error('Missing data');
// Validate data arrays exist
const required = ['productores', 'productos', 'ventas', 'gastos', ...];
for (const key of required) {
if (!Array.isArray(data.data[key])) throw new Error(`Missing or invalid ${key}`);
}
return true;
}
```
## Usage in Capacitor
For APK/native, can use:
- `@capacitor/filesystem` to save/load files
- Web File API as fallback
- Share API if available
Always mock in tests.
```typescript
// In tests
vi.mock('@capacitor/filesystem', () => ({
Filesystem: {
writeFile: vi.fn().mockResolvedValue({ uri: 'file://' }),
readFile: vi.fn().mockResolvedValue({ data: '...' }),
},
}));
```
## Distribution Between Devices
- Export on device A (tablet at market or home)
- Transfer via USB/OTG to device B
- Import on device B
- All offline, no network needed
- Works with any file manager
## Best Practices
- [ ] Always version exports
- [ ] Validate before importing
- [ ] Provide clear error messages
- [ ] Don't silently corrupt data
- [ ] Test migrations with real export files
- [ ] Keep backward compatibility when possible
- [ ] Log migration steps for debugging
- [ ] Consider backing up before destructive import
## Error Messages
Be user-friendly in Spanish (app is for CESTA in Colombia):
- "Formato de archivo inválido"
- "Versión de esquema incompatible. Actualice la aplicación."
- "Error al leer el archivo"
- "Datos importados correctamente"
## Resources
- See `openspec/changes/add-toldo-poc-capacitor/specs/toldo-poc/spec.md` for scenarios
- JSON versioned format is critical for long-term maintainability
- Test import/export round-trip

View File

@@ -0,0 +1,175 @@
# Agent Skill: toldo-tdd-vitest
## Metadata
```yaml
name: toldo-tdd-vitest
description: Workflow TDD con Vitest para Vite+Capacitor. Mock de plugins, fake-indexeddb, Testing Library. Ciclo Red-Green-Refactor estricto.
```
## When to use
Use this skill when:
- Writing tests
- Implementing features with TDD
- Setting up test infrastructure
- Mocking dependencies (Capacitor plugins, Dexie)
- Testing components
## TDD Workflow (Red-Green-Refactor)
### For Domain/Core (MANDATORY TDD)
1. **RED**: Write a failing test that describes the behavior
2. **GREEN**: Write minimal code to make the test pass
3. **REFACTOR**: Improve code while keeping tests green
4. **REPEAT**: Next test case
### For Data/Services
Write tests, can use mocks/fake DB. Still prefer test-first when possible.
### For UI
Test behavior and user interactions, not implementation details.
## Setup
### Dependencies
```json
{
"devDependencies": {
"vitest": "^1.0.0",
"jsdom": "^23.0.0",
"@testing-library/vue": "^8.0.0", // or @testing-library/react/svelte
"@testing-library/user-event": "^14.0.0",
"fake-indexeddb": "^5.0.0"
}
}
```
### vitest.config.ts
```typescript
import { defineConfig } from 'vitest/config';
import path from 'path';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./tests/setup.ts'],
},
resolve: {
alias: {
'@core': path.resolve(__dirname, '../../packages/core/src'),
'@data': path.resolve(__dirname, '../../packages/data/src'),
'@services': path.resolve(__dirname, '../../packages/services/src'),
'@ui': path.resolve(__dirname, '../../packages/ui/src'),
},
},
});
```
### tests/setup.ts
```typescript
import 'fake-indexeddb/auto';
```
## Mocking Capacitor Plugins
**NEVER** test against real Capacitor plugins. Always mock.
```typescript
import { vi } from 'vitest';
vi.mock('@capacitor/core', () => ({
Capacitor: {
isNativePlatform: () => false,
getPlatform: () => 'web',
},
}));
vi.mock('@capacitor/filesystem', () => ({
Filesystem: {
writeFile: vi.fn(),
readFile: vi.fn(),
},
}));
```
## Testing with Dexie (fake-indexeddb)
```typescript
import { describe, it, expect, beforeEach } from 'vitest';
import { db } from '../db';
describe('ProductorRepository', () => {
beforeEach(async () => {
await db.delete();
await db.open();
});
it('should create productor', async () => {
// test...
});
});
```
## Testing UI Components
Use @testing-library best practices:
- Query by role, label, text (accessible queries)
- Use userEvent for interactions
- Test behavior, not implementation
- Avoid testing internal state
```typescript
import { render, screen } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import Button from './Button.vue';
it('calls onClick when clicked', async () => {
const user = userEvent.setup();
const onClick = vi.fn();
render(Button, { props: { onClick } });
await user.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalled();
});
```
## Commands
```bash
# Run tests in watch mode (TDD)
npm test -- --watch
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run specific file
npm test path/to/file.test.ts
```
## Rules
- **Core tests**: Pure unit tests, no mocks needed, fast
- **Data tests**: Use fake-indexeddb, test in isolation
- **Services tests**: Mock repositories
- **UI tests**: Use Testing Library, mock services/composables
- **Capacitor**: Always mock in unit/integration tests
- **No tests in APK/emulator for initial development** - web tests are sufficient
- **Keep tests fast** - if slow, something is wrong
- **One assertion concept per test** when possible
## TDD Checklist
- [ ] Test written before implementation (for core)
- [ ] Test fails initially (RED)
- [ ] Minimal implementation makes it pass (GREEN)
- [ ] Code refactored (REFACTOR)
- [ ] All tests still pass
- [ ] Test is meaningful and tests behavior
## Resources
- [Vitest Docs](https://vitest.dev/)
- [Testing Library](https://testing-library.com/)
- [fake-indexeddb](https://github.com/dumbmatter/fakeIndexedDB)
- Follow Red-Green-Refactor strictly for domain logic