~/progetti/dit/README.md

COOKIES_ADVICE PRIVACY_POLICY.

~/progetti/dit/README.md

Dit

{ date: “2026-05-14”, status: “live”, stack_modules: 11 }

Minimal presence signals between people — no chat, no messages, just presence

Dit is a mobile app (iOS and Android) that allows exchanging minimal presence signals between people. No text, no images, no voice messages — just two primitives inspired by Morse code: a Dit (·) means "I'm here", a Dah (—) means "received". The app is for anyone who wants to stay in touch with important people without the pressure of a conversation.

## The concept

Dit is based on a simple observation: sometimes you want to show someone you're thinking of them — without having to formulate a message. Inspired by the old habit of calling someone and hanging up before they answer — a free signal that meant "thinking of you" or "call me back".

·Dit (·) — a short signal to another person, with a configurable lifetime of 1 hour, 6 hours, or 24 hours
·Dah (—) — a confirmation as a response, means "received" or "I'm also here"
·No simultaneously active Dit per user pair — one signal at a time, no more
·Notification tones encoded in Morse code: ·· (letter I = I) for Dit, ··— (letter U = you) for Dah

## Core features

The app includes the following functional areas:

·Authentication: Email + Password, Email OTP (passwordless), Google OAuth, Facebook OAuth
·Contact system: Search by username, one-sided and silent saving, private nicknames, Display name resolution (nickname → name → username)
·Real-time delivery: Signals are delivered immediately via WebSocket when the recipient is online
·Push notifications: custom Morse tones, action buttons directly in notification (send Dah without opening the app), scheduled reminders before expiration
·Multi-device: Notifications on all devices, cross-device dismiss sync, token deletion on logout
·Privacy: Profile visibility (All/Contacts/None), user blocking with immediate and irreversible data deletion, generic 404 responses without blocking indication
·Ping timeline: Visual sequence diagram representation of all signals between two users, rendered with Skia on GPU

## Architecture

Four independent services that communicate exclusively through shared infrastructure — no service calls another directly:

·dit-api (NestJS + Fastify): REST API for auth, users, contacts, ping creation, push token management
·dit-ping (Go): WebSocket engine for real-time delivery, Dah/Ignore processing, TTL monitoring, presence management
·dit-notifications-worker (Node.js + BullMQ): Push notification delivery via FCM, scheduled reminders, token cleanup
·dit-mobile (React Native + Expo): Cross-platform client for iOS and Android

## Tech stack

Technical choices reflect product requirements:

·Mobile: React Native 0.83+, Expo SDK 55 (Bare Workflow), expo-router, React Native Skia, Reanimated 4, Unistyles v3, Zustand, Notifee
·Backend API: NestJS 11, Fastify, BetterAuth, Prisma, ioredis, BullMQ
·Real-time engine: Go 1.23+, Fiber v3, nhooyr.io/websocket, go-redis v9, pgx v5
·Notification worker: Node.js, BullMQ, Firebase Admin SDK, Zod
·Database: PostgreSQL 16 + TimescaleDB 2 (Hypertable for Pings with time-series partitioning)
·Cache and queue: Redis 7 (presence, Pub/Sub, BullMQ queue, TTL state)
·Auth: BetterAuth (self-hosted), Two-token system: Session cookie (REST) + short-lived HS256 JWT (WebSocket)
·Email: Brevo SMTP for transactional emails
·Push: Firebase Cloud Messaging for Android and iOS (FCM-to-APNs proxy)

## Design system

A coherent visual system runs through the entire app:

·Primary color: toxic green (#2EF080 Dark, #00B84E Light)
·Two-font system: DM Mono for identity moments (timestamps, codes, signals), System UI for body text
·Animations: exclusively Spring-Physics (Reanimated 4), four configured presets
·DitPressable: single interactive component, combines Gesture Handler + Reanimated + Haptics
·PingTimeline: Skia canvas with Dot-and-Thread design, pulsing halos, tappable dots with tooltips
·DitGlow: Skia radial gradient effect under action bar with pulse animation
·Floating tab bar: pill-shaped with blur background and spring-animated icons

## Important design decisions

Decisions that shape the product and architecture:

·Two separate backends without direct runtime contact: dit-api creates pings via REST, dit-ping processes status updates via WebSocket — communication only via Redis Pub/Sub
·JWT independently validated: Go service validates tokens with the same secret, without calling the NestJS API — Zero Runtime Coupling
·ProfileFormatterService as sole visibility enforcer: every API response with user data goes through this service
·Blocking returns generic 404: blocked user cannot distinguish between "blocked" and "account deleted"
·FCM for both platforms: Firebase Admin SDK routes automatically — FCM direct for Android, FCM-to-APNs proxy for iOS
·TimescaleDB for Pings: time-series partitioning enables efficient time-based queries and automatic data cleanup

## What I'm learning

Insights from developing a real-time system with four independent services:

·Define clear ownership boundaries between services from day one — who writes what to which table
·Redis Pub/Sub as communication bus between heterogeneous services (TypeScript and Go) without direct contact
·Privacy as architectural constraint: generic errors, centralized visibility, destructive blocking
·Prefer Spring animations over withTiming — the difference in perceived quality is significant
·Notification sounds as branding element: Morse code tones make the app instantly recognizable without visual markers

Dit is available on Google Play Store. A European product based in Italy. Say nothing. Mean everything.

// stack
[react-native”, expo”, nestjs”, go”, postgres”, redis”, timescaledb”, websocket”, mobile”, real-time”, presence”, ]