Gracias por tu interes en contribuir a EmerKit. Thank you for your interest in contributing to EmerKit.
# 1. Fork y clona / Fork and clone
git clone https://github.com/<tu-usuario>/EmerKit.git
cd EmerKit
# 2. Instala dependencias / Install dependencies
flutter pub get
# 3. Ejecuta tests / Run tests
flutter test
# 4. Crea tu rama / Create your branch
git checkout -b feat/mi-nueva-featureEmerKit sigue una arquitectura Feature-First DDD (Domain-Driven Design orientado a features).
EmerKit follows a Feature-First DDD (feature-oriented Domain-Driven Design) architecture.
lib/
├── shared/ # Capa compartida / Shared layer
│ ├── di/ # Service locator (DI)
│ ├── domain/entities/ # Severity, ToolCategory
│ ├── presentation/
│ │ ├── widgets/ # ToolScreenBase, ResultBanner, InfoCard...
│ │ ├── theme/
│ │ └── router/
│ └── utils/
└── features/ # Una carpeta por herramienta / One folder per tool
└── <feature>/
├── domain/ # Calculadoras, datos, logica pura / Calculators, data, pure logic
└── presentation/# Screens, widgets especificos / Specific screens & widgets
- Calculadores son Dart puro: sin imports de Flutter, sin dependencias externas. Calculators are pure Dart: no Flutter imports, no external dependencies.
- Un feature = una carpeta: toda la logica de una herramienta vive en su carpeta. One feature = one folder: all tool logic lives in its own folder.
- Shared es transversal: widgets, entidades y utilidades comunes. Shared is cross-cutting: common widgets, entities, and utilities.
- Seguimos las reglas de
flutter_lintsdefinidas enanalysis_options.yaml. We follow theflutter_lintsrules defined inanalysis_options.yaml. prefer_const_constructors,prefer_const_declarations,avoid_print.- Ejecuta
flutter analyzeantes de cada commit. Runflutter analyzebefore every commit.
- Entre features: usa
package:emerkit/...Cross-feature: usepackage:emerkit/... - Dentro del mismo feature: usa imports relativos. Within the same feature: use relative imports.
| Tipo / Type | Patron / Pattern | Ejemplo / Example |
|---|---|---|
| Calculadora / Calculator | <feature>_calculator.dart |
glasgow_calculator.dart |
| Datos / Data | <feature>_data.dart |
glasgow_data.dart |
| Pantalla / Screen | <feature>_screen.dart |
glasgow_screen.dart |
| Test | <feature>_calculator_test.dart |
glasgow_calculator_test.dart |
Usamos Conventional Commits. We use Conventional Commits.
<tipo>(<scope>): <descripcion>
feat(glasgow): add pediatric GCS variant
fix(o2): correct cylinder volume calculation
test(triage): add START triage edge cases
docs: update README with new tools
refactor(shared): extract result banner widget
ci: add Android build workflow
chore(deps): bump go_router to 14.9.0
| Tipo / Type | Uso / Usage |
|---|---|
feat |
Nueva funcionalidad / New feature |
fix |
Correccion de bug / Bug fix |
test |
Anadir o mejorar tests / Add or improve tests |
docs |
Documentacion / Documentation |
refactor |
Refactorizacion sin cambio funcional / No functional change |
ci |
Cambios en CI/CD / CI/CD changes |
chore |
Tareas de mantenimiento / Maintenance tasks |
glasgow, triage, ictus, o2, rcp, tep, nihss, rankin, shared, ci, docs
feat/<nombre-descriptivo> # Nueva herramienta o funcionalidad
fix/<nombre-descriptivo> # Correccion de bug
refactor/<nombre-descriptivo> # Refactorizacion
docs/<nombre-descriptivo> # Documentacion
test/<nombre-descriptivo> # Tests
Ejemplos / Examples:
feat/pediatric-glasgowfix/o2-calculation-roundingdocs/contributing-guide
# Todos los tests / All tests
flutter test
# Un archivo / Single file
flutter test test/domain/glasgow_calculator_test.dart
# Con cobertura / With coverage
flutter test --coverage-
Usa
flutter_test, nopackage:test. Useflutter_test, notpackage:test. -
Testea casos de uso clinicos, no metodos de clase. Test clinical use cases, not class methods.
// BIEN / GOOD: describe el caso clinico group('Paciente con minima puntuacion (coma profundo)', () { test('GCS 3 es Grave', () { final r = calculator.calculate(eye: 1, verbal: 1, motor: 1); expect(r.total, 3); expect(r.severity.level, SeverityLevel.severe); }); }); // MAL / BAD: describe el metodo test('calculate returns 3', () { ... });
-
Patron AAA (Arrange, Act, Assert). Use the AAA pattern (Arrange, Act, Assert).
-
Cada calculadora necesita tests antes de hacer merge. Every calculator needs tests before merging.
- Crea un fork y clona / Fork and clone.
- Crea una rama desde
main/ Create a branch frommain. - Desarrolla y escribe tests / Develop and write tests.
- Asegurate de que pasan todos los checks:
Make sure all checks pass:
flutter analyze flutter test - Abre un Pull Request describiendo los cambios. Open a Pull Request describing the changes.
- Espera la revision / Wait for review.
Guia paso a paso para anadir una herramienta clinica nueva. Step-by-step guide to adding a new clinical tool.
lib/features/<nueva_herramienta>/
├── domain/
│ ├── <herramienta>_calculator.dart # Logica pura en Dart
│ └── <herramienta>_data.dart # Datos estaticos (items, opciones)
└── presentation/
└── <herramienta>_screen.dart # Pantalla con widgets de shared/
// lib/features/mi_escala/domain/mi_escala_calculator.dart
// SIN imports de Flutter / NO Flutter imports
class MiEscalaResult {
final int total;
final Severity severity;
const MiEscalaResult({required this.total, required this.severity});
}
class MiEscalaCalculator {
const MiEscalaCalculator();
MiEscalaResult calculate({required int param1, required int param2}) {
final total = param1 + param2;
return MiEscalaResult(
total: total,
severity: _classify(total),
);
}
Severity _classify(int score) { /* ... */ }
}Usa los widgets compartidos / Use shared widgets:
ToolScreenBase-- estructura base de la pantallaResultBanner-- banner con el resultado y color de gravedadInfoCard-- tarjetas informativasScoredItemSelector-- selector de items con puntuacionToolInfoPanel-- panel de informacion de la herramienta
Anade la ruta en lib/shared/presentation/router/.
Add the route in lib/shared/presentation/router/.
// lib/features/home/presentation/tool_registry.dart
ToolEntry(
id: 'mi_escala',
name: 'Mi Escala',
icon: Icons.assessment,
route: '/mi-escala',
category: ToolCategory.valoracion,
),// test/domain/mi_escala_calculator_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:emerkit/features/mi_escala/domain/mi_escala_calculator.dart';
void main() {
const calculator = MiEscalaCalculator();
group('Caso clinico: paciente con puntuacion maxima', () {
test('devuelve gravedad leve', () {
final r = calculator.calculate(param1: 5, param2: 5);
expect(r.total, 10);
expect(r.severity.level, SeverityLevel.mild);
});
});
}flutter analyze
flutter test
flutter runSe respetuoso y constructivo. Este proyecto esta destinado a mejorar herramientas para profesionales que salvan vidas.
Be respectful and constructive. This project is aimed at improving tools for professionals who save lives.