Rastrum Rastrum

Detailed tasks

Per-item roadmap breakdown. Subtasks with status and spec references.

Updated: 2026-04-26 · View roadmap

✓ Done ~ In progress ○ Planned ! Blocked

v0.1 Alpha MVP (online-first) Shipped

astro-skeleton Astro site skeleton + Tailwind + i18n
6/6

subtasks

Astro 5 project with output: 'static'
Tailwind 3 + @astrojs/tailwind integration
EN/ES locales via astro/i18n + prefixDefaultLocale
BaseLayout + DocLayout shared shells
Header + Footer with theme toggle, lang switcher, mobile menu
Sitemap (@astrojs/sitemap)
supabase-schema Supabase schema with PostGIS + RLS

02-observation.md · 05-map.md · 06-darwin-core.md · 07-licensing.md

8/8

subtasks

6 core tables (users, taxa, taxon_usage_history, observations, identifications, media_files)
PostGIS geography columns + GIST indexes
RLS owner + public-read + credentialed-read
3 triggers (auth-user-created, obs-count, sync-primary-id)
obscure_point() helper + obscure_level enum
Idempotent — replayable via make db-apply
Storage bucket 'media' + policies
Role-level grants (anon SELECT, authenticated CRUD)
auth-magic-link Magic-link auth + guest mode

04-auth.md

6/7

subtasks

supabase.ts singleton client
auth.ts helpers (sendMagicLink, exchangeCode, signOut)
Sign-in pages in EN + ES
Callback handles PKCE and implicit flows
Header avatar dropdown via onAuthStateChange
ObserverRef discriminated union
Hard-cap UI nudge after 3rd guest observation
auth-multi Google + GitHub OAuth, OTP code, passkey, sign-out-everywhere

04-auth.md

6/7

subtasks

signInWithGoogle / signInWithGitHub (with user:email scope)
Email OTP code path (verifyOtp)
Passkey enrol + verify (b64url ↔ ArrayBuffer)
WebAuthn feature detection
signOutEverywhere() global revocation
SignInForm shared component used by both locales
!
Operator: enable WebAuthn MFA toggle in dashboard

Blocked by: Manual dashboard step

ci-cd CI/CD via GitHub Actions

infra/testing.md · infra/github-actions.yml

5/5

subtasks

ci.yml — typecheck + test + build on PRs
deploy.yml — typecheck + test + build + deploy
deploy-functions.yml — manual Edge Function deploys
PUBLIC_* secrets pushed via gh secret set
Vitest job runs in CI
profile-basics Profile page + edit + avatar dropdown

08-profile-activity-gamification.md

7/7

subtasks

