Hiking-Logbook

Module Interactions - Sprint 1

This document explains how different parts of the Hiking Logbook system interact with each other for Sprint 1, focusing on user authentication and basic user profile storage.

Sprint 1 Scope

What’s Included:

What’s NOT Included (Future Sprints):

System Architecture

High-Level Architecture

┌─────────────────┐    HTTP/HTTPS    ┌─────────────────┐
│   Frontend      │ ◄──────────────► │    Backend      │
│   (React)       │                  │  (Express.js)   │
└─────────────────┘                  └─────────────────┘
         │                                     │
         │                                     │
         │ Firebase SDK                        │ Firebase Admin SDK
         │                                     │
         ▼                                     ▼
┌─────────────────┐                  ┌─────────────────┐
│  Firebase Auth  │                  │ Firebase Admin  │
│  (Client SDK)   │                  │   (Server SDK)  │
└─────────────────┘                  └─────────────────┘
         │                                     │
         │                                     │
         └─────────────┬───────────────────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Firebase        │
              │ Firestore       │
              │ (Database)      │
              └─────────────────┘

Module Responsibilities

Frontend (React)

Backend (Express.js)

Database (Firebase Firestore)

Authentication (Firebase Auth)

Data Flow Diagrams

User Signup Flow

1. User Signup Process

sequenceDiagram
    participant U as User
    participant F as Frontend
    participant B as Backend
    participant FA as Firebase Auth
    participant DB as Firestore

    U->>F: Fill signup form
    F->>B: POST /auth/signup
    B->>FA: Create user account
    FA-->>B: User created (UID)
    B->>DB: Create user profile
    DB-->>B: Profile saved
    B-->>F: Success response + UID
    F-->>U: Show success message

2. User Profile Retrieval

sequenceDiagram
    participant U as User
    participant F as Frontend
    participant B as Backend
    participant DB as Firestore

    U->>F: Navigate to profile
    F->>B: GET /users/:uid
    B->>DB: Query user profile
    DB-->>B: Profile data
    B-->>F: User profile data
    F->>F: Update UI with profile
    F-->>U: Display profile information

API Interactions

Authentication Endpoints

POST /auth/signup

Purpose: Create new user account and profile

Frontend Request:

const response = await fetch("/auth/signup", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "user@example.com",
    password: "password123",
    displayName: "John Doe",
    bio: "Hiking enthusiast",
  }),
});

Backend Processing:

// 1. Validate input data
// 2. Create user in Firebase Auth
// 3. Create profile in Firestore
// 4. Return success response

Response Handling:

if (response.ok) {
  const data = await response.json();
  // Handle success - redirect to profile or dashboard
} else {
  // Handle error - show error message
}

User Management Endpoints

GET /users/:uid

Purpose: Retrieve user profile by UID

Frontend Request:

const response = await fetch(`/users/${uid}`);

Backend Processing:

// 1. Validate UID parameter
// 2. Query Firestore for user profile
// 3. Return profile data or error

Response Handling:

if (response.ok) {
  const profile = await response.json();
  // Update UI with profile data
} else {
  // Handle error - user not found, etc.
}

Error Handling

Common Error Scenarios

1. Validation Errors (400)

{
  "error": "Validation failed",
  "details": "Email is required"
}

2. User Already Exists (409)

{
  "error": "User already exists"
}

3. User Not Found (404)

{
  "error": "User not found"
}

4. Server Errors (500)

{
  "error": "Internal server error"
}

Frontend Error Handling

try {
  const response = await fetch("/auth/signup", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(userData),
  });

  if (!response.ok) {
    const errorData = await response.json();
    throw new Error(errorData.error);
  }

  // Handle success
} catch (error) {
  // Display error message to user
  setError(error.message);
}

State Management

Authentication State

Frontend State Structure

const [authState, setAuthState] = useState({
  isAuthenticated: false,
  user: null,
  loading: false,
  error: null,
});

State Updates

// After successful signup
setAuthState({
  isAuthenticated: true,
  user: { uid: response.uid, email: userData.email },
  loading: false,
  error: null,
});

// After error
setAuthState((prev) => ({
  ...prev,
  loading: false,
  error: error.message,
}));

Form State Management

const [formData, setFormData] = useState({
  email: "",
  password: "",
  displayName: "",
  bio: "",
});

const handleInputChange = (e) => {
  setFormData({
    ...formData,
    [e.target.name]: e.target.value,
  });
};

Security Considerations

Input Validation

Frontend Validation

const validateForm = () => {
  const errors = [];

  if (!email || !isValidEmail(email)) {
    errors.push("Valid email is required");
  }

  if (!password || password.length < 8) {
    errors.push("Password must be at least 8 characters");
  }

  if (!displayName || displayName.length < 2) {
    errors.push("Display name must be at least 2 characters");
  }

  return errors;
};

Backend Validation

const validateSignupData = (data) => {
  const errors = [];

  if (!data.email || !isValidEmail(data.email)) {
    errors.push("Valid email is required");
  }

  if (!data.password || data.password.length < 8) {
    errors.push("Password must be at least 8 characters");
  }

  if (!data.displayName || data.displayName.length < 2) {
    errors.push("Display name must be at least 2 characters");
  }

  return errors;
};

Firebase Security Rules

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null &&
        request.auth.uid == userId;
    }
  }
}

Performance Considerations

Database Operations

Frontend Optimization

Testing Strategy

Frontend Testing

// Test signup form submission
test("should submit signup form with valid data", async () => {
  render(<SignupForm />);

  fireEvent.change(screen.getByLabelText(/email/i), {
    target: { value: "test@example.com" },
  });

  fireEvent.click(screen.getByRole("button", { name: /sign up/i }));

  await waitFor(() => {
    expect(screen.getByText(/success/i)).toBeInTheDocument();
  });
});

Backend Testing

// Test signup endpoint
test("POST /auth/signup should create new user", async () => {
  const userData = {
    email: "test@example.com",
    password: "password123",
    displayName: "Test User",
  };

  const response = await request(app).post("/auth/signup").send(userData);

  expect(response.status).toBe(201);
  expect(response.body).toHaveProperty("uid");
});

Future Enhancements (Post-Sprint 1)

Planned Module Interactions

Architecture Evolution

Troubleshooting

Common Issues

1. CORS Errors

// Backend CORS configuration
app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
);

2. Firebase Connection Issues

// Check Firebase configuration
const serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

3. Port Conflicts

Debug Tools


*This module interactions document covers Sprint 1 only - user authentication and basic profile storage.