/** * Core types for rMaps.online * Collaborative real-time friend-finding navigation */ // ============================================================================ // Room Types // ============================================================================ export interface Room { id: string; slug: string; // subdomain: .rmaps.online name: string; createdAt: Date; createdBy: string; // participant ID expiresAt: Date; // auto-cleanup after inactivity settings: RoomSettings; participants: Map; waypoints: Waypoint[]; } export interface RoomSettings { maxParticipants: number; // default: 10 password?: string; // optional room password defaultPrecision: PrecisionLevel; allowGuestJoin: boolean; showC3NavIndoor: boolean; // enable c3nav integration eventId?: string; // e.g., '39c3', 'eh2025' } // ============================================================================ // Participant Types // ============================================================================ export interface Participant { id: string; name: string; emoji: string; // avatar emoji color: string; // unique marker color joinedAt: Date; lastSeen: Date; status: ParticipantStatus; location?: ParticipantLocation; privacySettings: PrivacySettings; } export type ParticipantStatus = | 'online' // actively sharing | 'away' // app backgrounded | 'ghost' // hidden location | 'offline'; // disconnected export interface ParticipantLocation { latitude: number; longitude: number; accuracy: number; // meters altitude?: number; altitudeAccuracy?: number; heading?: number; // degrees from north speed?: number; // m/s timestamp: Date; source: LocationSource; indoor?: IndoorLocation; // c3nav indoor data } export type LocationSource = | 'gps' // device GPS | 'network' // WiFi/cell triangulation | 'manual' // user-set location | 'c3nav'; // c3nav positioning export interface IndoorLocation { level: number; // floor/level number x: number; // c3nav local X coordinate y: number; // c3nav local Y coordinate spaceName?: string; // e.g., "Saal 1", "Assembly XY" } // ============================================================================ // Privacy Types // ============================================================================ export type PrecisionLevel = | 'exact' // <5m - full precision | 'building' // ~50m - same building | 'area' // ~500m - nearby area | 'approximate'; // ~2km - general vicinity export interface PrivacySettings { sharingEnabled: boolean; defaultPrecision: PrecisionLevel; showIndoorFloor: boolean; ghostMode: boolean; // hide completely } // ============================================================================ // Navigation Types // ============================================================================ export interface Waypoint { id: string; name: string; emoji?: string; location: { latitude: number; longitude: number; indoor?: IndoorLocation; }; createdBy: string; // participant ID createdAt: Date; type: WaypointType; metadata?: Record; } export type WaypointType = | 'meetup' // meeting point | 'event' // scheduled event | 'poi' // point of interest | 'custom'; // user-created export interface Route { id: string; from: RoutePoint; to: RoutePoint; segments: RouteSegment[]; totalDistance: number; // meters estimatedTime: number; // seconds createdAt: Date; } export interface RoutePoint { type: 'participant' | 'waypoint' | 'coordinates'; id?: string; // participant or waypoint ID coordinates?: { latitude: number; longitude: number; indoor?: IndoorLocation; }; } export interface RouteSegment { type: 'outdoor' | 'indoor' | 'transition'; coordinates: Array<[number, number]>; // [lng, lat] for GeoJSON distance: number; duration: number; instructions?: string; level?: number; // for indoor segments } // ============================================================================ // c3nav Integration Types // ============================================================================ export interface C3NavLocation { id: number; slug: string; title: string; subtitle?: string; can_search: boolean; can_describe: boolean; geometry?: GeoJSON.Geometry; level?: number; } export interface C3NavRouteRequest { origin: C3NavPoint; destination: C3NavPoint; options?: C3NavRouteOptions; } export interface C3NavPoint { coordinates?: [number, number, number]; // [x, y, level] slug?: string; // location slug } export interface C3NavRouteOptions { mode?: 'fastest' | 'shortest'; avoid_stairs?: boolean; avoid_escalators?: boolean; wheelchair?: boolean; } export interface C3NavRouteResponse { status: 'ok' | 'no_route'; request?: C3NavRouteRequest; origin?: C3NavLocation; destination?: C3NavLocation; distance?: number; duration?: number; path?: Array<{ coordinates: [number, number, number]; level: number; }>; } // ============================================================================ // Event Types (for real-time updates) // ============================================================================ export type RoomEvent = | { type: 'participant_joined'; participant: Participant } | { type: 'participant_left'; participantId: string } | { type: 'participant_updated'; participant: Partial & { id: string } } | { type: 'location_updated'; participantId: string; location: ParticipantLocation } | { type: 'waypoint_added'; waypoint: Waypoint } | { type: 'waypoint_removed'; waypointId: string } | { type: 'room_settings_changed'; settings: Partial }; // ============================================================================ // Map Types // ============================================================================ export interface MapViewport { center: [number, number]; // [lng, lat] zoom: number; bearing?: number; pitch?: number; } export interface MapBounds { north: number; south: number; east: number; west: number; } // CCC venue bounds (Hamburg Congress Center) export const CCC_VENUE_BOUNDS: MapBounds = { north: 53.5580, south: 53.5520, east: 9.9950, west: 9.9850, }; // ============================================================================ // Utility Types // ============================================================================ export interface ApiResponse { success: boolean; data?: T; error?: string; } export type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; };