Skip to content

Latest commit

 

History

History
353 lines (277 loc) · 8.96 KB

PLAN.adoc

File metadata and controls

353 lines (277 loc) · 8.96 KB

NAFA Migration Plan: ReScript + Deno MVP

Overview

NAFA (Neurodiverse App for Adventurers) uses a ReScript + Deno architecture:

  • ReScript for type-safe client code with TEA (The Elm Architecture) pattern

  • Deno for server runtime and package management

  • Shared types for compile-time guarantees across the stack

Current MVP Status

Feature Status Location

Journey Plan View

✅ Complete

client/src/Page/JourneyView.res

Sensory Annotations

✅ Complete

client/src/Page/Annotate.res

Accessibility Settings

✅ Complete

client/src/Page/Accessibility.res

Offline Mode

✅ Complete

client/src/Page/Offline.res

Domain Types

✅ Complete

shared/src/Domain.res

Routing

✅ Complete

shared/src/Route.res

Deno Server

✅ Complete

server/src/main.js

CLI Demo

✅ Complete

server/src/demo.js

Project Structure

nafa-app/
├── client/                         # Browser SPA (ReScript)
│   ├── src/
│   │   ├── Main.res               # App entry with TEA pattern
│   │   └── Page/
│   │       ├── JourneyView.res    # Journey display
│   │       ├── Annotate.res       # Sensory annotation form
│   │       ├── Accessibility.res  # A11y settings
│   │       └── Offline.res        # Offline mode management
│   └── rescript.json
│
├── server/                         # Deno API server
│   ├── src/
│   │   ├── main.js                # HTTP server with REST API
│   │   └── demo.js                # CLI demo runner
│   └── deno.json
│
├── shared/                         # Shared types
│   ├── src/
│   │   ├── Domain.res             # Core domain types
│   │   └── Route.res              # Type-safe routing
│   └── rescript.json
│
├── nickel-rituals/                 # Badge/tier configuration
├── scripts/                        # Build scripts
├── Justfile                        # Task runner
└── PLAN.adoc                       # This file

Dependency Stack

Current (Self-Contained MVP)

┌─────────────────────────────────────────────────────────────────┐
│                        nafa-app                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌──────────────────┐    ┌────────────────┐ │
│  │   Deno      │    │    ReScript      │    │  @rescript/core│ │
│  │             │    │                  │    │                │ │
│  │ HTTP server │    │ TEA pattern      │    │ Standard lib   │ │
│  │ JSR imports │    │ Type-safe views  │    │ Belt, Core     │ │
│  └─────────────┘    └──────────────────┘    └────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Deferred Dependencies

These external packages are planned but not yet available:

Package Purpose Status

@cadre/router

Type-safe URL parsing (Parser, Navigation, Link)

Branch exists, not published to JSR

@cadre/tea-router

TEA integration via TeaRouter.Make functor

Needs GitHub repo creation

rescript-tea

Full TEA framework for browser

Available on npm, not yet integrated

Note
The MVP is fully functional without these dependencies. They will enable richer browser-based routing when published.

Running the MVP

# Run the CLI demo
just mvp-demo

# Start the API server (requires Deno)
just mvp-server

# Development mode with watch
just mvp-dev

# Build ReScript modules
just mvp-build

# Type-check server files
just mvp-check

Domain Types

Core Types (shared/src/Domain.res)

Sensory Profile

type sensoryLevel = int  // 0-10 scale

type sensoryProfile = {
  noise: sensoryLevel,
  light: sensoryLevel,
  crowd: sensoryLevel,
}

Journey

type transportMode = Walk | Bus | Train | Tram | Metro

type journeySegment = {
  id: string,
  transportMode: transportMode,
  fromLocation: string,
  toLocation: string,
  durationMinutes: int,
  sensoryWarning: option<string>,
  sensoryLevels: option<sensoryProfile>,
}

type journeyStatus = Planning | Active | Paused | Completed

type journey = {
  id: string,
  title: string,
  segments: array<journeySegment>,
  status: journeyStatus,
  estimatedMinutes: int,
  sensoryAnnotations: array<sensoryAnnotation>,
}

Accessibility

type textSize = Small | Medium | Large | ExtraLarge
type contrastMode = Standard | HighContrast | DarkHighContrast
type motionPreference = Full | Reduced | None
type hapticPreference = Off | Subtle | Standard | Strong

type accessibilityPrefs = {
  textSize: textSize,
  contrastMode: contrastMode,
  motionPreference: motionPreference,
  screenReaderVerbosity: screenReaderVerbosity,
  hapticFeedback: hapticPreference,
  reduceTransparency: bool,
  boldText: bool,
  monoAudio: bool,
}

Offline Mode

type connectivityStatus = Online | Offline | Connecting | Unstable
type syncStatus = Synced | Pending | Syncing | Conflict | Error(string)

type cached<'a> = {
  data: 'a,
  cachedAt: float,
  syncStatus: syncStatus,
  version: int,
}

type offlinePrefs = {
  enableOfflineMode: bool,
  autoSync: bool,
  syncOnWifiOnly: bool,
  maxCacheAgeDays: int,
  prefetchUpcomingJourneys: bool,
}

Routes

Available Routes (shared/src/Route.res)

Path Description

/

Home page

/journeys

Journey list

/journey/:id

View specific journey

/annotate/:locationId

Add sensory annotation

/accessibility

Accessibility settings

/offline

Offline mode management

API Endpoints

Server (server/src/main.js)

Method Endpoint Description

GET

/api/journey/:id

Retrieve journey by ID

GET

/api/annotations

List all sensory annotations

POST

/api/annotation

Create new sensory annotation

Migration Checklist

Completed ✅

  • ✓ Create directory structure (client/, server/, shared/)

  • ✓ Initialize rescript.json for each package

  • ✓ Set up shared type definitions (Domain.res, Route.res)

  • ✓ Configure deno.json for server

  • ✓ Implement journey view with TEA pattern

  • ✓ Implement sensory annotation flow

  • ✓ Implement accessibility settings

  • ✓ Implement offline mode management

  • ✓ Create Deno HTTP server with REST API

  • ✓ Create CLI demo runner

  • ✓ Remove legacy Elm files (src/*.elm)

  • ✓ Remove malformed files (elm-ui, assets)

  • ✓ Remove empty directories (elixir-backend)

Pending (Future Work)

  • ❏ Publish @cadre/router to JSR

  • ❏ Create and publish @cadre/tea-router

  • ❏ Integrate rescript-tea for browser runtime

  • ❏ Add browser entry point (index.html)

  • ❏ Implement real API integration (replace mocks)

  • ❏ Add authentication/session management

  • ❏ Server-side routing (Stage 3)

  • ❏ CRDT state for real-time features

Architecture Decisions

Why Deno over Node?

  • Native TypeScript/JavaScript support

  • Built-in formatter and linter

  • Secure by default (explicit permissions)

  • JSR for modern package management

  • No node_modules bloat

Why ReScript over TypeScript?

  • Sound type system (no any escape hatch)

  • Exhaustive pattern matching

  • Guaranteed null-safety with option<T>

  • Compiles to clean JavaScript

  • TEA pattern feels natural

Why TEA Pattern?

  • Predictable state management

  • Easy to test and debug

  • Scales well with complexity

  • Familiar to Elm developers

  • Works well with accessibility requirements

Next Steps

  1. Browser Integration: Add index.html and wire up ReScript to DOM

  2. Real Data: Replace mock journey with API calls

  3. Persistence: Implement IndexedDB for offline storage

  4. Testing: Add unit tests for domain logic

  5. CI/CD: Configure build pipeline for ReScript + Deno