tane/docs/design/sharing-model.md
vjrj adf396d49d feat(plantare): surface product link + dates; spec the bilateral record
The Plantaré screen stored madeOn/dueBy/varietyId but showed none of them,
so it felt half-built. Surface what's already there (no schema change):

- watchPlantareViews() joins each commitment with its variety label
- tile shows the made-on date, a "Return by {date}" line (amber + "overdue"
  when an open promise is past due, via new seedWarning colour), the variety
  name, and taps through to /variety/:id
- add sheet gains an optional return-by date picker (createPlantare already
  took dueBy)
- variety detail shows a read-only commitments section (hidden when empty,
  no add button — honours the single hand-over door)
- i18n en/es/pt/ast; tests for the join, dueBy round-trip, tile, and section

Also specs the deferred two-sided record in docs/design/plantare-bilateral.md
(Nostr pubkey counterparty, PlantareTransport propose->accept->counter-sign,
deferred key/signature/movement columns, provenance DAG, reputation anchor),
with a faithful transcription of the paper Plantaré v0.4 (BAH-Semillero 2009,
CC-BY-SA). Cross-linked from data-model §2.7 and sharing-model §6.
2026-07-13 18:06:33 +02:00

8.5 KiB
Raw Permalink Blame History

Tane — Modelo de compartición y mercado (nota de diseño)

Documento de reflexión. Lengua: español (discusión). Desarrolla la Capa 3 del PLAN.md §3§4 y §6, y conecta con el modelo de datos (data-model.md).

Dos cosas a resolver aquí: (a) cómo se anuncia lo que alguien comparte, de forma descentralizada, más allá del pagaré bilateral (que es el cierre, no el escaparate); y (b) permitir que quien quiera pueda pedir dinero —mercado— sin traicionar el alma del proyecto ni aumentar el riesgo legal de la gente.


1. El Plantare no es el anuncio

Aclaración conceptual, porque es fácil mezclarlos:

  • El Plantare (§5-bis) es el cierre bilateral de un intercambio: el compromiso firmado entre dos personas cuando ya se han encontrado. Es privado, entre las dos partes.
  • Lo que falta es el escaparate: cómo anuncia alguien "tengo esto para dar/cambiar/vender" para que otra persona lo descubra antes de que exista trato alguno. Eso es la Oferta (Offer).

Oferta → contacto → trato → (opcional) Plantare. El pagaré es el último paso, no el primero.


2. La Oferta (Offer): anunciar sin exponerse

Una Offer es una declaración firmada y publicada a la red: "yo (clave pública) ofrezco [resumen de variedad] cerca de [ubicación aproximada], como [regalo/trueque/venta], [condiciones]". Principios:

  • Revela solo lo que elijas. La Offer es un objeto distinto del Lot/inventario: publicas un resumen (nombre, foto, condiciones), nunca tu inventario completo ni tu dirección exacta. La separación Offer↔Lot es una decisión de privacidad, no solo técnica.
  • Ubicación aproximada siempre. Geohash de baja precisión (el "10 km near you" de los mockups), nunca coordenadas exactas. La precisión la sube la persona solo al cerrar trato, en privado.
  • Identidad = clave pública que controlas (Nostr). Sin registro central, sin email obligatorio.
  • La app presenta; la gente cierra. La Offer enlaza a un canal de contacto (mensaje cifrado). El trato se cierra entre personas. Es el "efecto Wallapop" sin el intermediario Wallapop.
  • Estacionalidad y caducidad. Las semillas son de temporada: la Offer tiene estado (active/reserved/closed) y caducidad (expires_at); hay que refrescarla. Una oferta vieja no debe engañar.
  • Descubrimiento = consulta a relays/instancias por geohash + categoría → es la pantalla de búsqueda de los mockups (04_search_page, 05_search_item).

Transporte concreto: NIP-99

Detrás de la abstracción OfferTransport (PLAN §4), el primer backend es Nostr NIP-99 ("Classified Listings"): evento kind:30402 (activo) / 30403 (borrador), con campos estructurados de título, resumen, precio (importe + moneda), ubicación y estado. Es decir: el estándar ya contempla precio y moneda de serie, así que regalo, trueque y venta caben en el mismo mecanismo. Existe ecosistema real (p.ej. Shopstr) del que aprender. La ubicación puede acompañarse de un tag geohash. ActivityPub / FEP-0837 queda como segundo backend posible.


3. Los cuatro modos de una Offer

offer_type:

  • Regalo (gift) — gratis, sin retorno esperado. El don puro.
  • Trueque (exchange) — a cambio de otras semillas, trabajo, o el compromiso Plantare (devolver después). Es el modo de reciprocidad.
  • Venta (sale) — dinero. Precio + moneda. (la novedad que pides)
  • Busco (wanted) — el inverso: anunciar demanda, no oferta ("busco semilla de tomate rosa de Barbastro"). Barato de añadir y muy útil en bancos y ferias.

