Skip to content

Lokal utviklingsmiljø

Denne guiden viser hvordan du setter opp et komplett lokalt utviklingsmiljø for GolfChart med Firebase Emulator Suite.

Forutsetninger

Prosjektstruktur

GolfChartAppV0.9/
├── admin/                  # Admin UI (React + Vite)
│   ├── src/
│   ├── package.json
│   └── vite.config.ts
├── functions/              # Cloud Functions (Node + TypeScript)
│   ├── src/
│   ├── package.json
│   └── tsconfig.json
├── public/                 # Public UI (eksisterende app)
├── docs/                   # MkDocs dokumentasjon
├── firebase.json           # Firebase config
├── firestore.rules         # Security rules
├── firestore.indexes.json  # Firestore indekser
└── mkdocs.yml              # Dokumentasjon config

Installasjon

1. Klon repository

git clone https://github.com/yourusername/golfchart.git
cd golfchart

2. Installer dependencies

Root og Functions:

# Installer Firebase Functions dependencies
cd functions
pnpm install
cd ..

Admin UI:

cd admin
pnpm install
cd ..

3. Konfigurer miljøvariabler

Admin UI (.env.local):

# admin/.env.local
VITE_FIREBASE_API_KEY=din-api-key
VITE_FIREBASE_AUTH_DOMAIN=golfbilkontroll-skigk.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=golfbilkontroll-skigk
VITE_FIREBASE_STORAGE_BUCKET=golfbilkontroll-skigk.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=123456789
VITE_FIREBASE_APP_ID=1:123456789:web:abc123
VITE_USE_EMULATOR=true

Functions (.env):

# functions/.env
SENDGRID_API_KEY=test-key-for-local
TWILIO_AUTH_TOKEN=test-token-for-local
GEMINI_API_KEY=test-gemini-key

Tips: For lokal utvikling kan du bruke dummy-verdier for eksterne API-nøkler.

Firebase Emulator Suite

Starte emulatorer

firebase emulators:start

Dette starter:

  • 🔥 Firestorelocalhost:8080
  • 🔐 Authlocalhost:9099
  • Functionslocalhost:5001
  • 📦 Storagelocalhost:9199
  • 🎛️ Emulator UIlocalhost:4000

Emulator UI

Åpne http://localhost:4000 for å:

  • Se Firestore data
  • Administrere Auth brukere
  • Inspisere Function logs
  • Teste Storage filer

Importere testdata

Opprett seed-data for utvikling:

# functions/src/seed.ts
import * as admin from 'firebase-admin';

admin.initializeApp();
const db = admin.firestore();

async function seed() {
  // Opprett testklubb
  await db.doc('clubs/ski-gk').set({
    name: 'Ski Golfklubb',
    slug: 'ski-gk',
    active: true,
    contact: {
      email: 'test@skigk.no',
      phone: '+47 12345678'
    },
    timezone: 'Europe/Oslo',
    createdAt: admin.firestore.FieldValue.serverTimestamp(),
    updatedAt: admin.firestore.FieldValue.serverTimestamp()
  });

  // Opprett prisregler
  await db.collection('pricingRules').add({
    clubId: 'ski-gk',
    holes18: { member: 350, nonMember: 425 },
    holes9: { member: 200, nonMember: 250 },
    doctorsNoteDiscount: 50,
    effectiveFrom: admin.firestore.Timestamp.now(),
    effectiveTo: null
  });

  // Opprett 3 carts
  for (let i = 1; i <= 3; i++) {
    await db.collection('carts').add({
      clubId: 'ski-gk',
      status: 'available',
      label: `Bil ${i}`,
      serial: `GOLF-2023-00${i}`,
      notes: '',
      currentRentalId: null,
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
      updatedAt: admin.firestore.FieldValue.serverTimestamp()
    });
  }

  console.log('✅ Seed data created');
}

seed().catch(console.error);

Kjør seeding:

cd functions
npx ts-node src/seed.ts

Utviklingsworkflow

Fyll med mock-data (Firestore)

⚠️ VIKTIG: Denne seeden skriver til PRODUKSJON Firestore (ikke emulator).

Se SEEDING_GUIDE.md i rot-katalog for detaljert dokumentasjon.

Kort versjon:

1) Sørg for at du er autentisert:

firebase login
firebase use golfbilkontroll-skigk

2) Kjør seeden fra functions-mappen:

cd functions
npx ts-node src/seed.ts

