features

DreamPro Citizen Science Platform — Deep Feature Reference

The DreamPro Citizen Science Platform is the public-facing community layer built on top of the unified DreamPro/Open Energy templates model. It is the active development frontier of HiveJournal — replication science as a worldwide participatory effort. This doc is the technical reference for everything that lives under /dreampro/* (excluding the private /dashboard/dreampro/* task surfaces). For the original Open Energy 10-phase pathway, see open-energy.md.

What it is

A worldwide community of citizen scientists, family teams, K-12 classrooms, and meetup groups replicating Open Energy experiments together. The platform is a directory and coordination layer — HiveJournal connects parties (sponsors ↔ scientists, teachers ↔ classroom-safe templates, organizers ↔ attendees, builders ↔ video viewers) but never processes payments and never stores personally identifying minor data.

Eight phases have shipped. Phase 7 (cron) and Phase 8b (channel landing) remain.

Phase map

PhaseSurfaceStatus
1Citizen Scientist World Map (/dreampro/map) + opt-in
2Open Energy Competition leaderboard (/dreampro/competition/[slug])
3aSponsors directory (/dreampro/sponsors, /sponsorship, /sponsors/apply)
3bOpportunities (/dreampro/opportunities[/slug])
3cSponsorable participants (/dreampro/sponsorable)
4Local meetups + events (/dreampro/meetups[/id], /meetup-organizer)
5K-12 classrooms (/dreampro/classroom, /templates/classroom, /classrooms/[id])
6Family teams (/dreampro/family)
7Manual scoring trigger (cron deferred)✅ trigger / ⏳ cron
8aDream videos (URL embed model)
8bDedicated /dreampro/videos channel landing + Creator Kit⏳ pending YouTube channel

URL map

RoutePurposeFile
/dreamproPublic landing with 8 entry-point cardspage.tsx
/dreampro/templatesBrowse all research-grade templatestemplates/page.tsx
/dreampro/templates/[id]Template detail (clone, replicate, build, video submit)templates/[id]/page.tsx
/dreampro/templates/classroomClassroom-safe template browse with grade-band filtertemplates/classroom/page.tsx
/dreampro/mapWorld map of opted-in participantsmap/page.tsx
/dreampro/citizen-scientistIndividual opt-in formcitizen-scientist/page.tsx
/dreampro/competition/[slug]Annual competition leaderboardcompetition/[slug]/page.tsx
/dreampro/sponsorsSponsor wallsponsors/page.tsx
/dreampro/sponsorshipProgram landing with tier benefitssponsorship/page.tsx
/dreampro/sponsors/applySponsor application formsponsors/apply/page.tsx
/dreampro/opportunitiesBrowse opportunities by kindopportunities/page.tsx
/dreampro/opportunities/[slug]Opportunity detail with apply CTAopportunities/[slug]/page.tsx
/dreampro/sponsorableDirectory of citizen scientists seeking sponsorshipsponsorable/page.tsx
/dreampro/meetupsBrowse meetups + global upcoming events feedmeetups/page.tsx
/dreampro/meetups/[id]Meetup detail with events list and RSVPmeetups/[id]/page.tsx
/dreampro/meetup-organizerMeetup group registrationmeetup-organizer/page.tsx
/dreampro/classroomTeacher opt-in formclassroom/page.tsx
/dreampro/classrooms/[id]Public classroom page with progress reportsclassrooms/[id]/page.tsx
/dreampro/familyFamily team registrationfamily/page.tsx

Backend

All endpoints live in apps/backend/src/routes/dreampro.ts (a single large router file). Services and helpers:

  • Scoring: services/dreampro/competition-scorer.tsrecomputeCompetition(), enrollParticipantInActiveCompetitions()
  • Privacy floor: utils/geoFuzz.tsfuzzCoords(), snapToGrid()
  • YouTube parsing: utils/youtube.tsextractYouTubeVideoId(), fetchYouTubeOEmbed()
  • Legacy bridge (Phase 0 of unification): services/dreampro/legacy-bridge.ts
  • Mosaic generator: services/dreampro/mosaic-generator.ts

Express route ordering trap

Several specific routes MUST be defined before parameterized /:id routes or Express will incorrectly match the parameter pattern. Routes that need this care:

  • GET /templates/community-summary before GET /templates/:id
  • GET /templates/classroom before GET /templates/:id
  • GET /meetup-events before GET /meetups/:id
  • GET /participants/sponsorable before GET /participants/:id
  • GET /participants/me before GET /participants/:id

Migrations

#FileAdds
050050_dreampro_unification.sqldreams template/clone columns, dream_replications, dream_builds, dream_cheers, version-bump triggers, can_mark_research_grade()
051051_legacy_experiment_clone_bridge.sqllegacy_experiment_clone_map for dual-write
052052_dreams_is_seed.sqlis_seed flag
053053_dream_mosaics.sqldream_mosaics cache + participation_version counter
054054_participants_and_competitions.sqlparticipants, participant_pattern_focus, competitions, competition_entries; seeds open-energy-2026
055055_sponsors.sqlsponsors + sponsorships (M2M)
056056_opportunities.sqlopportunities (internship/scholarship/fellowship/mentorship)
057057_sponsorable_participants.sqlseeking_sponsorship + sponsor_outreach
058058_classrooms.sqldreams.safety_level, dreams.min_grade_band, classroom_progress_reports
059059_meetups.sqlmeetup_events + meetup_event_rsvps + count view
060060_dream_videos.sqldream_videos + dream_video_upvotes

Privacy & safety invariants (do not violate)

These are the load-bearing design rules. Most have a "we'd get sued or banned" failure mode. Treat them as immutable unless explicitly relaxed by legal review.

Geographic privacy (all participant kinds)

  • All coordinates fuzzed server-side via fuzzCoords() to a ~5km grid + per-user deterministic jitter
  • The raw lat/lng a user submits is never persisted
  • Enforced in POST /api/dreampro/participants/opt-in — there is no path that bypasses the fuzz

K-12 classrooms (Phase 5)

  1. NO STUDENT DATA EVER. The participant is the school. The teacher is the contact. There are no rows representing individual students anywhere in the database.
  2. APPROXIMATE STUDENT COUNTS ONLY — bucketed at the form layer (10/20/30/40), never exact.
  3. TEMPLATES DEFAULT TO adult_only. Admins must explicitly call /admin/templates/:id/promote-to-classroom to make any template visible in the classroom catalog. There is no auto-promotion.
  4. PROGRESS REPORTS ARE AGGREGATE — class-as-a-unit, never per-student.
  5. TEACHER MUST OWN THE CLASSROOMPOST /classrooms/:id/progress-reports checks classroom.linked_user_id === auth.uid().
  6. NO PHOTOS, NO STUDENT FILES, NO DM. The platform never accepts uploads tied to a classroom.

Sponsors directory (Phase 3a)

  • contact_email and contact_name are admin-only and never returned by public endpoints — only the columns in SPONSOR_PUBLIC_COLUMNS
  • Six tiers: platinum / gold / silver / bronze / in_kind / community
  • Directory model only — HiveJournal does NOT process payments. Sponsors apply, admin approves, the wall renders publicly. Money flows happen off-platform.
  • The recipient's email is never exposed to the sender. The platform forwards via Resend with the sender's reply-to so threading still works
  • Rate-limited 5/24h per (sender, recipient) to prevent abuse

Dream videos (Phase 8a)

  1. Classroom-kind participants CANNOT submit videos (minor safety, enforced server-side at POST /videos)
  2. Rate limit: 3 submissions per user per 24 hours
  3. URL must extract a valid 11-char YouTube ID
  4. oEmbed must succeed (rejects private/deleted/non-existent videos)
  5. One pending or approved video per (template, submitter) — schema UNIQUE constraint
  6. Embeds use youtube-nocookie.com to minimize tracking
  7. Directory only — admin approval before public display, never re-host video files
  • Opt-in submission IS the consent record. A participants row existing implies the user submitted the form
  • We capture consent_version ('v1') and consent_at so we can prove what was on the page at the time
  • If consent text changes, bump the version

Scoring model (Phase 2 + 7)

The scoring service walks dreams (clones), dream_replications, and dream_builds for events whose created_at falls inside [competition.starts_at, competition.ends_at], groups by user_id, multiplies by per-event weights, and materializes the totals into competition_entries.current_score + rank.

Default weights:

EventPoints
Clone a template1
Complete a clone5
Confirm a replication25
Refute a replication5
Publish a build10

Weights are stored per-competition in competitions.scoring_rules and can be overridden. Recompute is idempotent — same input state always produces same output.

Manual trigger (Phase 7)

The competition leaderboard page detects super_admin and shows an amber row with a "Recompute scores" button. The button POSTs to /api/dreampro/competitions/:slug/recompute, which is gated server-side via isSuperAdmin(). On success the page refetches the leaderboard so new scores/ranks render in place.

Auto-enrollment

Opting into the map auto-enrolls the new participant in all active, entry-open competitions. Implemented in both:

  • The API endpoint POST /participants/opt-in (calls enrollParticipantInActiveCompetitions())
  • Seed scripts (which bypass the API) — see seed-citizen-scientists.ts for the manual mirror

Future cron (Phase 7 deferred)

When added, the cron should iterate competitions WHERE is_active AND entry_open and call recomputeCompetition(comp.id) for each. The trigger code is the same one-liner as the manual button.

Map architecture (Phase 1)

Leaflet + OpenStreetMap tiles. Free, no API key, indefinitely sustainable.

The inner map component must be dynamic-imported with ssr: false because Leaflet references window at module load:

// apps/frontend/src/app/dreampro/map/page.tsx
const WorldMapInner = dynamic(() => import('@/components/dreampro/map/WorldMapInner'), {
  ssr: false,
})

Seed data

Run order matters — sponsors must exist before opportunities, participants before meetups.

cd apps/backend
npx tsx scripts/seed-citizen-scientists.ts --apply  # 12 globally distributed individuals
npx tsx scripts/seed-sponsors.ts --apply             # 6 placeholder sponsors
npx tsx scripts/seed-opportunities.ts --apply        # 4 sample opportunities
npx tsx scripts/seed-meetups.ts --apply              # 3 meetups + 6 events

All seed rows carry is_seed=true so they can be filtered out via the Show demo toggles on each page.

Computational companion — calculators, optimizer, structured measurements

A full software layer that lets users predict before they build, reducing wasted physical iterations and enabling software-only contributions toward the 50-confirmation goal.

6 experiment calculators

Pure TypeScript, no external deps. Public, no auth required — accessible to anonymous visitors for funnel. Each returns structured outputs with confidence levels (exact / approximate / order-of-magnitude) and optional Chart.js graph data.

CalculatorCoversObjective for optimizer
ResonanceLC tank f₀, Q factor, bandwidth, tank voltage/currentMax Q factor
CoilToroid + solenoid inductance, SRF, distributed capacitance, DC wire resistance. 8 cores (FT37/50/82/114 in -43/-61/-77 materials)Max SRF
ImpedanceFull Z(f) sweep with magnitude + phase (log frequency axis) — "what your NanoVNA will show"Max Q
ElectrolysisFaraday-law gas production, voltage + overall energy efficiency, pulsed-mode correctionMax energy efficiency
Pulsed DCBack-EMF peak, inductor energy, recovery capacitor voltage + efficiency, time-domain waveformMax recovery efficiency
PlasmaPaschen curve for 5 gases, breakdown voltage, operating-point analysisMin breakdown voltage
  • Engine: apps/backend/src/services/experiment-calculators/
  • Endpoints: GET /api/dreampro/calculators, POST /api/dreampro/calculate
  • Frontend: ExperimentCalculator.tsx — mounted on research-grade template detail pages

Structured measurements (migration 078)

dream_replications now carries calculator_inputs, calculator_outputs, measured_values, and delta_values JSONB. The delta (predicted vs measured %) is computed server-side via PATCH /api/dreampro/replications/:id/measurements. The "Record your measurements" form on the template page shows real-time delta badges as the user types (green <5%, amber <20%, red >20%).

Parameter optimizer

optimizer.ts sweeps up to 50K parameter combinations per calculator, ranking by the default objective function (see table above). Admins set the top result as the golden spec on the template (predicted_values JSONB on dreams). The public-facing "Confirm this prediction" card on the template page shows: recommended build parameters, expected outcomes, convergence bar toward 50 confirmations within ±5%, and a "Clone + confirm this experiment" CTA.

  • Endpoints: POST /api/dreampro/optimize, GET /api/dreampro/optimize/meta/:calculator, POST /api/dreampro/templates/:id/golden-spec (super-admin), GET /api/dreampro/templates/:id/confirm-invitation (public)
  • Frontend: ExperimentOptimizer.tsx

Aggregate results + anomaly detection

GET /api/dreampro/templates/:id/measurement-stats aggregates measured_values across all replications. Per-parameter: mean, stddev, min/max, predicted reference, within-5% count, anomaly detection (>2σ). Frontend ExperimentResults.tsx renders Chart.js histograms with the predicted-value bin highlighted green, convergence bars, and anomaly flags in red.

The end-to-end flow

  1. Admin runs optimizer → reviews ranked configurations → sets #1 as golden spec
  2. Public "Confirm this prediction" card appears on the template page
  3. Visitor runs the calculator (predict before you build) → sees expected values + graph
  4. Buys parts, builds, records measurements → system computes delta
  5. Community aggregates converge (or diverge) → convergence bar tracks toward 50
  6. Anomalies (>2σ) surface for investigation — the gap between calculation and reality is where the 768-patent meta-pattern claims live

Future work

  • Phase 7 cron — wire the recompute trigger into Vercel Cron (or equivalent). The function call is already factored out
  • Phase 8b/dreampro/videos channel landing page with downloadable Creator Kit assets. Blocked on the actual YouTube channel existing (so we can hard-link to it)
  • Federation considerations — the participant model is single-instance. If/when we want to federate citizen scientist data with other platforms, the participants table will need a stable external identifier and consent-flow extensions

See also

  • INDEX.md § DreamPro Citizen Science Platform — feature index entries
  • open-energy.md — original 10-phase Open Energy initiative (legacy /open-energy/* routes still exist)
  • ../DREAMPRO_PLAN.md — earlier DreamPro design notes
Dreampro Citizen Science — Docs | HiveJournal