Skip to content

Data Configuration

Data configuration in the FiNAN website uses TypeScript interfaces to ensure consistency and catch errors at build time. All data lives in src/data/ and follows strict typing patterns.

All configuration data is organized by feature:

src/data/
├── representation/
│ └── committee/
│ ├── types.ts # TypeScript interfaces
│ ├── finlandCommittee.ts # Finland committee data
│ ├── swedenCommittee.ts # Sweden committee data
│ ├── norwayCommittee.ts # Norway committee data
│ ├── denmarkCommittee.ts # Denmark committee data
│ ├── icelandCommittee.ts # Iceland committee data
│ ├── faroe-islandsCommittee.ts # Faroe Islands committee data
│ ├── greenlandCommittee.ts # Greenland committee data
│ └── aland-islandsCommittee.ts # Åland Islands committee data
├── faqData.ts # FAQ questions and answers
└── siteConfig.ts # Site-wide SEO and metadata

Types are defined in dedicated types.ts files to ensure consistency across all data files.

The committee type system is defined in src/data/representation/committee/types.ts:

import type { ImageMetadata } from 'astro';
/**
* Represents a single committee member
*/
export interface CommitteeMember {
/** Full name of the committee member */
name: string;
/** Position/role in the committee (e.g., "President", "Secretary") */
position: string;
/** Imported image metadata for the member's photo */
photo: ImageMetadata;
/** Country this member represents */
country: string;
/** Optional contact email (not displayed publicly by default) */
email?: string;
}
/**
* Complete committee data for a country
*/
export interface CommitteeData {
/** Array of committee members */
members: CommitteeMember[];
/** Year the committee was established */
established: string;
/** Brief description of the committee's mission */
description: string;
}

FAQ data structure (typically inline in faqData.ts):

export interface FAQItem {
question: string;
answer: string;
category?: 'membership' | 'events' | 'general';
}
export interface FAQData {
items: FAQItem[];
}

Site-wide configuration (in siteConfig.ts):

export interface SiteConfig {
siteName: string;
siteUrl: string;
description: string;
author: string;
ogImage?: string;
twitterHandle?: string;
}

Here’s how to create a committee data file following the Finland example (the best practice):

  1. Import the type definition

    import type { CommitteeData } from './types';
  2. Import committee member photos

    import photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';
    import photoJaneSmith from '@/assets/images/committee/finland/jane-smith.jpg';
  3. Create and export the committee data

    export const finlandCommittee: CommitteeData = {
    members: [
    {
    name: 'John Doe',
    position: 'President',
    photo: photoJohnDoe,
    country: 'Finland',
    email: 'john.doe@example.com',
    },
    {
    name: 'Jane Smith',
    position: 'Secretary',
    photo: photoJaneSmith,
    country: 'Finland',
    },
    ],
    established: '2015',
    description: 'Supporting Filipino nurses across Finland since 2015.',
    };
  4. Type safety catches errors

    TypeScript will error if:

    • Required fields are missing (name, position, photo, country)
    • Fields have wrong types (e.g., photo is a string instead of ImageMetadata)
    • Extra fields are added that aren’t in the interface
src/data/representation/committee/finlandCommittee.ts
import type { CommitteeData } from './types';
// Import member photos
import photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';
import photoJaneSmith from '@/assets/images/committee/finland/jane-smith.jpg';
import photoMikeJohnson from '@/assets/images/committee/finland/mike-johnson.jpg';
/**
* Finland committee member data
* Updated: January 2026
*/
export const finlandCommittee: CommitteeData = {
members: [
{
name: 'John Doe',
position: 'President',
photo: photoJohnDoe,
country: 'Finland',
email: 'john.doe@finan-finland.org',
},
{
name: 'Jane Smith',
position: 'Vice President',
photo: photoJaneSmith,
country: 'Finland',
email: 'jane.smith@finan-finland.org',
},
{
name: 'Mike Johnson',
position: 'Secretary',
photo: photoMikeJohnson,
country: 'Finland',
},
],
established: '2015',
description:
'The Finland chapter of FiNAN supports Filipino nurses throughout Finland with professional development, networking, and advocacy.',
};