ALTER TABLE users with 11 profile/credential columns
ProfileView + ProfileEditForm shared components
Pages in EN /profile/* and ES /perfil/*
Initials-SVG avatar fallback
Header avatar dropdown (View / Edit / Sign out)
Activity feed section (renders v0.3+ events)
Badges section (renders when gamification opted in)
gps-observation GPS observation form with EXIF auto-fill

02-observation.md

9/9

subtasks

Multi-image capture/upload
Live GPS via getCurrentPosition
EXIF GPS fallback via exifr
Manual coords input
Habitat / weather / evidence_type dropdowns
Notes textarea (≤2000 chars)
NOM-059 / CITES privacy notice
Audio capture (MediaRecorder ≤30s)
Saves to Dexie outbox + immediate sync attempt
plantnet-id PlantNet photo ID integration

01-photo-id.md · 13-identifier-registry.md

7/7

subtasks

Edge Function with PlantNet → Claude waterfall
force_provider field for cascade routing
client_keys.plantnet BYO key support
0.7 confidence threshold
Plugin wrapper in identifiers/plantnet.ts
testConnection() probe
Operator: deploy + set secret
claude-haiku-id Claude Haiku 4.5 vision cascade

01-photo-id.md

4/5

subtasks

Cached system prompt (90% token savings)
JSON response parsing with code-fence stripping
client_anthropic_key BYO support
Cost-tracking probe in testConnection
Operator: optional ANTHROPIC_API_KEY secret
map-view MapLibre map with clustered observation pins

05-map.md

6/6

subtasks

OpenFreeMap Liberty style (free, IPv4)
GeoJSON source from observations table
Clustering at low zoom + pins at high zoom
Kingdom-coloured pins
Click pin → popup with thumbnail + link
pmtiles offline layer (handed off to v0.3 offline-maps)

→ tracked under offline-maps

darwin-core-csv Darwin Core CSV export

06-darwin-core.md

5/5

subtasks

darwin-core.ts mapping + CSV generation
Three column presets: DwC / SNIB / CONANP
Obscuration tier handling
ExportView component with format selector
9 Vitest unit tests
pwa-manifest PWA manifest + service worker shell cache

03-offline.md

4/4

subtasks

manifest.webmanifest with display:standalone
sw.js cache-first for same-origin GETs
Production-only registration (skip localhost)
Apple-mobile-web-app meta tags
offline-queue Dexie IndexedDB outbox + sync engine + identify trigger

03-offline.md · 10-media-storage.md

6/6

subtasks

RastrumDB with observations / mediaBlobs / idQueue
syncOutbox + registerSyncTriggers
R2 + Supabase Storage dual upload paths
Client-side image resize before upload
Cascade engine integration
Audio blob support
unit-tests Vitest unit-test scaffold

infra/testing.md

4/6

subtasks

Vitest 4.1 + happy-dom env
darwin-core.test.ts (9 tests)
byo-keys.test.ts (10 tests)
Make targets + CI integration
pgTAP RLS test suite
Playwright E2E suite

v0.3 Offline intelligence + activity Shipped

activity-feed Activity feed + server-side triggers

08-profile-activity-gamification.md

6/6

subtasks

activity_events table with kind enum (12 values)
RLS self/public + visibility tiers
fire_observation_created trigger
fire_research_grade trigger (auto-public)
Profile-page rendering with i18n labels
Auto-mark-as-read on view
unread-badge Unread-count badge on avatar dropdown

08-profile-activity-gamification.md

3/3

subtasks

Red dot with count when unread > 0
Refresh on every onAuthStateChange
99+ overflow text
sensitive-privacy NOM-059 / CITES obscuration warning

02-observation.md

4/5

subtasks

Amber notice always visible in form
Schema obscure_level enum
sync_primary_identification trigger applies obscuration
location_obscured separate column for public reads
Per-species look-up at form-submit time
exif-extraction EXIF/XMP/ID3 metadata auto-extraction

02-observation.md

3/3

subtasks

exifr library wired in observation form
GPS extracted with EXIF source flag
DateTimeOriginal → observation timestamp
webllm-text WebLLM Llama-3.2-1B for translation + field notes

11-in-browser-ai.md

5/6

subtasks

@mlc-ai/web-llm installed
loadTextEngine + translateNote + generateFieldNote
Profile/edit AI download card with consent modal
Cache management (probe / delete / re-download)
requestPersistentStorage() to prevent iOS eviction
Translate + Auto-narrative buttons in observation form
onnx-base EfficientNet-Lite0 ONNX base fallback (~18 MB INT8 hosted on R2)

13-identifier-registry.md

6/6

subtasks

Convert model to ONNX (TF Model Garden EfficientNet-Lite0)
Bundle ImageNet labels JSON
src/lib/identifiers/onnx-base.ts implementation
Image preprocessing (224x224 cover crop + ImageNet mean/std)
On-device inference via onnxruntime-web (cached in IndexedDB)
Profile/edit AI download card with consent + cache management
offline-maps pmtiles offline map download (Mexico zoom 0–10, ~48 MB)

05-map.md

5/6

subtasks

Mexico-bounded pmtiles archive hosted on R2
PUBLIC_PMTILES_MX_URL env var wired into the build
src/lib/offline-map.ts download + Cache API persistence
MapLibre pmtiles:// protocol registered for offline reads
Profile/edit download card with cell-conn warning
Per-region zoom 11–14 chunks on-demand
byo-anthropic-key BYO Anthropic key (client-set, never persisted)

01-photo-id.md · 13-identifier-registry.md

5/5

subtasks

byo-keys.ts central store backed by localStorage
client_keys.anthropic forwarded per call to Edge Function
Edge Function never logs or persists the key
Profile/edit Configure UI with Save/Test/Clear
testConnection() probe verifies a live key
webllm-default WebLLM as default AI fallback (download warning on first use)

11-in-browser-ai.md · 13-identifier-registry.md

5/5

subtasks

Phi-3.5-vision plugin registered in bootstrapIdentifiers()
Cascade automatically falls back to WebLLM when network plugins fail
First-use download dialog with size + persistence consent
Cache management (probe/delete/re-download) in profile
0.35 confidence cap to prevent low-quality auto-promote
identification-block Visible identification block in observation form

02-observation.md · 01-photo-id.md

5/5

subtasks

Inline ID block under photo grid (spinner + result chip)
Auto-fires on first photo + manual re-run button
Manual scientific-name input overrides cascade
Confidence + source surfaced (PlantNet, Claude, …)
Low-confidence amber notice when conf < 0.4
gps-two-pass Two-pass GPS: fast coarse fix then high-accuracy refinement

02-observation.md

5/5

subtasks

First call: enableHighAccuracy=false, ~1 s timeout
Second call: enableHighAccuracy=true, ~10 s timeout
Form preview updates live as fix improves
Cancel logic on form submit / reset
Falls back to EXIF GPS on timeout

v0.5 Beta

byo-keys-platform Per-plugin BYO API keys with guided setup

13-identifier-registry.md

6/6

subtasks

KeySpec + SetupStep + testConnection contract
byo-keys.ts central store
One-time legacy migration
Per-plugin Configure disclosure UI
Live save + Test + Clear buttons
10 unit tests
webllm-vision WebLLM Phi-3.5-vision fallback ID

11-in-browser-ai.md

5/5

subtasks

Phi-3.5-vision plugin in identifiers/phi-vision.ts
Confidence hard-cap 0.35 (DB trigger blocks <0.4)
Disclaimer in profile/edit + plugin description
Same consent + cache + delete flow as Llama
Cascade integration as last-resort opt-in
discovery-badges 39 seed badges + nightly evaluator

08-profile-activity-gamification.md

6/7

subtasks

badges + user_badges tables with RLS
39 badge seed (5 categories × 4 tiers)
Badge eligibility SQL functions
award-badges nightly Edge Function
Profile-page tier-coloured pills
Cron schedule 30 7 * * *
Activity-feed badge_earned event integration
quality-gates Confidence ≥ 0.4 enforcement on research-grade

08-profile-activity-gamification.md

2/2

subtasks

enforce_research_grade_quality trigger
Plugin-level confidence_ceiling cap
consensus-workflow Research-grade 2/3 consensus + anti-sybil + expert weight

08-profile-activity-gamification.md

2/4

subtasks

prevent_self_validation trigger
recompute_consensus with 3× expert weight
Validator UI for community input
AFTER INSERT/UPDATE auto-recompute trigger
multi-image Multi-image observations

02-observation.md

4/4

subtasks

Gallery <input multiple>
Photo grid with primary indicator + remove
All blobs saved to Dexie + uploaded to R2
media_files inserted with sort_order + is_primary
eco-evidence Ecological evidence fields

02-observation.md

2/2

subtasks

evidence_type enum on observations
Form dropdown with 9 values
birdnet-audio BirdNET-Lite audio ID (Cornell Lab CC BY-NC-SA 4.0, ONNX hosted on R2)

12-birdnet-audio.md

9/9

subtasks

Audio capture in observation form (≤30s)
Sync engine routes audio to R2 + cascade
Module 12 spec written
BirdNET-Lite v2.4 ONNX hosted on R2 + PUBLIC_BIRDNET_WEIGHTS_URL
Audio decode + 48 kHz resample + 3 s window pre-processing
onnxruntime-web inference in plugin (top-K species)
Bundle species labels JSON (~6,000 species)
Profile/edit download card with consent + cache management
Cornell Lab CC BY-NC-SA 4.0 attribution in UI + DwC export
scout-v0 Rastrum Scout v0 (conversational ID, pgvector RAG)
0/6

subtasks

!
Enable pgvector extension

Blocked by: Deferred per future-migrations.md

!
Embedding pipeline (Voyage-3 over ~50K Mexican taxa)

Blocked by: Embedding budget (~$50)

taxon_embeddings table + HNSW index
scout Edge Function (retrieval + Claude composition)
Chat UI in app
chat_sessions table + history
onnx-regional Regional ONNX packs (Oaxaca, Yucatán)
0/5

subtasks

!
Training pipeline (TFLite Model Maker / PyTorch+Optimum)

Blocked by: ML training infra

Curated training set per region (~1K species each)
Convert to ONNX int8
Download cards in profile/edit
Region-aware cascade routing (lat/lng → pack)
gbif-ipt GBIF IPT pilot publish (DwC-A ZIP)

06-darwin-core.md

3/6

subtasks

!
GBIF publisher account application

Blocked by: ~2-week ed-org review

DwC-A ZIP generator (meta.xml + eml.xml + csvs)
export-dwca Edge Function (on-demand export)
publish-to-ipt.sh operator script
gbif-publish Edge Function (monthly cron)
DOI tracking in dataset_versions table
local-contexts Local Contexts BC/TK Notice integration
0/4

subtasks

!
Community consent (Zapoteco partnership)

Blocked by: Multi-month governance work

Local Contexts Hub API v2 integration
observation_bc_notices link table
BC/TK label rendering on observations + DwC
user-api-tokens User API tokens (rst_*, scoped, SHA-256 hashed)

14-user-api-tokens.md

5/5

subtasks

user_api_tokens table with hashed token + scopes[]
Crypto-strong rst_<base32> generation client-side
RLS owner-only on user_api_tokens
Plaintext shown to user exactly once on creation
last_used_at fire-and-forget update on each call
token-rest-api Token-authenticated REST API

14-user-api-tokens.md

7/7

subtasks

supabase/functions/api Edge Function deployed
/api/observe POST creates a row in observations
/api/identify POST runs the cascade with the user's BYO keys
/api/observations GET (paginated, RLS-scoped to caller)
/api/export GET returns Darwin Core CSV for caller
Scope enforcement (observe/identify/export) per route
Deployed --no-verify-jwt; the function validates rst_* itself
token-ui Token management UI at /profile/tokens (EN) and /perfil/tokens (ES)

14-user-api-tokens.md

6/6

subtasks

Locale-paired routes /profile/tokens and /perfil/tokens
Create form (label + scopes checkboxes) + plaintext modal
List existing tokens (label, scopes, last used, created)
Revoke action with confirm
i18n strings under tr.profile.tokens.*
Copy-to-clipboard button on creation

v1.0 Public Launch

streaks Opt-in streaks + grace window

08-profile-activity-gamification.md

5/6

subtasks

user_streaks table
recompute_streak() with single-grace-per-30-days
recompute-streaks Edge Function (nightly)
Quality gate: confidence ≥ 0.4
Streak display on profile page (StreakCard)
Inbox-digest email for milestones
shareable-cards Observation share OG cards
5/5

subtasks

share-card Edge Function (SVG + HTML)
Branded design with species + region
OG / Twitter card meta
Sensitive-species badge when obscured
Public Astro page renders observation
social-features Follows + comments + watchlists schema

08-profile-activity-gamification.md

4/4

subtasks

follows table (anti-self-follow + RLS)
observation_comments (threading + soft-delete)
watchlists with radius_km
UI implementation (Comments, FollowButton, WatchlistView)

→ tracked under follows-comments-ui

expert-system Expert taxonomic 3× weight

08-profile-activity-gamification.md

3/4

subtasks

users.is_expert + users.expert_taxa[] columns
recompute_consensus() applies 3× weight
Expert-application UI (ExpertApplyView)
Expert badges in profile
bioblitz-events Events table + RLS

08-profile-activity-gamification.md

3/7

subtasks

events table with region_geojson
Public-read RLS
Three event kinds (bioblitz/survey/challenge)
Event detail page
Event aggregates (obs within polygon × window)
Participation badges
Top-decile detection
institutional-export DwC + SNIB + CONANP CSV presets

06-darwin-core.md

3/3

subtasks

Three column subsets in darwin-core.ts
Format selector in Export view
Filename suffixes per format
credentialed-access credentialed_researcher RLS gate

07-licensing.md

2/3

subtasks

Three columns on users table
obs_credentialed_read RLS policy
Application flow page
env-enrichment Lunar phase + OpenMeteo weather Edge Function
3/3

subtasks

enrich-environment Edge Function
Auto-fires on observation sync
Updates 5 environmental columns
video-support Video support ≤30s (H.265/AV1)

02-observation.md

3/6

subtasks

Video capture in observation form (MediaRecorder ≤30s)
media_files row with media_type='video' + R2 upload
Video preview tile in form grid (autoplay muted)
Server-side ffmpeg transcoding pipeline
Frame extraction for ID + audio split for BirdNET
Video player on share/obs page
camera-trap-ingest Camera trap ingestion (MegaDetector v5a INT8 ONNX)

09-camera-trap.md · 19-batch-photo-importer.md

3/5

subtasks

Bulk-upload UI at /profile/import/camera-trap (drag-drop)
Shared trap location (single GPS) + per-photo EXIF timestamp
MegaDetector v5a INT8 ONNX hosted on R2 (model_not_bundled stub)
camera_trap_deployments + processing_queue tables (deferred)
Edge Function: motion → ID → research-grade pipeline
capacitor-ios Capacitor iOS App Store wrapper (v1.2)
0/5

subtasks

!
Apple Developer Program ($99/yr)

Blocked by: Subscription required

Capacitor scaffolding + platform/ios
Native plugins (Camera, Geo, FS, Network)
App Store metadata + screenshots
First TestFlight build
follows-comments-ui UI for follows + threaded comments + watchlists

08-profile-activity-gamification.md

3/5

subtasks

Follow button on public profile pages (FollowButton.astro)
Threaded comments component on share/obs page (Comments.astro)
Watchlist add/edit view in profile (WatchlistView.astro)
Followers' research-grade events in activity feed
Watchlist alerts (inbox digest, daily cron)
map-location-picker Interactive map picker for observation location

15-map-location-picker.md · 02-observation.md

5/5

subtasks

Drag-pin + tap-to-place on MapLibre
Locality search (geocoder) with EN/ES results
Reverse-geocode to populate locality string
Mobile bottom-sheet UX for the picker
Round-trip integration with ObservationForm fields
my-observations Personal observation list/history page

16-my-observations.md

6/6

subtasks

Route /profile/observations (EN) / /perfil/observaciones (ES)
MyObservationsView component (shared between locales)
Thumbnail grid with status pill (synced/pending/failed)
Click row → /share/obs/<id> for detail
Includes outbox-pending rows (unsynced)
Pagination + newest-first sort
camera-getUserMedia In-app camera via getUserMedia API with file-input fallback

17-in-app-camera.md · 02-observation.md

5/5

subtasks

navigator.mediaDevices.getUserMedia({video:{facingMode:'environment'}})
Live <video> preview + capture-to-canvas → Blob
Permission denied → fallback to <input type=file capture=environment>
Stream cleanup on close to avoid camera-on indicator
Identify + Observe surfaces both wire to it
batch-exif-importer Batch photo importer with EXIF GPS/datetime extraction

19-batch-photo-importer.md

6/6

subtasks

Drag-drop / file-input multi-photo intake
exifr extraction of GPS + DateTimeOriginal per file
Per-row review table (include/exclude, edit fields)
Bulk insert into Dexie outbox + queued sync
EN /profile/import/, ES /perfil/importar/ pages
Camera-trap deep-link (subroute) for staged uploads
oauth-custom-domain Custom auth domain on Supabase OAuth (auth.rastrum.org)

04-auth.md

0/4

subtasks

!
Supabase Pro plan ($25/mo) — required by Supabase for custom auth domain

Blocked by: Deferred for the zero-cost target; default Supabase callback host is fine for v1.0

DNS CNAME for auth.rastrum.org
Update Site URL + redirect allow-list in Supabase Auth
Re-test Google + GitHub OAuth flows on custom domain
mcp-server MCP server for AI agents (JSON-RPC over HTTP at /functions/v1/mcp)

15-mcp-server.md · 14-user-api-tokens.md

6/6

subtasks

supabase/functions/mcp Edge Function with JSON-RPC 2.0 transport
tools/list and tools/call backed by user_api_tokens scopes
5 tools: identify_species, submit_observation, list_observations, get_observation, export_darwin_core
initialize + ping unauthenticated for capability probing
Deployed --no-verify-jwt; the function validates rst_* itself
Documented Claude Desktop, Cursor, VS Code, Copilot Coding Agent integrations
rastrum-org-domain Migrate canonical domain to rastrum.org
6/6

subtasks

Register rastrum.org + DNS via Cloudflare
Update Astro site config + sitemap host
Migrate media bucket hostname to media.rastrum.org
Service worker pass-through host list updated
Old domain (rastrum.artemiop.com) 301-redirects
Documentation updated to reference rastrum.org

v1.5 Territory Layer Planned

biodiversity-trails Biodiversity Trails with GPS waypoints + diversity metrics
0/5

subtasks

trails table (start/end, route LineString, observer)
Trail recording UI (start/stop, waypoints)
Per-trail observation linking (FK trail_id)
Diversity metrics per trail (S, H', D)
Trail detail page + map render
pits-qr PITs + QR/NFC anchors
0/5

subtasks

pits table (slug, polygon, install_location)
/{lang}/pit/<slug>/ page (obs in polygon)
QR generator for printing
NFC tag write protocol docs
Stats: visitors + species recorded at PIT
spatial-analysis Spatial analysis: ANP/INEGI/INAH GeoJSON layers
0/5

subtasks

Static GeoJSON for ANP boundaries (CONANP)
INEGI municipal boundaries
INAH archaeological-zone polygons
Layer toggle in MapLibre
PostGIS ST_Within queries (obs within ANP X)
diversity-indices Diversity indices: S, H', D, Chao1, Pielou J
0/4

subtasks

diversity-stats Edge Function (bbox + window → JSON)
Math: Shannon-Wiener, Simpson, Chao1, Pielou
Rarefaction curves
Render in trail / event / region pages
trail-pdf-export Trail PDF export (field guide style)
0/3

subtasks

Server-side PDF rendering (Puppeteer or react-pdf)
Cover map, species list, diversity stats
Bilingual templates

v2.0 Institutional Planned

camera-trap-advanced Camera trap: occupancy modelling, activity histograms
0/3

subtasks

R or Python statistical pipeline
Activity histograms by species + time-of-day
Multi-camera grid analysis
gbif-publisher GBIF dataset publisher + DOI generation
0/3

subtasks

Continuous DwC-A export
Versioned dataset releases with DOIs (Zenodo/DataCite)
Citation generator
regional-ml Regional ML training pipeline

07-licensing.md

0/4

subtasks

Continuous fine-tuning on validated observations
Federated learning across institutional partners
Model card publication per release
License gate: only CC BY / CC0 enter training
b2g-dashboard B2G SaaS dashboard for CONANP / state agencies
0/5

subtasks

Separate Astro+React app at b2g.rastrum.app
Per-agency report templates
Stripe subscriptions
Audit logs + SLA monitoring
!
Cornell BirdNET commercial license signed

Blocked by: Cornell licensing process

inat-bridge iNaturalist import/export bridge
0/4

subtasks

iNat OAuth flow
Import: pull user's iNat observations
Export: push verified data back with attribution
Rate-limit compatibility

v2.5 AI + AR Planned

scout-full Rastrum Scout — full conversational field AI
0/4

subtasks

Multi-turn conversation refinement
Region-aware retrieval (lat/lng filtering)
Citation rendering for sources
Builds on scout-v0
ar-overlay AR species overlay in camera viewfinder
0/3

subtasks

WebXR or Capacitor ARKit/ARCore
Real-time camera frame → ID → 3D label
Performance budget: 30fps mobile
voice-indigenous Indigenous language voice I/O
0/3

subtasks

Whisper-tiny via transformers.js for STT
!
Custom-trained TTS for Zapoteco/Mixteco

Blocked by: No off-the-shelf TTS exists

Conversation flow in Zapoteco for Sierra Norte pilot
conabio-api Formal CONABIO/CONANP/INAH partnership APIs
0/3

subtasks

MOUs with each agency
Whitelisted API endpoints with audit logs
Bidirectional sync agreements

Edit docs/tasks.json to update. The page rebuilds on every push.

Report an issue

We'll include this in your report