diff --git a/.roadmap/Core 1/changes/AgentsLogs/2026-08-07-GPT-5.6-Luna-core1-ci-fix.md b/.roadmap/Core 1/changes/AgentsLogs/2026-08-07-GPT-5.6-Luna-core1-ci-fix.md new file mode 100644 index 00000000..d3b062b4 --- /dev/null +++ b/.roadmap/Core 1/changes/AgentsLogs/2026-08-07-GPT-5.6-Luna-core1-ci-fix.md @@ -0,0 +1,26 @@ +# Core 1 CI correction log + +Date: 2026-08-07 +model: GPT-5.6 Luna +Route: app/src/main/java/com/elitec/alejotaller/feature/product/data/repository/ProductNetRepositoryImpl.kt +Description: Ajusté las operaciones atómicas de stock de Core 1 para adaptar los valores enteros del dominio (`quantity`, `maxReserved`) al contrato `Double?` exigido por el SDK Android de Appwrite. Se mantuvo el dominio de inventario como cantidades enteras y el cambio se limita a la frontera de infraestructura. `incrementReserved` usa `toDouble()` para `value` y `max`, mientras `decrementReserved` usa `toDouble()` para `value` y `0.0` como mínimo. El objetivo es resolver el error de compilación `Int` vs `Double?` reportado por `:app:compileDebugKotlin` sin alterar la semántica de stock. + +Date: 2026-08-07 +model: GPT-5.6 Luna +Route: shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/mapper/Document.toSaleDto.kt +Description: Migré el mapper de ventas de `Document>` a `Row>` para eliminar la dependencia del modelo obsoleto de Databases y permitir la migración del repositorio de ventas a TablesDB. Se conservaron las reglas existentes de conversión de fecha, monto, productos, estado de compra, usuario y `stockHoldApplied`. + +Date: 2026-08-07 +model: GPT-5.6 Luna +Route: shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/repository/SaleNetRepositoryImpl.kt +Description: Migré las operaciones de ventas de la API obsoleta de Appwrite Databases (`listDocuments`, `getDocument`, `createDocument`, `updateDocument`) a `TablesDB` (`listRows`, `getRow`, `createRow`, `updateRow`). El cambio conserva el mismo flujo de dominio, filtros, IDs y payloads, pero utiliza el modelo actual de Rows recomendado por Appwrite. Esto elimina los warnings de obsolescencia observados durante `:shared-data:compileDebugKotlin`. + +Date: 2026-08-07 +model: GPT-5.6 Luna +Route: app/src/main/java/com/elitec/alejotaller/infraestructure/di/infrastructureDiModule.kt +Description: Registré `TablesDB` como dependencia de infraestructura de Appwrite para que `SaleNetRepositoryImpl` pueda consumir el servicio moderno sin eliminar `Databases`, ya que otras partes de Core 1 todavía pueden depender de esa API. La migración se mantiene acotada al repositorio de ventas. + +Date: 2026-08-07 +model: GPT-5.6 Luna +Route: .roadmap/Core 1/changes/AgentsLogs/2026-08-07-GPT-5.6-Luna-core1-ci-fix.md +Description: Creé este registro para dejar trazabilidad de la corrección solicitada después del fallo de CI. La corrección se realizó sobre la rama `fix/core1-ci-stock-and-deprecations`, creada desde `master`, y está destinada a validación mediante Pull Request antes de cualquier integración en producción. diff --git a/app/src/main/java/com/elitec/alejotaller/feature/product/data/repository/ProductNetRepositoryImpl.kt b/app/src/main/java/com/elitec/alejotaller/feature/product/data/repository/ProductNetRepositoryImpl.kt index 9abcf67b..e747ef89 100644 --- a/app/src/main/java/com/elitec/alejotaller/feature/product/data/repository/ProductNetRepositoryImpl.kt +++ b/app/src/main/java/com/elitec/alejotaller/feature/product/data/repository/ProductNetRepositoryImpl.kt @@ -41,8 +41,8 @@ class ProductNetRepositoryImpl( collectionId = BuildConfig.PRODUCT_TABLE_ID, documentId = productId, attribute = "reserved", - value = quantity, - max = maxReserved + value = quantity.toDouble(), + max = maxReserved.toDouble() ) return response.toProductDto() } @@ -55,8 +55,8 @@ class ProductNetRepositoryImpl( collectionId = BuildConfig.PRODUCT_TABLE_ID, documentId = productId, attribute = "reserved", - value = quantity, - min = 0 + value = quantity.toDouble(), + min = 0.0 ) return response.toProductDto() } diff --git a/app/src/main/java/com/elitec/alejotaller/infraestructure/di/infrastructureDiModule.kt b/app/src/main/java/com/elitec/alejotaller/infraestructure/di/infrastructureDiModule.kt index 72f72f98..7b3bd9bd 100644 --- a/app/src/main/java/com/elitec/alejotaller/infraestructure/di/infrastructureDiModule.kt +++ b/app/src/main/java/com/elitec/alejotaller/infraestructure/di/infrastructureDiModule.kt @@ -22,6 +22,7 @@ import io.appwrite.Client import io.appwrite.services.Account import io.appwrite.services.Databases import io.appwrite.services.Storage +import io.appwrite.services.TablesDB import io.ktor.client.HttpClient import io.ktor.client.engine.android.Android import io.ktor.client.plugins.contentnegotiation.ContentNegotiation @@ -45,6 +46,7 @@ val infrastructureModule = module { .setSelfSigned(false) } single { Databases(get()) } + single { TablesDB(get()) } single { Account(get()) } single { Storage(get()) } single { @@ -61,7 +63,7 @@ val infrastructureModule = module { klass = AppBD::class.java, name = "app_database" ) - .addMigrations(*AppBDMigrations.ALL) // ✅ Migraciones registradas + .addMigrations(*AppBDMigrations.ALL) .build() } diff --git a/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/mapper/Document.toSaleDto.kt b/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/mapper/Document.toSaleDto.kt index 3b3cd246..f79aa8ea 100644 --- a/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/mapper/Document.toSaleDto.kt +++ b/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/mapper/Document.toSaleDto.kt @@ -3,7 +3,7 @@ package com.elitec.shared.data.feature.sale.data.mapper import com.elitec.shared.data.feature.sale.data.dto.SaleDto import com.elitec.shared.sale.feature.sale.domain.entity.Currency import com.elitec.shared.sale.feature.sale.domain.entity.SaleItem -import io.appwrite.models.Document +import io.appwrite.models.Row import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray @@ -12,7 +12,7 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.intOrNull -fun Document>.toSaleDto(): SaleDto = +fun Row>.toSaleDto(): SaleDto = SaleDto( id = id, date = data["date"].toLocalDate(), diff --git a/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/repository/SaleNetRepositoryImpl.kt b/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/repository/SaleNetRepositoryImpl.kt index 00231da1..74a888a7 100644 --- a/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/repository/SaleNetRepositoryImpl.kt +++ b/shared-data/src/main/java/com/elitec/shared/data/feature/sale/data/repository/SaleNetRepositoryImpl.kt @@ -6,30 +6,30 @@ import com.elitec.shared.data.feature.sale.data.mapper.toSaleDto import com.elitec.shared.data.infraestructure.core.data.config.SaleRemoteConfig import io.appwrite.ID import io.appwrite.Query -import io.appwrite.services.Databases +import io.appwrite.services.TablesDB import kotlinx.serialization.json.Json class SaleNetRepositoryImpl( - private val netDB: Databases, + private val netDB: TablesDB, private val config: SaleRemoteConfig ): SaleNetRepository { override suspend fun getAll(userId: String): List { Log.i(TAG, "event=sale_net_get_all_start userId=$userId collection=${config.saleCollectionId}") - val response = netDB.listDocuments( + val response = netDB.listRows( databaseId = config.databaseId, - collectionId = config.saleCollectionId, + tableId = config.saleCollectionId, queries = listOf(Query.equal("user_id", userId)) ) - Log.i(TAG, "event=sale_net_get_all_success userId=$userId count=${response.documents.size}") - return response.documents.map { document -> document.toSaleDto() } + Log.i(TAG, "event=sale_net_get_all_success userId=$userId count=${response.rows.size}") + return response.rows.map { row -> row.toSaleDto() } } override suspend fun getById(itemId: String): SaleDto { Log.i(TAG, "event=sale_net_get_by_id_start saleId=$itemId collection=${config.saleCollectionId}") - val response = netDB.getDocument( + val response = netDB.getRow( databaseId = config.databaseId, - collectionId = config.saleCollectionId, - documentId = itemId + tableId = config.saleCollectionId, + rowId = itemId ) Log.i(TAG, "event=sale_net_get_by_id_success saleId=$itemId") return response.toSaleDto() @@ -39,13 +39,13 @@ class SaleNetRepositoryImpl( val normalizedQuery = query.trim() if (normalizedQuery.isBlank()) return emptyList() - val response = netDB.listDocuments( + val response = netDB.listRows( databaseId = config.databaseId, - collectionId = config.saleCollectionId, + tableId = config.saleCollectionId, queries = listOf(Query.limit(limit)) ) - return response.documents + return response.rows .map { it.toSaleDto() } .filter { sale -> when (field.uppercase()) { @@ -61,10 +61,10 @@ class SaleNetRepositoryImpl( override suspend fun save(item: SaleDto) { val resolvedId = item.id.ifBlank { ID.unique() } Log.i(TAG, "event=sale_net_save_start saleId=$resolvedId userId=${item.userId} verified=${item.verified}") - netDB.createDocument( + netDB.createRow( databaseId = config.databaseId, - collectionId = config.saleCollectionId, - documentId = resolvedId, + tableId = config.saleCollectionId, + rowId = resolvedId, data = item.toAppwriteData() ) Log.i(TAG, "event=sale_net_save_success saleId=$resolvedId") @@ -73,10 +73,10 @@ class SaleNetRepositoryImpl( override suspend fun upsert(item: SaleDto) { if (item.id.isBlank()) return Log.i(TAG, "event=sale_net_upsert_start saleId=${item.id} userId=${item.userId} verified=${item.verified}") - netDB.updateDocument( + netDB.updateRow( databaseId = config.databaseId, - collectionId = config.saleCollectionId, - documentId = item.id, + tableId = config.saleCollectionId, + rowId = item.id, data = item.toAppwriteData() ) Log.i(TAG, "event=sale_net_upsert_updated saleId=${item.id}") diff --git a/web/src/core/feature/sale/data/repository/sale.net.repository.ts b/web/src/core/feature/sale/data/repository/sale.net.repository.ts index b2fc3886..d9166c69 100644 --- a/web/src/core/feature/sale/data/repository/sale.net.repository.ts +++ b/web/src/core/feature/sale/data/repository/sale.net.repository.ts @@ -1,9 +1,9 @@ import type { SaleDTO } from "../dto/SaleDTO"; -import { type Databases, ID, Query } from "appwrite"; +import { type TablesDB, ID, Query } from "appwrite"; import type { Models } from "appwrite"; import { ENV } from "../../../../infrastructure/env"; -const COLLECTION_ID = "sale"; +const TABLE_ID = "sale"; function stripMeta(data: Record): Record { const clean: Record = {}; @@ -16,7 +16,7 @@ function stripMeta(data: Record): Record { } export class SaleNetRepository { - constructor(private databases: Databases) {} + constructor(private tablesDB: TablesDB) {} private get databaseId(): string { const id = ENV.databaseId; @@ -25,60 +25,60 @@ export class SaleNetRepository { } async getAll(): Promise { - const response = await this.databases.listDocuments( - this.databaseId, - COLLECTION_ID - ) + const response = await this.tablesDB.listRows({ + databaseId: this.databaseId, + tableId: TABLE_ID, + }); - return response.documents + return response.rows as unknown as SaleDTO[]; } async create( - data: Omit | Record + data: Omit | Record ): Promise { const payload = stripMeta(data as Record); - return await this.databases.createDocument( - this.databaseId, - COLLECTION_ID, - ID.unique(), - payload - ) + return await this.tablesDB.createRow({ + databaseId: this.databaseId, + tableId: TABLE_ID, + rowId: ID.unique(), + data: payload, + }) as unknown as SaleDTO; } async getByUser(userId: string): Promise { - const response = await this.databases.listDocuments( - this.databaseId, - COLLECTION_ID, - [Query.equal("user_id", userId)] - ) + const response = await this.tablesDB.listRows({ + databaseId: this.databaseId, + tableId: TABLE_ID, + queries: [Query.equal("user_id", userId)], + }); - return response.documents + return response.rows as unknown as SaleDTO[]; } async updateVerified(id: string, verified: string): Promise { - return await this.databases.updateDocument( - this.databaseId, - COLLECTION_ID, - id, - { buy_state: verified } - ); + return await this.tablesDB.updateRow({ + databaseId: this.databaseId, + tableId: TABLE_ID, + rowId: id, + data: { buy_state: verified }, + }) as unknown as SaleDTO; } async updateDeliveryType(id: string, deliveryType: string): Promise { - return await this.databases.updateDocument( - this.databaseId, - COLLECTION_ID, - id, - { delivery_type: deliveryType } - ); + return await this.tablesDB.updateRow({ + databaseId: this.databaseId, + tableId: TABLE_ID, + rowId: id, + data: { delivery_type: deliveryType }, + }) as unknown as SaleDTO; } async updateStockHoldApplied(id: string, value: boolean): Promise { - return await this.databases.updateDocument( - this.databaseId, - COLLECTION_ID, - id, - { stock_hold_applied: value } - ); + return await this.tablesDB.updateRow({ + databaseId: this.databaseId, + tableId: TABLE_ID, + rowId: id, + data: { stock_hold_applied: value }, + }) as unknown as SaleDTO; } } diff --git a/web/src/core/feature/sale/di/sale.container.ts b/web/src/core/feature/sale/di/sale.container.ts index 39007108..1ff0006d 100644 --- a/web/src/core/feature/sale/di/sale.container.ts +++ b/web/src/core/feature/sale/di/sale.container.ts @@ -10,9 +10,9 @@ import { SessionSaleNotificationUserProvider } from "../data/repository/SessionS import { TelegramNotificatorImpl } from "../data/repository/TelegramNotificatorImpl"; import {productContainer} from "../../product/di/product.container"; -const netDatabases= infrastructureContainer.appwrite.databases +const netTablesDB = infrastructureContainer.appwrite.tablesDB -const saleNetRepository = new SaleNetRepository(netDatabases) +const saleNetRepository = new SaleNetRepository(netTablesDB) const saleOfflineFirstRepository = new SaleOfflineFirstRepository(saleNetRepository) const saleNotificationUserProvider = new SessionSaleNotificationUserProvider( () => infrastructureContainer.appwrite.account.get() diff --git a/web/src/core/infrastructure/di/appwrite.config.ts b/web/src/core/infrastructure/di/appwrite.config.ts index 8d7782a2..4e195faf 100644 --- a/web/src/core/infrastructure/di/appwrite.config.ts +++ b/web/src/core/infrastructure/di/appwrite.config.ts @@ -1,4 +1,4 @@ -import {Client, Databases, Storage, Account, Functions} from "appwrite" +import {Client, Databases, TablesDB, Storage, Account, Functions} from "appwrite" import {ENV} from "../env"; const client = new Client() @@ -14,6 +14,7 @@ if (ENV.appwriteEndpoint && ENV.appwriteProjectId) { } export const databases = new Databases(client) +export const tablesDB = new TablesDB(client) export const storage = new Storage(client) export const account = new Account(client) export const functions = new Functions(client) diff --git a/web/src/core/infrastructure/di/infrastructure.container.ts b/web/src/core/infrastructure/di/infrastructure.container.ts index f9ac9995..fbbcf27e 100644 --- a/web/src/core/infrastructure/di/infrastructure.container.ts +++ b/web/src/core/infrastructure/di/infrastructure.container.ts @@ -1,4 +1,4 @@ -import {account, client, databases, functions, storage} from "./appwrite.config"; +import {account, client, databases, functions, storage, tablesDB} from "./appwrite.config"; import {db} from "./dexie.db"; import {authService} from "./auth.service"; @@ -6,6 +6,7 @@ export const infrastructureContainer = { appwrite: { client, databases, + tablesDB, storage, account, functions,