mzone-images-storage
Imágenes de Zonas de Gestión — Almacenamiento y Migración
Documentación del almacenamiento de imágenes de zonas de gestión (management zones) para la migración.
Ubicación en el filesystem
Las imágenes se guardan usando @capacitor/filesystem con Directory.Data, dentro de un subdirectorio por usuario.
Ruta base por plataforma
| Plataforma | Directory.Data |
|---|---|
| Android | file:///data/user/0/com.auravant/files/ |
| iOS | file:///var/mobile/Containers/Data/Application/{APP_UUID}/Library/NoCloud/ |
Estructura de directorios
{Directory.Data}/
└── {userId}/
├── mZone/ ← imágenes permanentes
│ ├── {imgUuid1} ← archivo sin extensión
│ ├── {imgUuid2}
│ └── ...
└── mzTemp/ ← imágenes temporales (pre-guardado)
├── localName0
├── localName1
└── ...
Ejemplo real de path completo
file:///data/user/0/com.auravant/files/123456/mZone/a1b2c3d4-e5f6-11ee-b7c8-0242ac120002
Formato de nombre de archivos
| Directorio | Nombre del archivo | Descripción |
|---|---|---|
mZone/ | UUID v1 (sin extensión) | Imagen guardada permanentemente. El nombre es el uuid del objeto MZImg |
mzTemp/ | localName{N} (N = 0, 1, 2, 3) | Imagen temporal antes de confirmar la zona. Se borra al confirmar o cancelar |
- No tienen extensión de archivo. El mimetype se guarda por separado en el modelo de datos.
- Formato del contenido: base64 escrito directamente con
Filesystem.writeFile(). Al leer se obtiene base64 y se reconstruye condata:image/{mimetype};base64,{data}. - Máximo 4 imágenes por texto/nota (constante
LIMIT = 4enMZoneImageService).
Modelo de datos — Relación imagen ↔ zona
MZone (zona de gestión)
├── uuid: string ← ID de la zona
├── field_id: string ← ID del lote
├── texts: Array<MZText> ← notas/textos de la zona
│ └── MZText
│ ├── uuid: string ← ID del texto
│ ├── zone_id: string ← referencia al MZone.uuid
│ ├── text: string ← contenido del texto
│ └── images: Array<MZImg>
│ └── MZImg
│ ├── uuid: string ← ID de la imagen = NOMBRE DEL ARCHIVO en disco
│ ├── text_id: string ← referencia al MZText.uuid
│ ├── path: string ← URI completa del archivo en disco
│ ├── mimetype: string ← "jpeg" | "png" | "gif"
│ └── coordinates: string ← "POINT(lon lat)" o ""
Cómo se linkea la imagen con la zona
MZone.uuid → MZText.zone_id → MZImg.text_id
│
├── MZImg.uuid = nombre del archivo en mZone/
└── MZImg.path = URI completa (ej: file:///.../{userId}/mZone/{uuid})
Persistencia del modelo en SQLite
Las zonas de gestión (incluyendo las referencias a imágenes) se guardan en SQLite bajo la key "mz" en la tabla U{userId}:
-- Se lee igual que offline: por partes
SELECT data FROM "U{userId}" WHERE id = 'userkeyparts';
-- → {"mz": 2, "offline": 1, ...}
SELECT data FROM "U{userId}" WHERE id = 'mz1';
SELECT data FROM "U{userId}" WHERE id = 'mz2';
-- Concatenar y JSON.parse()
El JSON resultante tiene la estructura:
interface MZones {
[fieldId: string]: Array<MZone>;
}
Ejemplo:
{
"field-uuid-abc": [
{
"uuid": "zone-uuid-123",
"field_id": "field-uuid-abc",
"area": 50.5,
"code": "MZ-001",
"spot_name": "MZ-001",
"spot_shape": "POLYGON((-60.1 -33.2, ...))",
"tags": [{"uuid": "tag-1", "name": "Soja", "label": "Soja"}],
"vars": [{"name": "Rendimiento", "unitId": 1, "value": 3500}],
"timestamp_usr": "2024-01-15T10:30:00.00Z",
"texts": [
{
"uuid": "text-uuid-456",
"zone_id": "zone-uuid-123",
"text": "Zona con buen desarrollo",
"timestamp_usr": "2024-01-15T10:30:00.00Z",
"images": [
{
"uuid": "a1b2c3d4-e5f6-11ee-b7c8-0242ac120002",
"text_id": "text-uuid-456",
"path": "file:///data/user/0/com.auravant/files/123456/mZone/a1b2c3d4-e5f6-11ee-b7c8-0242ac120002",
"mimetype": "jpeg",
"coordinates": "POINT(-60.123 -33.456)"
}
]
}
]
}
]
}
Cola offline — PUTF de imágenes
Cuando se crea una zona con imágenes, se encola un PUTF por cada imagen en el sender mzone-img:
{
"id": 55,
"api": "/spots/msgs/imgs",
"body": "",
"method": "PUTF",
"opts": {
"params": {
"uuid": "a1b2c3d4-e5f6-11ee-b7c8-0242ac120002",
"mimetype": "jpeg",
"path": "file:///data/user/0/com.auravant/files/123456/mZone/a1b2c3d4-e5f6-11ee-b7c8-0242ac120002"
},
"headers": {
"Authorization": "Bearer eyJ..."
}
},
"eventData": {"msg": 104},
"attempts": 0,
"date": 1705312200000,
"userId": "123456"
}
Cómo se envía al servidor
- Se lee el archivo:
Filesystem.readFile({path: "{userId}/mZone/{uuid}"}) - Se convierte a blob:
fetch("data:image/{mimetype};base64,{data}").then(r => r.blob()) - Se envía como FormData:
PUT /spots/msgs/imgs?uuid={imgUuid}confd.append('img', blob)
Si el archivo no existe
Si al intentar enviar el archivo no se encuentra en disco (ej: el usuario borró datos), se emite el error 'path not found' y la request se elimina de la cola.
Pasos para migrar las imágenes
1. Leer el modelo de zonas desde SQLite
SELECT data FROM "U{userId}" WHERE id LIKE 'mz%' AND id != 'userkeyparts';
O mejor, leer userkeyparts → obtener cantidad de partes de mz → leer mz1, mz2, etc.
2. Parsear y recorrer las imágenes
const mZones: MZones = JSON.parse(concatenatedData);
for (const fieldId of Object.keys(mZones)) {
for (const zone of mZones[fieldId]) {
for (const text of zone.texts) {
for (const img of text.images) {
// img.uuid = nombre del archivo
// img.path = URI completa en disco
// img.mimetype = formato de la imagen
// Archivo en: {Directory.Data}/{userId}/mZone/{img.uuid}
}
}
}
}
3. Leer los archivos de imagen
Los archivos están en {Directory.Data}/{userId}/mZone/{imgUuid} como base64 (sin header, solo el contenido base64 raw).
4. Verificar imágenes pendientes en la cola offline
Si hay requests PUTF en requestQueue["mzone-img"], esas imágenes aún no se subieron al servidor. Se pueden identificar por:
method === "PUTF"opts.params.uuid= UUID de la imagenopts.params.path= path del archivo en disco
5. Imágenes que pueden no existir en disco
- Si
img.pathestá vacío ("") en el modelo, la imagen existe en el servidor pero nunca se descargó al dispositivo. - La descarga se hace bajo demanda via
GET /spots/msgs/imgs/{imgUuid}(retorna blob).
Resumen de relaciones
| Dato | Dónde está | Cómo se accede |
|---|---|---|
| Lista de zonas con sus imágenes | SQLite → U{userId} → key mz | Leer partes, concatenar, JSON.parse |
| Archivo de imagen | Filesystem → {userId}/mZone/{imgUuid} | Leer con Capacitor Filesystem (base64) |
| Request pendiente de subida | SQLite → U{userId} → key offline → requestQueue["mzone-img"] | Dentro del OfflineData |
| Metadata de imagen | Dentro del JSON de mZones | MZImg.uuid, .mimetype, .coordinates |
| Relación imagen → zona | MZImg.text_id → MZText.uuid → MZText.zone_id → MZone.uuid | Navegación jerárquica |