Faros is a full-stack web application for tracking lighthouse visits and connecting with other lighthouse enthusiasts. The system follows a clean architecture pattern with clear separation between frontend, backend, and data layers.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ Backend │ │ Database │
│ (React) │◄──►│ (Go API) │◄──►│ (Turso/SQLite)│
│ │ │ │ │ │
│ - User Interface│ │ - REST API │ │ - User Data │
│ - State Mgmt │ │ - Authentication│ │ - Lighthouse DB │
│ - API Client │ │ - Business Logic│ │ - Relationships │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ ┌─────────────────┐
└─────────────►│ Device Passkey │
│ Authenticator │
└─────────────────┘
┌─────────────────────────────────────────────────┐
│ HTTP Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐│
│ │ Lighthouse │ │ User │ │ Friends ││
│ │ Handler │ │ Handler │ │ Handler ││
│ └─────────────┘ └─────────────┘ └─────────────┘│
└─────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────┐
│ Business Logic │
│ ┌─────────────────────────────────────────────┐│
│ │ Interfaces Layer ││
│ │ (DBInterface) ││
│ └─────────────────────────────────────────────┘│
└─────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────┐
│ Data Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐│
│ │ Lighthouse │ │ User │ │ Friends ││
│ │ DB │ │ DB │ │ DB ││
│ └─────────────┘ └─────────────┘ └─────────────┘│
└─────────────────────────────────────────────────┘
- LighthouseHandler: Manages lighthouse-related operations
- UserHandler: Handles user profiles and lighthouse visits
- FriendsHandler: Manages social features and friend relationships
- DBInterface: Defines database operations contract
- Enables dependency injection and testability
- Abstracts database implementation details
- Turso (production): SQLite in the cloud
- SQLite (local): File-based database for development
- Connection pooling and transaction management
- CORS: Cross-origin resource sharing
- Authentication: WebAuthn passkey verification and JWT validation
- Error Handling: Consistent error responses
src/
├── components/
│ ├── features/ # Feature-specific components
│ │ ├── lighthouses/ # Lighthouse management
│ │ ├── friends/ # Social features
│ │ └── map/ # Map visualizations
│ └── layout/ # Layout components
├── context/ # React contexts
│ ├── UserContext # User state management
│ └── LighthouseContext # Lighthouse data
├── hooks/ # Custom React hooks
│ ├── useApi # API communication
│ ├── useUser # User operations
│ └── useLighthouse # Lighthouse operations
└── utils/ # Utility functions
├── api.ts # API client
└── map.ts # Map utilities
- React Context: Global state for user and lighthouse data
- Custom Hooks: Encapsulate business logic and API calls
- Local State: Component-specific state management
1. User visits application (no authentication required)
2. Frontend requests lighthouse data from public API
3. Backend serves lighthouse data without authentication
4. Map displays all lighthouses to any visitor
5. Interactive features require authentication
1. Frontend requests a short-lived, single-use WebAuthn ceremony
2. The user's device or password manager verifies the passkey
3. Backend validates the signed WebAuthn response and stored credential
4. Frontend receives a 24-hour JWT
5. JWT is included in authenticated API requests
6. Backend validates the JWT for protected routes
1. Frontend component triggers action
2. Custom hook handles API call
3. Public routes: Direct API call (no auth headers)
4. Protected routes: API client adds authentication headers
5. Backend handler receives request
6. Public routes: Process immediately
7. Protected routes: Middleware validates authentication
8. Handler processes business logic
9. Database layer executes queries
10. Response sent back to frontend
11. Context/state updated
12. UI re-renders with new data
- Lighthouse Data: Publicly accessible without authentication
- Map Visualization: Available to all visitors
- Basic Browse Functionality: No login required
- Passkeys: Discoverable WebAuthn credentials with required user verification
- JWT Tokens: Stateless authentication for protected routes
- Header-based Auth: Bearer token in Authorization header
- Public Routes: Lighthouse data accessible to everyone
- Protected Routes: Authentication middleware on user-specific endpoints
- User Context: Access control based on authenticated user
- Data Isolation: Users can only access their own personal data (visits, wishlist, friends)
- Input Validation: Query parameter validation and sanitization
- SQL Injection Prevention: Parameterized queries
- CORS Configuration: Controlled cross-origin access
Developer Machine
├── Frontend (localhost:5173)
│ ├── Public: Lighthouse map and data
│ └── Protected: User features (login required)
├── Backend (localhost:8080)
│ ├── Public API: /api/lighthouses
│ └── Protected API: /user/* endpoints
└── Database (SQLite file)
├── Public: Lighthouse data
└── Private: User data, visits, friendships
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Azure Static │ │ Cloud Host │ │ Turso │
│ Web Apps │◄──►│ (Backend) │◄──►│ Database │
│ (Frontend) │ │ │ │ │
│ │ │ Public Routes: │ │ Public Data: │
│ - Public Map │ │ /api/lighthouses│ │ - Lighthouses │
│ - Auth Features │ │ │ │ │
│ │ │ Protected: │ │ Private Data: │
│ │ │ /user/* │ │ - User profiles │
│ │ │ /users/search │ │ - Visits │
│ │ │ │ │ - Friendships │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- lighthouses: Lighthouse information and locations (publicly accessible)
- users: User profiles and metadata (authentication required)
- webauthn_users: Stable opaque user handles scoped by relying-party ID
- webauthn_credentials: Passkey public credentials and authenticator state
- webauthn_sessions: Short-lived, single-use ceremony state
- user_visited_lighthouses: User visit tracking (user-specific)
- user_wishlist: User wishlist management (user-specific)
- friends: Friend relationships (user-specific)
- friend_requests: Pending friend requests (user-specific)
- Public: No user relationships required for lighthouse data
- Private: One-to-many: User → Visits, User → Wishlist
- Private: Many-to-many: Users ↔ Friends (via friend relationships)
- Connection Pooling: Efficient database connections
- Query Optimization: Indexed database queries
- Map Payload Cache: Pre-warmed in-memory GeoJSON cache avoids repeated Turso queries and JSON encoding
- HTTP Delivery: Map data is gzip-compressed and uses
Cache-ControlandETagheaders
- WebGL Clustering: Both public and authenticated maps render through MapLibre GeoJSON layers instead of thousands of React DOM markers
- Lightweight Data: The map downloads only IDs and coordinates; details load after selection
- Progressive User State: Visited, wishlist, and friend data enhance the map without blocking its initial render
- Set-Based State: User lighthouse membership uses constant-time lookups and avoids rebuilding the full lighthouse collection for individual updates
- Stateless Backend: Easy to scale across multiple instances
- Database: Turso provides global distribution
- Frontend: CDN distribution via Azure Static Web Apps
- Resource Optimization: Efficient memory and CPU usage
- Database Indexing: Optimized query performance
- Caching: Reduce database load