Een dating-app op basis van brieven, niet van gezichten!

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

4.9 kB Ruw bestand
/*
 * Het gemeenschapsrapport ophalen: welke metingen er gedaan worden en met welke vensters.
 *
 * Dit staat apart van wie het afdrukt, omdat er inmiddels drie afnemers zijn: `npm run health` in de
 * terminal, hetzelfde als HTML-bestand, en de maandelijkse pagina op de website (/cijfers). Die drie
 * horen naar dezelfde meting te kijken — anders zegt de ene pagina iets anders dan de andere over
 * dezelfde maand, en dan is geen van beide nog te vertrouwen.
 *
 * De vensters hieronder zijn eigenschappen van de méting, niet van het product; wat wel een uitspraak
 * over het product is (wanneer heet het een correspondentie) staat in src/constants.js.
 */
import * as db from "./queries.js";

export const DEFAULTS = {
  days: 30,             /* het venster */
  weeks: 8,             /* cohortrijen in de trechter */
  settle: 14,           /* hoe lang een eerste brief de tijd krijgt voordat hij meetelt */
  grace: 7,             /* zo lang lid zijn voordat je meetelt in de verdeling van de aandacht */
  readSettle: 7,        /* idem voor "is hij al gelezen?" */
  hostile: 30,          /* liep de eerste brief hierbinnen uit op een blokkade of melding? */
  responsive: 90,       /* wie telt als iemand die daadwerkelijk terugschrijft */
  sample: 500,          /* bereikbaarheid: steekproef uit de actieven; 0 = iedereen */
  placements: 15,       /* zoveel woonplaatsen per proefprofiel; het cijfer is de mediaan daarvan */

  /*
   * De proefprofielen. Oriëntatie staat er expliciet in, want zonder dat meet je niemand: de
   * standaardinstelling van een nieuw account zoekt álle genders, en dan tel je vrouwen, mannen en
   * non-binaire mensen bij elkaar op tot een getal dat voor geen enkele echte persoon geldt.
   *
   * Dit is een vaste lijst en geen afgeleide van wie er al lid is, en dat is de bedoeling: een proef
   * die zijn vragen ontleent aan de bestaande leden meet vooral dat de bestaande leden er zijn.
   * Juist de cel die leeg blijft — een vrouw van 55 die vrouwen zoekt — is het antwoord waarvoor
   * dit bestaat.
   */
  probeProfiles: [
    { label: "vrouw zoekt man", gender: "v", seeks: ["m"] },
    { label: "man zoekt vrouw", gender: "m", seeks: ["v"] },
    { label: "vrouw zoekt vrouw", gender: "v", seeks: ["v"] },
    { label: "man zoekt man", gender: "m", seeks: ["m"] },
    /* Wie uitdrukkelijk alle genders zoekt staat logischerwijs ook open voor trans correspondenten;
       het omgekeerde profiel spreekt zichzelf tegen. */
    { label: "non-binair zoekt iedereen", gender: "x", seeks: ["v", "m", "x"], seekTrans: true },
    /* En andersom: wie zelf trans is verschijnt alleen bij wie daar bewust voor openstaat. Dat is
       de bescherming uit de matchquery, en dit is de enige plek waar zichtbaar wordt wat ze kost.
       seekTrans staat aan omdat createUser() dat voor een trans account ook doet. */
    { label: "trans vrouw zoekt man", gender: "v", seeks: ["m"], trans: true, seekTrans: true, publiek: false },
    { label: "trans man zoekt vrouw", gender: "m", seeks: ["v"], trans: true, seekTrans: true, publiek: false },
  ],
  probeAges: [25, 35, 45, 55, 65],
};

/*
 * De zes goedkope metingen tegelijk; de bereikbaarheid daarna, want die is de enige die kan duren
 * (O(n²) over de actieve leden). `reachability: false` slaat hem over — dat doet zowel `--fast` als
 * de publieke pagina, die hem niet toont.
 */
export async function collectReport(opts = {}) {
  const w = { ...DEFAULTS, ...opts };
  const [overview, funnel, openers, spread, shapes, safety] = await Promise.all([
    db.communityOverview({ days: w.days }),
    db.newcomerFunnel({ weeks: w.weeks }),
    db.openerOutcomes({ settleDays: w.settle }),
    db.attentionSpread({ days: w.days, graceDays: w.grace }),
    db.pairShapes({ days: w.days, readSettleDays: w.readSettle }),
    db.safetySignals({ days: w.days, hostileDays: w.hostile }),
  ]);

  const t0 = Date.now();
  const reachability = w.reachability === false ? null : await db.reachability({ days: w.days, sample: w.sample });
  const probeGrid = await db.probeGrid({
    profiles: w.probeProfiles, ages: w.probeAges, days: w.days,
    responsiveDays: w.responsive, placements: w.placements,
  });
  const reachMs = Date.now() - t0;

  /*
   * Waar op gezocht wordt staat er alleen bij als erom gevraagd wordt, en dat is met opzet de
   * omgekeerde schakelaar van `reachability` (die je uitzet). De publieke pagina roept
   * collectReport() zonder deze vlag aan en krijgt hem dus nooit: wat mensen intypen om iemand te
   * vinden is iets voor de beheerder om de gemeenschap mee te begrijpen, niet iets om te publiceren.
   */
  const searchTerms = w.searchTerms ? await db.searchTerms({ days: w.days }) : null;

  const { probeProfiles, probeAges, reachability: _skip, searchTerms: _skip2, ...window } = w;
  return {
    data: { generatedAt: new Date().toISOString(), window, overview, funnel, openers, spread, shapes, safety, reachability, probeGrid, searchTerms },
    reachMs,
  };
}