3) Verifiser i Firebase Console eller admin-appen at data er opprettet.

1. Start alle tjenester

Terminal 1 (Emulatorer):

firebase emulators:start

Terminal 2 (Admin UI dev server):

cd admin
pnpm dev

Admin UI er nå tilgjengelig på http://localhost:5173

Terminal 3 (Functions watch - valgfritt):

cd functions
pnpm build --watch

2. Administrere testbrukere

Opprett en testbruker via Emulator UI eller via Firebase CLI:

firebase auth:import users.json --project golfbilkontroll-skigk

users.json:

{
  "users": [
    {
      "localId": "test-admin-123",
      "email": "admin@skigk.no",
      "passwordHash": "...",
      "displayName": "Test Admin",
      "customClaims": "{\"role\":\"clubAdmin\",\"clubs\":[\"ski-gk\"]}"
    }
  ]
}

Eller opprett manuelt i Emulator UI (http://localhost:4000/auth) med en enkel passord-autentisering.

3. Hot reload

  • Admin UI: Vite hot-reloader ved filendringer
  • Functions: Emulator restarter automatisk ved endringer i build-output
  • Firestore Rules: Deploy med firebase deploy --only firestore:rules

4. Debugging

Frontend (Chrome DevTools):

// admin/src/firebase.ts
import { connectFirestoreEmulator } from 'firebase/firestore';
import { connectAuthEmulator } from 'firebase/auth';

if (import.meta.env.VITE_USE_EMULATOR === 'true') {
  connectFirestoreEmulator(db, 'localhost', 8080);
  connectAuthEmulator(auth, 'http://localhost:9099');
  console.log('🔧 Using Firebase Emulators');
}

Functions (VS Code debugger):

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Functions",
      "port": 9229,
      "restart": true,
      "sourceMaps": true,
      "outFiles": ["${workspaceFolder}/functions/lib/**/*.js"]
    }
  ]
}

Start emulators med inspect:

firebase emulators:start --inspect-functions

Testing

Unit tests (Admin UI)

cd admin
pnpm test

Eksempel test:

// admin/src/components/__tests__/CartCard.test.tsx
import { render, screen } from '@testing-library/react';
import { CartCard } from '../CartCard';

test('viser cart status', () => {
  render(<CartCard cart={{ label: 'Bil 1', status: 'available' }} />);
  expect(screen.getByText('Bil 1')).toBeInTheDocument();
  expect(screen.getByText('Tilgjengelig')).toBeInTheDocument();
});

Security Rules tests

cd functions
pnpm test:rules

Eksempel test:

// tests/firestore-rules.test.ts
import { assertFails, assertSucceeds } from '@firebase/rules-unit-testing';

test('klubbadmin kan lese egne klubber', async () => {
  const db = testEnv.authenticatedContext('user123', {
    role: 'clubAdmin',
    clubs: ['ski-gk']
  }).firestore();

  await assertSucceeds(
    db.collection('rentals').where('clubId', '==', 'ski-gk').get()
  );
});

Integration tests (Functions)

cd functions
pnpm test:integration

Dokumentasjon (MkDocs)

Installere MkDocs

pip install mkdocs-material mkdocs-git-revision-date-localized-plugin

Kjøre docs lokalt

mkdocs serve

Dokumentasjon er tilgjengelig på http://localhost:8000

Bygge docs

mkdocs build

Genererer statiske filer i site/ som kan deployes til GitHub Pages eller Firebase Hosting.

Feilsøking

Problem: Firestore emulator starter ikke

Løsning: Sjekk at port 8080 ikke er i bruk:

netstat -ano | findstr :8080

Kill prosess eller endre port i firebase.json:

{
  "emulators": {
    "firestore": {
      "port": 8081
    }
  }
}

Problem: Auth emulator har ingen brukere

Løsning: Opprett manuelt i Emulator UI (http://localhost:4000/auth) eller importer users.json.

Problem: Functions kan ikke nå Firestore

Løsning: Sørg for at Functions bruker emulator:

// functions/src/index.ts (for testing)
if (process.env.FUNCTIONS_EMULATOR) {
  process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';
}

Problem: CORS-feil i Admin UI

Løsning: Legg til CORS i Functions:

// functions/src/index.ts
import { onCall } from 'firebase-functions/v2/https';

export const myFunction = onCall(
  { cors: ['http://localhost:5173'] },
  async (data, context) => {
    // ...
  }
);

Neste steg