OpportunitiesEntities
Docs
    Ring Platform

    Futuro descentralizado que se construye a sí mismo

    Iniciar sesión
    Entities
    Opportunities
    Store
    Docs
    Conceptos de la plataforma
    RING EconomíaSonoratek LLCImpacto globalIA encuentra Web3
    Empezar
    Inicio rápidoCalculadoraHoja de ruta
    Privacidad|Contacto
    v1.106.26|Sonoratek LLC

    Documentation

    Conceptos, valor y escenarios típicos de clon — menos código.

    Primeros pasos
    Requisitos previos
    Instalación
    Validación del primer éxito
    Próximos pasos
    Funcionalidades
    Tienda multivendedor
    Membership
    Cortina de página
    Entidades
    Oportunidades
    Mensajería en tiempo real
    Módulo de noticias
    Blogs de miembros
    Notificaciones
    Personalización
    Ringization playbook
    Despliegue
    Despliegue autoalojado
    Arquitectura
    Arquitectura de News Kingdom
    Desarrollo
    OSS frente a enterprise

    Entrada rápida (CTOs · auditores · agentes)

    Bienvenida — misión y audiencias
    Referencia rápida
    Primeros pasos
    Arquitectura y Auth.js
    Modos de backend y bases de datos (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Lecturas de seguridad y cumplimiento
    ringdom.org — base LegioX
    Código fuente — licencia MIT (GitHub)

    Documentation

    Conceptos, valor y escenarios típicos de clon — menos código.

    Primeros pasos
    Requisitos previos
    Instalación
    Validación del primer éxito
    Próximos pasos
    Funcionalidades
    Tienda multivendedor
    Membership
    Cortina de página
    Entidades
    Oportunidades
    Mensajería en tiempo real
    Módulo de noticias
    Blogs de miembros
    Notificaciones
    Personalización
    Ringization playbook
    Despliegue
    Despliegue autoalojado
    Arquitectura
    Arquitectura de News Kingdom
    Desarrollo
    OSS frente a enterprise

    Entrada rápida (CTOs · auditores · agentes)

    Bienvenida — misión y audiencias
    Referencia rápida
    Primeros pasos
    Arquitectura y Auth.js
    Modos de backend y bases de datos (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Lecturas de seguridad y cumplimiento
    ringdom.org — base LegioX
    Código fuente — licencia MIT (GitHub)

    Documentation

    Conceptos, valor y escenarios típicos de clon — menos código.

    Primeros pasos
    Requisitos previos
    Instalación
    Validación del primer éxito
    Próximos pasos
    Funcionalidades
    Tienda multivendedor
    Membership
    Cortina de página
    Entidades
    Oportunidades
    Mensajería en tiempo real
    Módulo de noticias
    Blogs de miembros
    Notificaciones
    Personalización
    Ringization playbook
    Despliegue
    Despliegue autoalojado
    Arquitectura
    Arquitectura de News Kingdom
    Desarrollo
    OSS frente a enterprise

    Entrada rápida (CTOs · auditores · agentes)

    Bienvenida — misión y audiencias
    Referencia rápida
    Primeros pasos
    Arquitectura y Auth.js
    Modos de backend y bases de datos (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Lecturas de seguridad y cumplimiento
    ringdom.org — base LegioX
    Código fuente — licencia MIT (GitHub)
    Ring Logo

    Loading documentation...

    Preparing Ring content

    Ring Logo

    Loading documentation...

    Preparing Ring content

    Ring Logo

    Loading documentation...

    Preparing Ring content

    API de oportunidades

    REST para el marketplace de doble naturaleza. La lista de navegación está abierta a los visitantes; todo lo demás requiere sesión. La lista de navegación (GET /api/opportunities) es una paginación por cursor consciente del rol más enriquecimiento por espectador. La búsqueda es una ruta aparte. Like / Save / Hide / Contact son Server Actions, no recursos HTTP.

    Usa las pestañas Founder / Developer para filtrar esta página. Ciclo de producto y UX de las tarjetas: Oportunidades.

    No son siete tipos

    Textos antiguos de la API enumeraban unos "7 tipos" fijos. Los tipos en tiempo de ejecución son la unión OpportunityType en features/opportunities/types/index.ts, limitada por ring-config.json → opportunities.enabledTypes. No documentes un conjunto cerrado de siete.

    Superficies (compartido)

    MétodoRutaAutenticaciónNotas
    GET/api/opportunitiesOpcionallimit, startAfter. Los parámetros de filtro types/type, q/query, categories/category, location, priority cambian al servicio de búsqueda. Pasa viewerUserId cuando hay sesión. Devuelve { opportunities, items, lastVisible, cursor, hasMore }
    POST/api/opportunitiesSesiónCuerpo createOpportunityBodySchema → { opportunity } 201
    GET/api/opportunities/{id}SesiónUn anuncio
    PUT / PATCH/api/opportunities/{id}SesiónActualizar
    DELETE/api/opportunities/{id}SesiónEliminar
    GET/api/opportunities/searchSesiónRequiere q. Opcionales types, categories, location, limit
    POST/api/opportunities/searchSesiónCuerpo JSON SearchOpportunitiesParams
    POST/api/opportunities/{id}/signSesiónFirma consultiva de una petición, una por usuario. Devuelve signatureCount, signatureTarget
    GET/api/opportunities/mySesiónLista del propietario; view= all | drafts | pending | active | archived
    POST/api/opportunities/uploadSesiónAdjuntos
    GET / POST/api/mcp/v1/opportunitiesMCP guardLa lista hoy no pasa viewerUserId

    Desde 2026-10-17, GET /api/opportunities sin autenticar devuelve filas públicas no confidenciales para el rol visitor. El filtro de visitante se aplica después de obtener la página, así que una página de invitado puede tener menos de limit filas. Detalle, búsqueda y cambios siguen devolviendo 401 sin sesión.

    Lo que deben saber los operadores

    • Navegar frente a buscar. La página /opportunities carga GET /api/opportunities (una página de anuncios). Los filtros del panel derecho se envían como parámetros de consulta y se aplican en el servidor. Los visitantes pueden navegar sin cuenta.
    • Anuncios ocultos. Cuando un miembro toca Hide, la siguiente navegación o búsqueda de esa cuenta omite el id. Los demás miembros lo siguen viendo.
    • Nombres en las tarjetas. Las respuestas de lista y búsqueda adjuntan una instantánea creator segura para el público, así que la UI nunca muestra un UUID en bruto.
    • Crear en el producto. El formulario para añadir oportunidades sigue prefiriendo el Server Action createOpportunity (app/_actions/opportunities.ts). El POST REST es para clientes de API y MCP; ambos llaman al mismo servicio.

    Ciclo de la funcionalidad

    Matcher, tipos habilitados, acciones de las tarjetas del feed, My Opportunities.

    Sincronización del descubrimiento

    Etiquetas de caché, revalidatePath, Tunnel opportunity:* tras crear, actualizar o eliminar.

    Enriquecimiento de la lista

    GET /api/opportunities (app/api/opportunities/route.ts):

    1. auth(). Sin sesión el rol es visitor, sin enriquecimiento de espectador.
    2. Con parámetros de filtro: searchOpportunities. Si no, getOpportunitiesForRole({ userRole, limit, startAfter, viewerUserId }).
    3. Si viewerUserId está definido: getViewerHiddenOpportunityIds y luego el filtro de DatabaseService { field: 'id', operator: 'not-in', value: hiddenIds }.
    4. attachOpportunityFeedFields añade creator, viewer, likes.

    searchOpportunities lee internamente session.user.id (o el id del actor MCP); los llamantes no pasan viewerUserId. La exclusión de ocultos y el adjunto se ejecutan cuando ese id existe.

    MCP GET /api/mcp/v1/opportunities llama a getOpportunitiesForRole sin viewerUserId (sin filtro de ocultos, sin creator/viewer en esa lista).

    Extras de SerializedOpportunity (lista/búsqueda)

    Archivo de tipos canónico: features/opportunities/types/index.ts. Las fechas son cadenas ISO. Las formas Timestamp de Firestore solo existen para DB_BACKEND_MODE=firebase-full.

    Cuerpo de creación (obligatorio)

    createOpportunityBodySchema (features/opportunities/lib/create-opportunity-schema.ts): title, briefDescription, organizationId, category, location, visibility, contactInfo.linkedEntity, contactInfo.contactAccount.

    POST devuelve 201 { opportunity }. Después, la creación llama a syncOpportunityDiscovery con un fragmento que incluye de la sesión (tarjetas insertadas en vivo).

    Control de acceso

    • Visibilidad en el documento: public | subscriber | member | confidential | entity. Las filas entity solo las pueden leer administradores, el autor y los miembros de la entidad vinculada. Las consultas de lista aplican filtros de visibilidad según el rol (buildOpportunityVisibilityFilters).
    • Los anuncios confidenciales requieren roles con acceso confidencial.
    • Postularse ocurre dentro de la app (no hay una ruta REST /apply dedicada en alpha).

    Preguntas frecuentes

    Impacto

    ¿Puedo listar oportunidades sin sesión?

    Sí, solo filas públicas no confidenciales. GET /api/opportunities/{id} y la búsqueda siguen requiriendo sesión.

    ¿Respeta la búsqueda Hide?

    Sí, cuando searchOpportunities tiene el id de usuario de la sesión (o del actor MCP). Las rutas HTTP de búsqueda GET/POST requieren sesión.

    Migración

    ¿Ha desaparecido createdBy?

    No. Sigue siendo el id de usuario. creator es una instantánea pública opcional para la UI.

    Operaciones

    ¿Por qué las listas MCP siguen mostrando UUID en las tarjetas?

    La lista MCP omite viewerUserId, así que attachOpportunityFeedFields no se aplica en esa ruta.

    Documentación relacionada

    Related documentation

    Opportunities

    Requisito previo: ciclo de producto, acciones de las tarjetas del feed y límites de tipos habilitados.

    Discovery Mutation Sync

    Depende de: etiquetas de caché, revalidatePath y Tunnel opportunity:* tras los cambios.

    Ring Tasks

    Mismo flujo: convertir en solicitud escribe metadata.source, que leen las tarjetas de la lista.

    Entities

    Mismo flujo: el vínculo con la organización es obligatorio al crear (`organizationId` / linkedEntity).

    1. Docs
    2. /API
    3. /API de oportunidades

    Actualizado 26 oct 20266 min de escucha

    API de oportunidades

    REST para el marketplace de doble naturaleza. La lista de navegación está abierta a los visitantes; todo lo demás requiere sesión. La lista de navegación (GET /api/opportunities) es una paginación por cursor consciente del rol más enriquecimiento por espectador. La búsqueda es una ruta aparte. Like / Save / Hide / Contact son Server Actions, no recursos HTTP.

    Usa las pestañas Founder / Developer para filtrar esta página. Ciclo de producto y UX de las tarjetas: Oportunidades.

    No son siete tipos

    Textos antiguos de la API enumeraban unos "7 tipos" fijos. Los tipos en tiempo de ejecución son la unión OpportunityType en features/opportunities/types/index.ts, limitada por ring-config.json → opportunities.enabledTypes. No documentes un conjunto cerrado de siete.

    Superficies (compartido)

    MétodoRutaAutenticaciónNotas
    GET/api/opportunitiesOpcionallimit, startAfter. Los parámetros de filtro types/type, q/query, categories/category, location, priority cambian al servicio de búsqueda. Pasa viewerUserId cuando hay sesión. Devuelve { opportunities, items, lastVisible, cursor, hasMore }
    POST/api/opportunitiesSesiónCuerpo createOpportunityBodySchema → { opportunity } 201
    GET/api/opportunities/{id}SesiónUn anuncio
    PUT / PATCH/api/opportunities/{id}SesiónActualizar
    DELETE/api/opportunities/{id}SesiónEliminar
    GET/api/opportunities/searchSesiónRequiere q. Opcionales types, categories, location, limit
    POST/api/opportunities/searchSesiónCuerpo JSON SearchOpportunitiesParams
    POST/api/opportunities/{id}/signSesiónFirma consultiva de una petición, una por usuario. Devuelve signatureCount, signatureTarget
    GET/api/opportunities/mySesiónLista del propietario; view= all | drafts | pending | active | archived
    POST/api/opportunities/uploadSesiónAdjuntos
    GET / POST/api/mcp/v1/opportunitiesMCP guardLa lista hoy no pasa viewerUserId

    Desde 2026-10-17, GET /api/opportunities sin autenticar devuelve filas públicas no confidenciales para el rol visitor. El filtro de visitante se aplica después de obtener la página, así que una página de invitado puede tener menos de limit filas. Detalle, búsqueda y cambios siguen devolviendo 401 sin sesión.

    Lo que deben saber los operadores

    • Navegar frente a buscar. La página /opportunities carga GET /api/opportunities (una página de anuncios). Los filtros del panel derecho se envían como parámetros de consulta y se aplican en el servidor. Los visitantes pueden navegar sin cuenta.
    • Anuncios ocultos. Cuando un miembro toca Hide, la siguiente navegación o búsqueda de esa cuenta omite el id. Los demás miembros lo siguen viendo.
    • Nombres en las tarjetas. Las respuestas de lista y búsqueda adjuntan una instantánea creator segura para el público, así que la UI nunca muestra un UUID en bruto.
    • Crear en el producto. El formulario para añadir oportunidades sigue prefiriendo el Server Action createOpportunity (app/_actions/opportunities.ts). El POST REST es para clientes de API y MCP; ambos llaman al mismo servicio.

    Ciclo de la funcionalidad

    Matcher, tipos habilitados, acciones de las tarjetas del feed, My Opportunities.

    Sincronización del descubrimiento

    Etiquetas de caché, revalidatePath, Tunnel opportunity:* tras crear, actualizar o eliminar.

    Enriquecimiento de la lista

    GET /api/opportunities (app/api/opportunities/route.ts):

    1. auth(). Sin sesión el rol es visitor, sin enriquecimiento de espectador.
    2. Con parámetros de filtro: searchOpportunities. Si no, getOpportunitiesForRole({ userRole, limit, startAfter, viewerUserId }).
    3. Si viewerUserId está definido: getViewerHiddenOpportunityIds y luego el filtro de DatabaseService { field: 'id', operator: 'not-in', value: hiddenIds }.
    4. attachOpportunityFeedFields añade creator, viewer, likes.

    searchOpportunities lee internamente session.user.id (o el id del actor MCP); los llamantes no pasan viewerUserId. La exclusión de ocultos y el adjunto se ejecutan cuando ese id existe.

    MCP GET /api/mcp/v1/opportunities llama a getOpportunitiesForRole sin viewerUserId (sin filtro de ocultos, sin creator/viewer en esa lista).

    Extras de SerializedOpportunity (lista/búsqueda)

    Archivo de tipos canónico: features/opportunities/types/index.ts. Las fechas son cadenas ISO. Las formas Timestamp de Firestore solo existen para DB_BACKEND_MODE=firebase-full.

    Cuerpo de creación (obligatorio)

    createOpportunityBodySchema (features/opportunities/lib/create-opportunity-schema.ts): title, briefDescription, organizationId, category, location, visibility, contactInfo.linkedEntity, contactInfo.contactAccount.

    POST devuelve 201 { opportunity }. Después, la creación llama a syncOpportunityDiscovery con un fragmento que incluye de la sesión (tarjetas insertadas en vivo).

    Control de acceso

    • Visibilidad en el documento: public | subscriber | member | confidential | entity. Las filas entity solo las pueden leer administradores, el autor y los miembros de la entidad vinculada. Las consultas de lista aplican filtros de visibilidad según el rol (buildOpportunityVisibilityFilters).
    • Los anuncios confidenciales requieren roles con acceso confidencial.
    • Postularse ocurre dentro de la app (no hay una ruta REST /apply dedicada en alpha).

    Preguntas frecuentes

    Impacto

    ¿Puedo listar oportunidades sin sesión?

    Sí, solo filas públicas no confidenciales. GET /api/opportunities/{id} y la búsqueda siguen requiriendo sesión.

    ¿Respeta la búsqueda Hide?

    Sí, cuando searchOpportunities tiene el id de usuario de la sesión (o del actor MCP). Las rutas HTTP de búsqueda GET/POST requieren sesión.

    Migración

    ¿Ha desaparecido createdBy?

    No. Sigue siendo el id de usuario. creator es una instantánea pública opcional para la UI.

    Operaciones

    ¿Por qué las listas MCP siguen mostrando UUID en las tarjetas?

    La lista MCP omite viewerUserId, así que attachOpportunityFeedFields no se aplica en esa ruta.

    Documentación relacionada

    Related documentation

    Opportunities

    Requisito previo: ciclo de producto, acciones de las tarjetas del feed y límites de tipos habilitados.

    Discovery Mutation Sync

    Depende de: etiquetas de caché, revalidatePath y Tunnel opportunity:* tras los cambios.

    Ring Tasks

    Mismo flujo: convertir en solicitud escribe metadata.source, que leen las tarjetas de la lista.

    Entities

    Mismo flujo: el vínculo con la organización es obligatorio al crear (`organizationId` / linkedEntity).

    1. Docs
    2. /API
    3. /API de oportunidades

    Actualizado 26 oct 20266 min de escucha

    API de oportunidades

    REST para el marketplace de doble naturaleza. La lista de navegación está abierta a los visitantes; todo lo demás requiere sesión. La lista de navegación (GET /api/opportunities) es una paginación por cursor consciente del rol más enriquecimiento por espectador. La búsqueda es una ruta aparte. Like / Save / Hide / Contact son Server Actions, no recursos HTTP.

    Usa las pestañas Founder / Developer para filtrar esta página. Ciclo de producto y UX de las tarjetas: Oportunidades.

    No son siete tipos

    Textos antiguos de la API enumeraban unos "7 tipos" fijos. Los tipos en tiempo de ejecución son la unión OpportunityType en features/opportunities/types/index.ts, limitada por ring-config.json → opportunities.enabledTypes. No documentes un conjunto cerrado de siete.

    Superficies (compartido)

    MétodoRutaAutenticaciónNotas
    GET/api/opportunitiesOpcionallimit, startAfter. Los parámetros de filtro types/type, q/query, categories/category, location, priority cambian al servicio de búsqueda. Pasa viewerUserId cuando hay sesión. Devuelve { opportunities, items, lastVisible, cursor, hasMore }
    POST/api/opportunitiesSesiónCuerpo createOpportunityBodySchema → { opportunity } 201
    GET/api/opportunities/{id}SesiónUn anuncio
    PUT / PATCH/api/opportunities/{id}SesiónActualizar
    DELETE/api/opportunities/{id}SesiónEliminar
    GET/api/opportunities/searchSesiónRequiere q. Opcionales types, categories, location, limit
    POST/api/opportunities/searchSesiónCuerpo JSON SearchOpportunitiesParams
    POST/api/opportunities/{id}/signSesiónFirma consultiva de una petición, una por usuario. Devuelve signatureCount, signatureTarget
    GET/api/opportunities/mySesiónLista del propietario; view= all | drafts | pending | active | archived
    POST/api/opportunities/uploadSesiónAdjuntos
    GET / POST/api/mcp/v1/opportunitiesMCP guardLa lista hoy no pasa viewerUserId

    Desde 2026-10-17, GET /api/opportunities sin autenticar devuelve filas públicas no confidenciales para el rol visitor. El filtro de visitante se aplica después de obtener la página, así que una página de invitado puede tener menos de limit filas. Detalle, búsqueda y cambios siguen devolviendo 401 sin sesión.

    Lo que deben saber los operadores

    • Navegar frente a buscar. La página /opportunities carga GET /api/opportunities (una página de anuncios). Los filtros del panel derecho se envían como parámetros de consulta y se aplican en el servidor. Los visitantes pueden navegar sin cuenta.
    • Anuncios ocultos. Cuando un miembro toca Hide, la siguiente navegación o búsqueda de esa cuenta omite el id. Los demás miembros lo siguen viendo.
    • Nombres en las tarjetas. Las respuestas de lista y búsqueda adjuntan una instantánea creator segura para el público, así que la UI nunca muestra un UUID en bruto.
    • Crear en el producto. El formulario para añadir oportunidades sigue prefiriendo el Server Action createOpportunity (app/_actions/opportunities.ts). El POST REST es para clientes de API y MCP; ambos llaman al mismo servicio.

    Ciclo de la funcionalidad

    Matcher, tipos habilitados, acciones de las tarjetas del feed, My Opportunities.

    Sincronización del descubrimiento

    Etiquetas de caché, revalidatePath, Tunnel opportunity:* tras crear, actualizar o eliminar.

    Enriquecimiento de la lista

    GET /api/opportunities (app/api/opportunities/route.ts):

    1. auth(). Sin sesión el rol es visitor, sin enriquecimiento de espectador.
    2. Con parámetros de filtro: searchOpportunities. Si no, getOpportunitiesForRole({ userRole, limit, startAfter, viewerUserId }).
    3. Si viewerUserId está definido: getViewerHiddenOpportunityIds y luego el filtro de DatabaseService { field: 'id', operator: 'not-in', value: hiddenIds }.
    4. attachOpportunityFeedFields añade creator, viewer, likes.

    searchOpportunities lee internamente session.user.id (o el id del actor MCP); los llamantes no pasan viewerUserId. La exclusión de ocultos y el adjunto se ejecutan cuando ese id existe.

    MCP GET /api/mcp/v1/opportunities llama a getOpportunitiesForRole sin viewerUserId (sin filtro de ocultos, sin creator/viewer en esa lista).

    Extras de SerializedOpportunity (lista/búsqueda)

    Archivo de tipos canónico: features/opportunities/types/index.ts. Las fechas son cadenas ISO. Las formas Timestamp de Firestore solo existen para DB_BACKEND_MODE=firebase-full.

    Cuerpo de creación (obligatorio)

    createOpportunityBodySchema (features/opportunities/lib/create-opportunity-schema.ts): title, briefDescription, organizationId, category, location, visibility, contactInfo.linkedEntity, contactInfo.contactAccount.

    POST devuelve 201 { opportunity }. Después, la creación llama a syncOpportunityDiscovery con un fragmento que incluye de la sesión (tarjetas insertadas en vivo).

    Control de acceso

    • Visibilidad en el documento: public | subscriber | member | confidential | entity. Las filas entity solo las pueden leer administradores, el autor y los miembros de la entidad vinculada. Las consultas de lista aplican filtros de visibilidad según el rol (buildOpportunityVisibilityFilters).
    • Los anuncios confidenciales requieren roles con acceso confidencial.
    • Postularse ocurre dentro de la app (no hay una ruta REST /apply dedicada en alpha).

    Preguntas frecuentes

    Impacto

    ¿Puedo listar oportunidades sin sesión?

    Sí, solo filas públicas no confidenciales. GET /api/opportunities/{id} y la búsqueda siguen requiriendo sesión.

    ¿Respeta la búsqueda Hide?

    Sí, cuando searchOpportunities tiene el id de usuario de la sesión (o del actor MCP). Las rutas HTTP de búsqueda GET/POST requieren sesión.

    Migración

    ¿Ha desaparecido createdBy?

    No. Sigue siendo el id de usuario. creator es una instantánea pública opcional para la UI.

    Operaciones

    ¿Por qué las listas MCP siguen mostrando UUID en las tarjetas?

    La lista MCP omite viewerUserId, así que attachOpportunityFeedFields no se aplica en esa ruta.

    Documentación relacionada

    Related documentation

    Opportunities

    Requisito previo: ciclo de producto, acciones de las tarjetas del feed y límites de tipos habilitados.

    Discovery Mutation Sync

    Depende de: etiquetas de caché, revalidatePath y Tunnel opportunity:* tras los cambios.

    Ring Tasks

    Mismo flujo: convertir en solicitud escribe metadata.source, que leen las tarjetas de la lista.

    Entities

    Mismo flujo: el vínculo con la organización es obligatorio al crear (`organizationId` / linkedEntity).

    1. Docs
    2. /API
    3. /API de oportunidades

    Actualizado 26 oct 20266 min de escucha

    Ejemplos de API

    curl con cookies de sesión en un clon local.

    creator { id, name, avatar }

    Interacciones (no REST)

    AcciónMódulo
    LiketoggleOpportunityLike → like-service / likes
    SavetoggleOpportunitySave → user_content_interactions
    HidemarkOpportunityNotInterested → user_content_interactions
    ComentariocreateOpportunityComment
    Intención de contactorecordOpportunityContactIntent (Matcher; la UI sigue haciendo router.push a /messages?user=)

    Archivo: app/_actions/opportunity-interactions.ts.

    Mapeo y not-in

    mapDbQueryRowToSerializedOpportunity() en features/opportunities/lib/opportunity-db-mapper.ts. No uses lib/converters/opportunity-converter.ts en Postgres.

    El operador 'not-in' está en IDatabaseService DatabaseFilterOperator. PostgreSQL: NOT (field = ANY($n)). El adaptador de Firebase filtra después.

    Sincronización del descubrimiento tras cambios

    Las creaciones, actualizaciones, eliminaciones y cambios de estado llaman a syncOpportunityDiscovery(), que:

    1. revalidateTag: invalida las listas de oportunidades de unstable_cache (lib/cached-data.ts)
    2. revalidatePath: /[locale]/opportunities, /[locale]/opportunities/[id], /[locale]/opportunities/my
    3. Tunnel: opportunity:created|updated|deleted en el canal opportunities

    No hay un comando aparte de reindexación de búsqueda. Ver Discovery mutation sync. La navegación del cliente sigue usando useCursorFeed (24 h); revalidatePath por sí solo no limpia esa caché.

    Ejemplos

    Creación en la UI: useActionState + createOpportunity de app/_actions/opportunities.ts, ver API integration.

    API Integration Examples

    Siguiente paso: curl con una cookie de sesión local.

    Authentication

    Depende de: cookie de sesión requerida para cada ruta de oportunidades.

    Ejemplos de API

    curl con cookies de sesión en un clon local.

    creator { id, name, avatar }

    Interacciones (no REST)

    AcciónMódulo
    LiketoggleOpportunityLike → like-service / likes
    SavetoggleOpportunitySave → user_content_interactions
    HidemarkOpportunityNotInterested → user_content_interactions
    ComentariocreateOpportunityComment
    Intención de contactorecordOpportunityContactIntent (Matcher; la UI sigue haciendo router.push a /messages?user=)

    Archivo: app/_actions/opportunity-interactions.ts.

    Mapeo y not-in

    mapDbQueryRowToSerializedOpportunity() en features/opportunities/lib/opportunity-db-mapper.ts. No uses lib/converters/opportunity-converter.ts en Postgres.

    El operador 'not-in' está en IDatabaseService DatabaseFilterOperator. PostgreSQL: NOT (field = ANY($n)). El adaptador de Firebase filtra después.

    Sincronización del descubrimiento tras cambios

    Las creaciones, actualizaciones, eliminaciones y cambios de estado llaman a syncOpportunityDiscovery(), que:

    1. revalidateTag: invalida las listas de oportunidades de unstable_cache (lib/cached-data.ts)
    2. revalidatePath: /[locale]/opportunities, /[locale]/opportunities/[id], /[locale]/opportunities/my
    3. Tunnel: opportunity:created|updated|deleted en el canal opportunities

    No hay un comando aparte de reindexación de búsqueda. Ver Discovery mutation sync. La navegación del cliente sigue usando useCursorFeed (24 h); revalidatePath por sí solo no limpia esa caché.

    Ejemplos

    Creación en la UI: useActionState + createOpportunity de app/_actions/opportunities.ts, ver API integration.

    API Integration Examples

    Siguiente paso: curl con una cookie de sesión local.

    Authentication

    Depende de: cookie de sesión requerida para cada ruta de oportunidades.

    Ejemplos de API

    curl con cookies de sesión en un clon local.

    creator { id, name, avatar }

    Interacciones (no REST)

    AcciónMódulo
    LiketoggleOpportunityLike → like-service / likes
    SavetoggleOpportunitySave → user_content_interactions
    HidemarkOpportunityNotInterested → user_content_interactions
    ComentariocreateOpportunityComment
    Intención de contactorecordOpportunityContactIntent (Matcher; la UI sigue haciendo router.push a /messages?user=)

    Archivo: app/_actions/opportunity-interactions.ts.

    Mapeo y not-in

    mapDbQueryRowToSerializedOpportunity() en features/opportunities/lib/opportunity-db-mapper.ts. No uses lib/converters/opportunity-converter.ts en Postgres.

    El operador 'not-in' está en IDatabaseService DatabaseFilterOperator. PostgreSQL: NOT (field = ANY($n)). El adaptador de Firebase filtra después.

    Sincronización del descubrimiento tras cambios

    Las creaciones, actualizaciones, eliminaciones y cambios de estado llaman a syncOpportunityDiscovery(), que:

    1. revalidateTag: invalida las listas de oportunidades de unstable_cache (lib/cached-data.ts)
    2. revalidatePath: /[locale]/opportunities, /[locale]/opportunities/[id], /[locale]/opportunities/my
    3. Tunnel: opportunity:created|updated|deleted en el canal opportunities

    No hay un comando aparte de reindexación de búsqueda. Ver Discovery mutation sync. La navegación del cliente sigue usando useCursorFeed (24 h); revalidatePath por sí solo no limpia esa caché.

    Ejemplos

    Creación en la UI: useActionState + createOpportunity de app/_actions/opportunities.ts, ver API integration.

    API Integration Examples

    Siguiente paso: curl con una cookie de sesión local.

    Authentication

    Depende de: cookie de sesión requerida para cada ruta de oportunidades.