If you’re a content editor adding or updating committee members, follow this simplified guide:

  1. Find the correct file

    Navigate to src/data/representation/committee/ and open the file for your country (e.g., finlandCommittee.ts).

  2. Add member photos to assets

    Place photos in src/assets/images/committee/[country]/ with kebab-case names:

    • ✅ Good: john-doe.jpg, jane-smith.jpg
    • ❌ Bad: John Doe.jpg, jane_smith.png, JohnDoe.jpeg
  3. Import the photo

    At the top of the file, add:

    import photoNewMember from '@/assets/images/committee/finland/new-member.jpg';
  4. Add member to the array

    Add a new member object in the members array:

    {
    name: 'New Member',
    position: 'Treasurer',
    photo: photoNewMember,
    country: 'Finland',
    email: 'new.member@example.com', // Optional
    },
  5. Save and test

    Run pnpm build to check for errors. If the build succeeds, your changes are correct!

FAQ data is stored in src/data/faqData.ts:

src/data/faqData.ts
export interface FAQItem {
question: string;
answer: string;
category?: 'membership' | 'events' | 'general';
}
export const faqData: FAQItem[] = [
{
question: 'How do I become a member?',
answer:
'You can apply for membership by filling out the form on our Membership page. Membership is open to all Filipino nurses working in the Nordic region.',
category: 'membership',
},
{
question: 'When is the next FiNAN event?',
answer:
'Check our Events page for the latest information on upcoming conferences, webinars, and networking events.',
category: 'events',
},
// Add more FAQ items...
];
  1. Open src/data/faqData.ts

  2. Add a new item to the array:

    {
    question: 'Your question here?',
    answer: 'Your detailed answer here.',
    category: 'membership', // or 'events' or 'general'
    },
  3. Save and run pnpm build to validate

Site-wide settings are stored in src/data/siteConfig.ts:

src/data/siteConfig.ts
export interface SiteConfig {
siteName: string;
siteUrl: string;
description: string;
author: string;
ogImage?: string;
twitterHandle?: string;
}
export const siteConfig: SiteConfig = {
siteName: 'FiNAN',
siteUrl: 'https://finan.org',
description:
'Filipino Nurses Association in the Nordic Region - Supporting Filipino nurses across the Nordics',
author: 'FiNAN',
ogImage: '/images/og-image.jpg',
twitterHandle: '@finan_nordic',
};

Errors are caught before deployment:

// ❌ This will fail at build time
export const finlandCommittee: CommitteeData = {
members: [
{
name: 'John Doe',
// Missing required 'position' field - TypeScript error!
photo: photoJohnDoe,
country: 'Finland',
},
],
established: '2015',
description: 'Supporting Filipino nurses in Finland',
};

Your code editor will autocomplete field names and show documentation:

IntelliSense example

If you change a type definition, TypeScript will show all affected files:

// Change the type definition
export interface CommitteeMember {
name: string;
position: string;
photo: ImageMetadata;
country: string;
email?: string;
phoneNumber?: string; // New optional field
}
// TypeScript will NOT error on existing files because it's optional
// But you can add it to any member if needed

Types serve as inline documentation:

export interface CommitteeMember {
/** Full name of the committee member */
name: string;
/** Position/role in the committee (e.g., "President", "Secretary") */
position: string;
// ... more fields
}

Use ? for optional fields:

export interface CommitteeMember {
name: string; // Required
email?: string; // Optional
}

Types can reference other types:

export interface Address {
street: string;
city: string;
country: string;
}
export interface CommitteeMember {
name: string;
address: Address; // Nested type
}

Restrict values to specific options:

export interface FAQItem {
question: string;
answer: string;
category?: 'membership' | 'events' | 'general'; // Only these values allowed
}

Error message:

Type '{ name: string; photo: ImageMetadata; country: string; }' is missing the following properties from type 'CommitteeMember': position

Solution: Add the missing position field to the member object.

Error message:

Cannot find module '@/assets/images/committee/finland/john-doe.jpg'

Solution:

  1. Check that the image file exists at the specified path
  2. Verify the file extension matches (.jpg vs .jpeg vs .png)
  3. Ensure the path starts with @/assets/

Error message:

Type 'string' is not assignable to type 'ImageMetadata'

Solution: You’re passing a string instead of an imported image. Import the image first:

// ❌ Wrong
photo: '/images/john-doe.jpg'
// ✅ Correct
import photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';
// ...
photo: photoJohnDoe

Asset Management

Learn where to place images and how they’re optimized

View Guide →

Committee Management

Complete guide for adding and updating committee members

View Guide →

Creating Components

Learn how components consume this typed data

View Guide →