Migración de iOS a paridad
apps/ios se construyó contra una versión anterior del backend y quedó desfasada. El paquete de operaciones compartidas declara hoy 746 operaciones GraphQL; apps/frontend-nextjs usa 649, apps/ios resuelve 75. Además, siete tipos de operación que el código de iOS todavía referencia ya no existen en el paquete, así que hoy la app no se puede regenerar limpiamente.
Esta página es el plan de trabajo para llevar iOS a paridad con web. Es una lista viva: marca las casillas conforme avance el trabajo — nada regenera esta página.
Decisión de alcance registrada: paridad total. Toda operación y feature que exista en apps/frontend-nextjs se planea para iOS, salvo lo listado en Fuera de alcance, que es web por construcción (superficie SEO, páginas de marketing, retornos de pago por redirección del navegador). Los flujos de compra sí entran, pero deben rediseñarse para StoreKit, no portarse.
Relacionado: App de iOS · GraphQL · Testing · Roadmap
Dónde está iOS hoy
Conteo de operaciones por dominio en packages/graphql/operations/Web. "web" = documentos importados por apps/frontend-nextjs; "iOS" = tipos generados que el código Swift referencia y que todavía resuelven.
| Dominio | Operaciones | web | iOS | Cobertura iOS |
|---|---|---|---|---|
| AppVersion | 1 | 0 | 0 | 0% |
| Auth | 51 | 45 | 6 | 11% |
| Calls | 27 | 5 | 23 | 85% |
| Coins | 41 | 40 | 4 | 9% |
| Contacts | 6 | 6 | 0 | 0% |
| Conversations | 44 | 15 | 24 | 54% |
| DeviceTokens | 2 | 0 | 2 | 100% |
| Family | 7 | 7 | 0 | 0% |
| Follow | 39 | 39 | 2 | 5% |
| Live | 34 | 34 | 0 | 0% |
| Messages | 89 | 65 | 6 | 6% |
| Misc | 26 | 25 | 0 | 0% |
| Notes | 4 | 4 | 0 | 0% |
| Notifications | 28 | 24 | 0 | 0% |
| Payments | 6 | 6 | 4 | 66% |
| Posts | 126 | 124 | 0 | 0% |
| Profile | 28 | 24 | 3 | 10% |
| Reports | 3 | 3 | 0 | 0% |
| Search | 42 | 41 | 1 | 2% |
| Settings | 48 | 48 | 0 | 0% |
| Shop | 16 | 16 | 0 | 0% |
| SocialLinks | 6 | 6 | 0 | 0% |
| Stories | 47 | 47 | 0 | 0% |
| Subscriptions | 25 | 25 | 0 | 0% |
| Total | 746 | 649 | 75 | 10% |
Dos cosas que la tabla esconde y que conviene saber antes de planear:
- iOS va adelante de web en llamadas en tiempo real. Calls (23/27) y Conversations (24/44) son los únicos dominios donde iOS lidera. 45 de las 75 operaciones que usa iOS no las usa web: CallKit/VoIP, solicitudes de speaker, conversaciones archivadas y bloqueadas, device tokens. Nada de eso se reescribe; se conserva y se cubre con tests.
- Algunas operaciones de iOS son variantes legacy que todavía compilan.
MeQuery,GetUserQuery,UpdateProfileMutation,LoginWithAppleMutation,LoginWithPhoneMutation,RequestPhoneOtpMutationySearchConversationsQuerysiguen existiendo en el paquete, pero web ya migró a documentos*Inlinemás nuevos (GetMe,GetPublicProfile,UpdateProfileInline,LoginWithAppleInline,LoginWithPhoneInline) con selection sets más ricos. iOS muestra menos datos que web desde el mismo backend.
Fase 0 — Desbloquear el build y el codegen
Nada más se puede verificar hasta que iOS compile contra código recién generado. Esta fase es prerrequisito de todas las demás.
Restaurar el enlace al paquete Swift
El módulo generado se renombró ClosegramAPI → ClosegramGraphQL (commit 2762f0fa), y packages/apollo-swift/Package.swift ahora expone el producto ClosegramGraphQL. 104 archivos Swift hacen import ClosegramGraphQL, pero apps/ios/app/app.xcodeproj/project.pbxproj sigue enlazando un producto llamado ClosegramAPI, que ya no existe — la cadena ClosegramGraphQL aparece cero veces en el archivo de proyecto.
- Reemplazar la dependencia de producto
ClosegramAPIporClosegramGraphQLen el targetappy commitearproject.pbxproj— hecho;project.pbxprojenlazaClosegramGraphQL(0 referencias restantes al producto anterior) - Confirmar que
xcodebuild -scheme app buildcompila desde derived data limpio — reconfirmado tras la reescritura de NavigationStack de la Fase 1 (ver abajo) - Actualizar las referencias obsoletas a
ClosegramAPIen la prosa:apps/ios/README.md(líneas 136, 681),apps/ios/app/app/Core/Services/Auth/README.md(línea 194),packages/apollo-swift/README.md— siguen obsoletas, aún no tocadas
Arreglar las siete referencias muertas
Estos tipos generados los referencia el código Swift pero el codegen no puede producirlos, porque ningún documento .graphql los declara. La resolución cambia por caso: tres necesitan documento nuevo, tres adoptar el renombrado, uno rediseño.
| iOS referencia | Estado en backend | Resolución |
|---|---|---|
ChangePasswordMutation | El campo changePassword existe | Adoptar ChangePasswordInline (Auth/ChangePasswordInline.graphql) → ChangePasswordInlineMutation |
ResetPasswordMutation | El campo resetPassword existe | Adoptar ResetPasswordInline (Auth/ResetPasswordInline.graphql) → ResetPasswordInlineMutation |
LoginWithFirebaseMutation | Campo eliminado del schema | Migrar a loginWithIdToken (Auth/LoginWithIdToken.graphql) — es la ruta de Google/Firebase que usa web |
DeleteAccountMutation | El campo deleteAccount(password: String!) existe, sin documento compartido | Agregar un documento en Auth/ o adoptar el flujo nuevo que usa web: RequestAccountDeletionInline + CancelAccountDeletionInline + DeleteAccountImmediatelyInline (Settings) |
MyPurchaseHistoryQuery | El campo myPurchaseHistory existe | Resuelto — en vez de cambiar a MyCoinPurchases/MyRecentTransactions, se agregó un documento MyPurchaseHistory($limit, $offset) a Coins/MyCoinPurchases.graphql y se regeneró el codegen; iOS lo resuelve directamente |
SearchMyMessagesQuery | El campo searchMyMessages existe, sin documento compartido | Adoptar SearchMessagesInline (Messages/SearchMessagesInline.graphql), que es lo que usa web |
RefreshTokenMutation | No existe tal mutation — refreshToken es solo un campo String en la respuesta de auth | Rediseñar el refresco de sesión: persistir el refreshToken que devuelve el login y reautenticar, o volver a emitir un ID token de Firebase y llamar a loginWithIdToken |
- Decidir, por fila, si se agrega documento compartido o se adopta el existente
- Agregar los documentos faltantes a
packages/graphql/operations/Web/**(según elCLAUDE.mdraíz, las operaciones solo-móvil también viven bajoWeb/, compartidas conapollo-webyapollo-swift) - Reescribir los siete call sites en Swift
- Ejecutar
npm run codegen:iosy commitearpackages/apollo-swift/Sources/ClosegramGraphQL/Sourcesregenerado
Hacer imposible reintroducir el desfase
- Agregar un job de CI de iOS (runner macOS) que ejecute el codegen y falle si las fuentes generadas quedan sucias — implementado como
.github/workflows/ios-ci.ymldedicado (no fusionado enci.yml, que solo cubre backend/frontend), movido ahí después de encontrarse en la ruta con typo.githubtest/workflows/ios-ci.ymly nunca haberse ejecutado realmente en GitHub Actions. También se corrigieronXCODE_VERSION: '16.1'/ runnersmacos-15obsoletos, ninguno compatible con elIPHONEOS_DEPLOYMENT_TARGET = 26.1de este proyecto - Que ese mismo job compile el scheme
appy ejecuteappTests(ver Requisitos de testing) - Documentar el ritual en App de iOS: pull →
npm run codegen:schema→npm run codegen:ios→ build
Adoptar las variantes vigentes de cada documento
Documentos legacy que aún compilan pero ya no coinciden con lo que renderiza web. Bajo riesgo; conviene hacerlo con el codegen recién corrido.
-
MeQuery→GetMe/GetMeProfileInline -
GetUserQuery→GetPublicProfile -
UpdateProfileMutation→UpdateProfileInline -
LoginWithAppleMutation→LoginWithAppleInline -
LoginWithPhoneMutation→LoginWithPhoneInline -
RequestPhoneOtpMutation— confirmar la variante vigente y alinear - Comparar cada selection set nuevo contra el mapeo de modelos de iOS y ampliar los modelos de dominio donde se agregaron campos
Fase 1 — Ajustes de arquitectura
Arreglos estructurales que abaratan las fases de features. Hacerlos antes del trabajo de volumen, no después: cada uno se encarece por cada feature agregada.
Violaciones de capas
- Sacar las llamadas directas a Apollo de las vistas SwiftUI:
ChatsListView.swift(líneas 870, 959),ParticipantActionsSheet.swift(líneas 207, 226),ContactInfoView.swift— enrutarlas por el repositorio de Chat - Agregar
Features/Calls/Data/Repositories/CallRepositoryy queCallStore(y sus cinco extensiones) deje de llamar aGraphQLService/ChatAPIServicedirectamente — hoy son 22 llamadas directas a servicios - Fijar la regla en revisión de código:
View → ViewModel → Store → Repository → Service, sin atajos
Inyección de dependencias
- Registrar los cuatro repositorios sin registrar en
DIContainer+Registration.swift:SearchRepository,PaymentRepository,CoinPackageRepository(hoy se instancian por argumento por defecto delinit) — más los que agreguen las fases siguientes - Agregarlos todos a
validateRequiredDependencies(), que hoy valida 3 de 7 y por lo tanto da falsa confianza - Se arregló un problema de DI relacionado pero distinto:
SearchView,CreateDirectChatViewyCreateGroupChatView(además, antes de borrarse arriba, elshowCreateChat()deNestedNavigationView) hacíanlet searchStore = SearchStore()detrás de un comentario "Temporary: Create local stores until we can use @EnvironmentObject in init", evitando el singleton registrado en DI y creando instancias nuevas desechables. Los cuatro ahora resuelvenDIContainer.shared.resolve(SearchStore.self). Es un arreglo a nivel de Store, no el hueco a nivel de Repository que siguen rastreando las dos líneas de arriba
Costuras de testing
- Sacar
MockAuthRepositoryyMockChatRepositorydel target de la app (o envolverlos en#if DEBUG) — hoy se compilan dentro del binario de producción - Eliminar el duplicado:
MockAuthRepositoryexiste dos veces, enFeatures/Auth/Data/Repositories/(2.5 KB) y enappTests/Tests/AuthTests/Data/(7.4 KB), con comportamiento divergente — sigue pendiente, ambos siguen existiendo - Agregar
<Testables>deappTestsalapp.xcschemecompartido — hecho.TestActionteníashouldAutocreateTestPlan = "YES"pero sin bloque<Testables>, así quexcodebuild test/fastlane testfallaban directamente con "Scheme app is not currently configured for the test action" en vez de ejecutar cero tests silenciosamente. Arreglarlo sacó a la luz 9 fallos antes invisibles enAuthTests(huecos reales en la validación deLoginUseCase/RegisterUseCase, más 3 tests que afirmaban el nivel incorrecto de fortaleza de contraseña), todos arreglados de verdad
Estructura
- Reemplazar el puente a UIKit
NestedNavigationView/CustomTabBarController(unUIViewControllerRepresentableque envolvíaUINavigationController/UITabBarController, reconstruyendo manualmente unUIHostingControllercon una lista de.environmentObject()elegida a mano por cada ruta empujada) por unMainTabViewpuro en SwiftUI: unNavigationStack(path: $router.path)externo alrededor de unTabView, cada una de las 5 pestañas con su propioNavigationStackinterno,.navigationDestination(for: AppRoute.self)para las 4 rutas entre pestañas. Ambos archivos anteriores fueron borrados. Esto era la causa raíz de la fragilidad de asignación de environment-objects que esta sección advertía — un árbol SwiftUI puro propaga el entorno automáticamente, así que ya no existe una lista manual de reasignación que mantener sincronizada - Consolidar las (ahora cinco,
Helpers/CustomSheetModifier.swiftse borró en esta pasada por estar completamente sin uso — cero referencias, y su propio diseño no adjuntaba ningún environment object) implementaciones de sheets en un solo lugar (Helpers/SheetPreferenceKey.swift,Utilities/SheetPresentationState.swift,Stores/SheetCoordinator.swift,Shared/Components/BottomSheet.swift,Chat/.../CustomBottomSheet.swift) - Eliminar las carpetas raíz
Helpers/,Utilities/yStores/— ninguna forma parte de la arquitectura declarada - Decidir el destino de
Domain/UseCases: solo existe enAuth. O se adopta en todos los features o se quita de la descripción de arquitectura - Trocear los god objects antes de agregarles código:
ChatStore.swift(1411 líneas),ChatsListView.swift(1010),LiveKitManager.swift(965),CallStore.swift(873 + 5 extensiones). El patrón a copiar esCallStore+* - Borrar o reescribir
apps/ios/app/Package.swift— declara un targetClosegrammAppcuyo directorioSources/no existe y lista solo dos de las seis dependencias reales - Rotar la clave de Giphy commiteada como fallback de DEBUG en
Config/Secrets.swifty mover ambos fallbacks a xcconfig/.env - Corregir
apps/ios/README.md, que documenta unCacheCoordinator, unApolloClientManager, unGoogleAuthManager,Core/Models/User.swift,Views/Messages/y unTESTING_GUIDE.mdque no existen
Scaffolding de features nuevos
Hacen falta nueve módulos nuevos. Crear cada uno como Features/<Nombre>/{Data/Repositories,Domain/Models,Presentation/{Store,ViewModels,Views}} con su repositorio registrado, según App de iOS.
-
Posts· [ ]Stories· [ ]Live· [ ]Notifications· [ ]Settings(promover desde solo-vistas) · [ ]Shop· [ ]Subscriptions· [ ]Social(Follow + Contacts + Family) · [ ]Monetization(Coins + Payments + Payouts)
Fase 2 — Auth, cuenta y seguridad
Faltan 45 operaciones de Auth. Esta fase desbloquea cambio de cuenta, 2FA y passkeys — todo ya soportado por el backend y ya en producción en web.
- Flujos de contraseña sobre los documentos vigentes:
ChangePasswordInline,ResetPasswordInline,ChangeForcedPasswordInline,RequestPasswordReset,VerifyResetTokenInline - Inicio de sesión con Google vía
LoginWithIdToken(reemplaza al eliminadologinWithFirebase) - Apple sign-in vía
LoginWithAppleInline; OTP por teléfono víaLoginWithPhoneInline+RequestPhoneOtp - Passkeys / WebAuthn con
ASAuthorizationPlatformPublicKeyCredentialProvider:GeneratePasskeyRegOptionsInline,VerifyPasskeyRegInline,GeneratePasskeyAuthOptionsInline,VerifyPasskeyAuthInline,MyPasskeysInline,DeletePasskeyInline— con Face ID/Touch ID la experiencia queda mejor en iOS que en web - Doble factor:
SetupTwoFactorInline,VerifyTwoFactorSetupInline,EnableTwoFactorInline,DisableTwoFactorInline,TwoFactorStatusInline,RegenerateBackupCodesInline,VerifyLoginTwoFactorInline - Multi-cuenta:
AddAccountLogin,AddAccountGoogle,AddAccountApple,AddAccountPhone,AddAccountVerify2FA,AddAccountVerifyPasskey— requiere almacenamiento multi-token en Keychain, que hoy asume una sola sesión - Onboarding:
CompleteOnboarding,OnboardingInterestSuggestions,OnboardingSearchUsers,OnboardingFollow,OnboardingUnfollow,OnboardingFollowRequirement - Sesiones y seguridad:
ActiveSessionsInline,RevokeSessionInline,RevokeAllOtherSessionsInline,LoginHistoryInline,SecurityEventLogInline,SecurityScoreTwoFactorInline,SecurityScoreEmailInline,GetSecurityAlertsInline,MarkSecurityAlertReadInline,DismissSecurityAlertInline - Rediseño del refresco de sesión (viene de la Fase 0) implementado y cubierto por tests
-
Logoutconectado a limpiar Keychain, caché de Apollo y device tokens - Strings i18n en
en.lprojyes.lproj; tests según Requisitos de testing
Fase 3 — Perfil, grafo social y descubrimiento
Faltan 25 de Profile, 37 de Follow, 41 de Search, 6 de SocialLinks, 6 de Contacts.
- Perfil público sobre
GetPublicProfile+GetRelationshipStatusForProfile+RecordProfileVisitFromProfile - Perfil propio y edición:
GetMeProfileInline,UpdateProfileInline,ValidateUsernameInline,GetAboutAccount,GetMyInterests,UpdateInterests - Presencia:
UpdateLastSeen,SetUserOffline - Verificación y correo:
RequestVerificationInline,VerificationStatusInline,SubmitIdentityVerificationInline,MyIdentityVerificationStatusInline,GetEmailStatusInline,ResendEmailVerificationInline,VerifyEmailInline - Grafo de follow: modales de seguidores/seguidos,
RemoveFollowerModal, close friends, favoritos, bloqueados, silenciados, restringidos (AddToCloseFriendsInline,GetFavoriteUsersInline,GetBlockedUsersInline,GetMutedUsersInline,RestrictedAccountsInliney las variantes*FromProfile) - Acciones masivas:
BulkUnfollowUsersAction,BulkBlockUsersAction,BulkRemoveFollowersAction,BulkGetUserFollowers,BulkGetUserFollowing - Búsqueda y descubrimiento:
SearchUsersExplore,SearchHashtagsInline,DiscoverPosts,DiscoverTrending,DiscoverRecommended,DiscoverSimilar,DiscoverNearby,DiscoverMayKnow,GetSuggestedUsers,MentionSuggestionsInline, historial de búsquedas recientes - Enlaces sociales:
MySocialLinks,AddSocialLink,UpdateSocialLink,DeleteSocialLink,ReorderSocialLinks,UserSocialLinks - Importación de contactos con el framework nativo
Contactsy su permiso (las 6 operaciones de Contacts) - Share sheet nativo y QR de perfil
- i18n + tests
Fase 4 — Ponerse al día en mensajería
Faltan 83 operaciones de Messages y 20 de Conversations. iOS ya tiene el transporte y la capa de tiempo real; esto es superficie de features sobre plomería que ya funciona.
- Reacciones, destacados y anclados:
AddReaction,GetMessageReactions,GetPinnedMessages - Hilos y respuestas:
GetMessageThread,GetMessageReplies,GetMessage - Semántica de borrado:
DeleteMessageForMevsDeleteMessageForEveryone(iOS solo tiene el legacyDeleteMessage) - Búsqueda dentro de la conversación:
SearchMessagesInline(reemplaza al muertoSearchMyMessagesQuery) - Navegador de multimedia:
GetMessagesByMediaType - Encuestas:
CreatePoll,GetPollResults - Mensajes programados y con expiración:
CancelScheduledMessage,EditScheduledMessage - Traducción de mensajes, por mensaje y global (
MyTranslationSetting) - Gestión de grupos:
GetConversationParticipants,UpdateConversation,UpdateConversationSettings,TransferAdmin,LeaveConversation,DeleteConversation,ConversationInviteLinkInfo, unirse por enlace - Solicitudes de mensaje y privacidad:
ConversationPrivacyInfo, aceptar/rechazar - Contadores de no leídos:
GetConversationUnreadCount,GetTotalUnreadCount,NavTotalUnread— necesarios para un badge correcto - Reportes:
ReportConversation - Notas:
MyNote,CreateNote,DeleteNote,NotesFromFollowing(las 4 operaciones de Notes) - Mensajes y grupos de pago — la parte de compra se difiere a la Fase 10; primero el lado de lectura y permisos (
HasConversationAccess,GetMyMessagePurchases) - i18n + tests
Fase 5 — Posts y feed
126 operaciones, el hueco más grande y el núcleo del producto. Web usa 124; iOS ninguna.
- Feed principal:
GetFeed,GetInteractionCounts, registro de vistas - Detalle y tarjeta de post:
GetPost,HasUserLikedPostInline,IsPostSavedInline,HasUserRepostedInline - Crear post: subida de media, caption, menciones/hashtags, visibilidad, colaboradores, programación (
CreatePost,GetScheduledPostForEdit) - Comentarios:
CreateComment,GetPostComments, likes y ajustes de comentarios - Reposts, guardados y colecciones
- Modales de likes y visitantes:
GetPostInteractionsForLikesModal,GetMyProfileViewers - Opciones de post: editar (
GetPostForEdit), archivar (ArchiveOwnPost), borrar (DeleteOwnPost), fijar, reportar (CreatePostReport) - Insights y promociones:
CreatePostPromotionFromComposer, estadísticas de promoción - Páginas de hashtag:
PostsByHashtag,HashtagStatsHashtagPage - Archivo y eliminados recientemente, con restauración
- Desbloqueo de posts de pago — lectura ahora, compra en la Fase 10
- Marca de agua dinámica sobre media de pago, igual que la superposición anti-captura de web
- i18n + tests
Fase 6 — Stories, clips y destacados
47 operaciones, ninguna en iOS.
- Barra de stories, visor, reacciones, respuestas, conteo de vistas
- Crear story: media y texto con selector de fondo
- Destacados:
GetUserHighlights,GetMyStoriesForHighlight, crear/editar/borrar/reordenar - Compartir story a DM
- Feed de clips y creación de clips (like, guardar, repost, estadísticas)
- Historial de búsqueda que vive en este dominio (
SearchHistoryExplore,ClearSearchHistoryExplore,DeleteSearchHistoryItemExplore) - i18n + tests
Fase 7 — Live
34 operaciones, ninguna en iOS — pero iOS ya tiene LiveKit conectado para llamadas, que es la mayor parte de lo difícil.
- Descubrimiento de lives: en vivo ahora, trending, programados, archivo
- Sala de live: video, comentarios, reacciones, comentarios fijados, regalos
- Salir en vivo: crear/iniciar/actualizar/terminar, tokens de invitado, guardar grabación
- Control de speakers — reutilizar la maquinaria de solicitudes que ya existe en
CallStore - Subscriptions en tiempo real:
LiveCommentAddedSub,LiveReactionsSub,LiveStreamUpdatedSub,LiveStreamsChangedSub - i18n + tests
Fase 8 — Notificaciones
28 operaciones, ninguna en iOS. El registro de device tokens ya funciona (DeviceTokens está al 100%), así que esto es la superficie in-app, no el transporte.
- Lista de notificaciones y lista enriquecida:
MyNotifications,MyNotificationsRich - Leídas y borrado:
MarkNotificationAsRead,MarkAllNotificationsAsRead,DeleteNotification,DeleteAllNotifications - Badge y conteo:
UnreadNotificationsCount+NavTotalUnread - Tiempo real: subscription
NotificationAdded - Solicitudes de follow:
PendingFollowRequests,AcceptFollowRequest,RejectFollowRequest,SendFollowRequestFromProfile,CancelFollowRequestFromProfile,GetSentFollowRequestsForProfile - Ajustes:
GetNotificationSettingsInline,UpdateNotificationSettingsInline, ajustes extendidos, vistas previas de mensajes,GetSleepModeSettingsInline/UpdateSleepModeSettingsInline - Mapear cada tipo de payload APNs a un deep link in-app a través de
AppRouter - i18n + tests
Fase 9 — Ajustes, privacidad y seguridad
48 operaciones de Settings más 26 de Misc, ninguna en iOS. Web tiene unas 85 pantallas de ajustes; el feature Settings de iOS son hoy tres vistas sin store.
- Promover
Settingsa módulo completo (Data/Domain/Presentation) - Privacidad:
GetPrivacySettingsInline,UpdatePrivacySettingsInline, privacidad extendida,ResetPrivacySettingsInline, revisión de privacidad - Palabras ocultas, protección de desnudos, confirmaciones de lectura, etiquetas y menciones, ajustes de compartir
- Ciclo de vida de la cuenta:
DeactivateAccountInline,ReactivateAccountInline,RequestAccountDeletionInline,CancelAccountDeletionInline,DeleteAccountImmediatelyInline,AccountStatusInline,GetAccountStandingStatusInline - Exportación de datos: solicitar, estado, descargar, borrar, más la subscription
DataExportStatusChangedInline - Gestión del tiempo y uso:
GetTimeManagementDataInline,RecordUsageHeartbeatInline,TakeBreakInline,EndBreakInline,GetActivityHeatmapInline - Límites de interacción:
MyInteractionLimitInline,SetInteractionLimitInline - Preferencias de contenido:
RemoveContentPreferenceInline,GetNotInterestedContentInline,UpdateMediaPreferencesInline - Compartir ubicación:
GetMyLocationSharing,UpdateMyLocationSharing,DeleteMyLocationSharing - Ajustes de traducción:
MyTranslationSetting,GetReelsTranslationSettingsInline - Family Center (las 7 operaciones de Family): vínculo padre-hijo, límites de tiempo, estadísticas de uso
- Moderadores (dominio Reports):
MyModerators,AddModerator,RemoveModerator,UpdateModeratorPermissions,ModeratorActivity - Control de versión al inicio:
CheckAppVersion— el contrato de backend se construyó justo para esto, ver Control de versiones de la app - i18n + tests
Fase 10 — Monetización
Faltan 37 de Coins, 25 de Subscriptions, 16 de Shop, 2 de Payments, más las operaciones de propinas, top fans y referidos en Misc. Esta fase no es un port. Web vende monedas con Stripe y PayPal; en iOS los bienes digitales tienen que pasar por StoreKit o la app se rechaza.
- Decidir y dejar por escrito la frontera de StoreKit antes de construir: qué compras son IAP (monedas, regalos, propinas, posts de pago, mensajes de pago, suscripciones de creador) y cuáles siguen con tarjeta/PayPal (producto físico de la tienda, payouts)
- StoreKit 2 y flujo de compra con validación de recibo en servidor — esto necesita contrato nuevo de backend; las operaciones existentes
CreateCoinPurchaseIntent/CapturePaypalCoinOrderno aplican - Saldo y billetera:
MyCoinBalance(ya en iOS),MyRecentTransactions,MyCoinPurchases - Regalos: catálogo (
GiftCatalogInline,LiveGiftCatalogInline), enviar a usuario/post/live - Propinas y top fans:
SendTipFromChat,MyReceivedTipsInline,MyTipStatsInline,TopFansInline,TopTippersInline,RewardTopFanReward - Suscripciones de creador: tiers, ofertas (
OfferByToken,OffersMyTiers,CreateSubscriptionOffer), suscribir/cancelar/renovar, pruebas (RedeemSubscriptionTrial) - Conversaciones de pago:
SubscribeToConversation,GrantFreeConversationAccess,GetConversationSubscriptionStats,GetMySubscriptionEarnings - Tienda: gestión de productos,
GetSellerProductsForProfile,PurchaseProductFromProfile, reseñas, pedidos y disputas - Payouts y ganancias: perfil de payout,
StartPayoutOnboardingInline, solicitudes de cashout,MySalesInline, ganancias por anuncios, estados de cuenta - Referidos:
MyReferralInfoInline - Métodos de pago: conservar las cuatro operaciones existentes; agregar
CreatePaypalVaultSetupToken/ConfirmPaypalVaultSetupTokensolo si PayPal sobrevive a la decisión de frontera de StoreKit - i18n + tests
Fase 11 — Pulido de llamadas
Solo faltan 4 operaciones; aquí iOS va adelante de web. Fase pequeña, se puede hacer cuando convenga.
-
ActiveCall,GetCall,MySpeakerRequests,CallStatusChanged - Escribir tests para las 23 operaciones de Calls que hoy no tienen ninguno
Requisitos de testing
La regla del CLAUDE.md raíz — un feature no está terminado sin tests, en ambos idiomas — también aplica a iOS. Hoy apps/ios solo tiene tests de Auth (8 archivos), y puede que ni se ejecuten.
Por fase, antes de marcar la última casilla:
- Tests de reducer para cada
*Reducernuevo (funciones puras, la cobertura más barata del proyecto) - Tests de store con repositorio mock para las rutas async y de efectos secundarios
- Tests de ViewModel para validación y ramas de error
- Tests de repositorio contra un
GraphQLServicemockeado, verificando el mapeo de la respuesta - Strings presentes en
en.lprojyes.lproj— una pantalla que solo se lee bien en inglés no está terminada -
npm run codegen:ioslimpio yxcodebuild test -scheme appen verde
Infraestructura, una sola vez:
-
<Testables>agregado aapp.xcscheme(Fase 1) - Job de CI en macOS que compile, ejecute tests y verifique desfase de codegen (Fase 0)
- Que el target de tests refleje la estructura de features:
appTests/Tests/<Feature>Tests/{Data,Domain,Presentation}— hoy solo existeAuthTests
Definición de terminado, por feature
Un feature pasa de - [ ] a - [x] solo cuando se cumple todo esto:
- Las operaciones vienen de
packages/graphql/operations/Web/**y el codegen está commiteado - La ruta de datos es
View → ViewModel → Store → Repository → Service, con el repositorio registrado enDIContainery validado - Los strings existen en
en.lprojyes.lproj - Los tests de reducer, store y repositorio pasan en CI
- El comportamiento offline es deliberado — cacheado, encolado o explícitamente no disponible
- La página correspondiente en
docs/features/tiene marcada su casilla de iOS
Fuera de alcance
Web por construcción; no se planea equivalente en iOS.
| Feature de web | Motivo |
|---|---|
Páginas estáticas de marketing y legales (/about, /blog, /press, /terms, …) | Se sirven en webview o no se sirven |
sitemap.ts, robots.ts, metadata SSR, la capa components/public/* y cada variante Public*Page | Superficie SEO; iOS siempre usa las variantes autenticadas |
Link-in-bio (/l/[username]) | Es una landing web por definición |
EarnLandingPage (/coins público) | Página de marketing |
FloatingChat | Patrón de superposición de escritorio |
Web push (lib/webPush, RegisterWebPushTokenInline) | Lo reemplaza APNs vía el dominio DeviceTokens, ya al 100% en iOS |
/payments/return | Manejador de redirección del navegador; StoreKit no tiene equivalente |
settings/app-website-permissions | Modelo de permisos del navegador |
| Etiqueta de Google Analytics | Firebase Analytics ya está conectado en iOS |
Necesitan rediseño en vez de port: todos los flujos de compra con dinero fiat (StoreKit, Fase 10), el OAuth de crossposting (ASWebAuthenticationSession) y los permisos de dispositivo (deep links a ajustes nativos).
Seguimiento de avance
Una casilla por dominio. Marcar cuando las operaciones del dominio estén conectadas, localizadas y con tests.
- AppVersion (1 operación)
- Auth (faltan 45)
- Calls (faltan 4)
- Coins (faltan 37)
- Contacts (6)
- Conversations (faltan 20)
- DeviceTokens (completo)
- Family (7)
- Follow (faltan 37)
- Live (34)
- Messages (faltan 83)
- Misc (26)
- Notes (4)
- Notifications (28)
- Payments (faltan 2)
- Posts (126)
- Profile (faltan 25)
- Reports (3)
- Search (faltan 41)
- Settings (48)
- Shop (16)
- SocialLinks (6)
- Stories (47)
- Subscriptions (25)