4. El mercado (dinero): cómo hacerlo sin traicionar el proyecto

Permitir vender es legítimo y realista —hay quien produce semilla artesanal, quien vende excedente— pero toca el alma anti-monopolio del proyecto y la ley. Cómo cuadrarlo, con las tensiones nombradas, no escondidas:

4.1 Valores: el don es de primera clase; la venta, permitida, no promovida

  • En la interfaz, regalo y trueque se muestran primero; la venta es un modo que eliges, nunca el defecto. Preservas el ethos sin imponer tu criterio a nadie (autonomía de la persona).
  • Sin gamificación de la venta, sin "destacados de pago", sin ránkings de vendedores. Vender es una etiqueta más, no el eje.

Esto es lo delicado. La venta de variedades tradicionales no registradas es exactamente lo que multó a Kokopelli; el regalo/trueque entre aficionados o agricultores está mucho más protegido (PLAN §6). Al añadir "venta" aumentas la exposición legal de tus usuarios. Mitigaciones de diseño:

  • Tane no es un mercado, es infraestructura neutral. La app no opera el mercado, no publica un catálogo central, no pone en venta nada: son las personas, entre iguales (como flohmarkt). Esta neutralidad es la mejor defensa (replica por qué Kokopelli fue vulnerable —venta + operador central identificable— y evita ambas).
  • Aviso contextual por región, no policía. Al marcar una Offer como "venta", la app puede mostrar una nota suave y dependiente del país ("vender semilla de variedades no registradas puede estar restringido en tu país"). Informar, no bloquear, no vigilar.
  • La venta prioriza el marco de conservación/compartición en el discurso y el diseño; el dinero es una opción, no la portada.

4.3 Nada de rieles de pago (esto es innegociable)

  • La app NO procesa pagos, NO cobra comisión, NO retiene dinero, NO muestra publicidad. El pago se acuerda directamente entre las personas (efectivo, su propia transferencia, lo que sea), fuera de la app.
  • Meter pagos dentro convertiría a Tane en operador central: obligaciones KYC/AML, custodia de fondos, y reintroduce justo la centralización que se quiere evitar. Además mataría la sostenibilidad (§7: financiación por subvenciones/donaciones, no por comisiones).
  • Resultado: es el "efecto Wallapop sin Wallapop" también para la venta — anuncia y conecta; el dinero cambia de manos entre personas.

4.4 Representación del precio

price_amount (decimal) + price_currency (ISO 4217, admitiendo también monedas locales/comunitarias) + price_negotiable (bool). Para trueque, exchange_terms (texto: "a cambio de semilla de legumbre" / "o X horas"). El precio puede ser "a convenir".

4.5 Confianza y abuso

  • Un mercado abierto y descentralizado atrae spam y estafas. La red de confianza (Capa 4) es el filtro: mostrar primero ofertas de gente dentro de tu grafo de confianza; el ámbito local/geohash ya acota mucho.
  • Tras un trato, valoraciones/comentarios (los del mockup de perfil 09_public_profile) — descentralizados, sin bloquear a nadie.

5. Añadidos al modelo de datos

Nueva entidad publicable (se serializa a NIP-99 / ActivityPub). En inglés, para data-model.md:

Offer

Columna Tipo Notas
id UUID
lot_id UUID → Lot Nullable (puedes ofrecer sin exponer un lote concreto; wanted no lo usa).
variety_summary TEXT/JSON Desnormalizado: nombre + ref de foto que eliges publicar (privacidad).
offer_type enum gift / exchange / sale / wanted.
price_amount DECIMAL Nullable (solo sale).
price_currency TEXT Nullable. ISO 4217 o moneda local.
price_negotiable BOOLEAN
exchange_terms TEXT Nullable (para exchange).
approx_geohash TEXT Baja precisión.
radius_km INTEGER Ámbito.
status enum active / reserved / closed.
published_at / expires_at Estacionalidad.
transport_ref TEXT id del evento en el relay (NIP-99) / objeto AP.
author_key TEXT Clave pública que publica.
(+ columnas comunes)

Offer es distinta de Lot a propósito: publicar revela solo lo elegido. Un trato cerrado puede generar un Movement (given) y, si es trueque con retorno, un Plantare.


6. A decidir

  • ¿Las valoraciones (reputación) se atan a un Movement/Offer cerrado para evitar reseñas falsas? (Probablemente sí, Capa 4.) El ancla fuerte es el Plantaré bilateral firmado — spec en plantare-bilateral.md.
  • ¿Permitir monedas comunitarias/tiempo explícitamente en price_currency (guiño al espíritu Plantare como "moneda de semillas")? Interesante.
  • ¿Ofertas de banco colectivo (publica el banco, no la persona)? Afecta a identidad/permisos (Capa 23).
  • ¿Cómo se revoca/expira una Offer publicada en relays que ya la replicaron? (Estado closed + caducidad; los relays acaban soltando lo viejo.)