Package Exports
- @jobsearch-works/firestore-models
- @jobsearch-works/firestore-models/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@jobsearch-works/firestore-models) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
firestore-models
A shared library for standardizing Firestore document schemas and paths across multiple projects. This library provides:
- Standardized document models and interfaces
- Consistent path builders for Firestore collections and documents
- Type-safe access to Firestore data
- Shared validation and transformation utilities
Purpose
This library serves as a single source of truth for Firestore data structures across different applications. By centralizing the schema definitions, it:
- Ensures consistency in data structure across projects
- Reduces duplication of model definitions
- Provides type safety when working with Firestore data
- Makes it easier to maintain and update schemas across all applications
Installation
npm install @jsw/firestore-models
# or
yarn add @jsw/firestore-modelsProject Structure
firestore-models/
├── src/
│ ├── models/ # All Firestore models
│ │ ├── Application.ts
│ │ ├── AuthUser.ts
│ │ ├── Client.ts
│ │ ├── ClientData.ts
│ │ ├── ClientLogin.ts
│ │ ├── Question.ts
│ │ ├── UserQuestion.ts
│ │ ├── Vacancy.ts
│ │ └── VacancySuggestion.ts
│ ├── BaseModel.ts # Base interface for all models
│ └── index.ts # Main entry point
├── dist/ # Compiled output
└── package.jsonBase Model
All models extend from the BaseModel interface:
interface BaseModel {
id?: string; // Optional document ID
createdAt?: Date | string; // Optional creation timestamp
updatedAt?: Date | string; // Optional update timestamp
}Models and Namespaces
Each model is defined within its own namespace, which includes:
- The model interface
- Path builders for Firestore collections and documents
- Utility functions for working with the model
Client
namespace Client {
interface Model extends BaseModel {
name: string;
email: string;
status: "active" | "inactive";
resume?: string;
}
// Path builders
const collection = () => "clients";
const document = (clientId: string) => `clients/${clientId}`;
// Utility functions
const formatClient = (client: Client.Model): string;
const createNew = (name: string, email: string): Client.Model;
}Application
namespace Application {
interface Model extends BaseModel {
vacancyId: string;
clientId: string;
status:
| "new"
| "submitted"
| "interviewing"
| "accepted"
| "rejected"
| "withdrawn"
| "applying"
| "suggested"
| "approved";
coverLetter?: string;
resume?: string;
// Denormalized fields from Vacancy
company?: string;
position?: string;
location?: string;
jobId?: string;
advertisingUrl?: string;
applicationUrl?: string;
applicationDomain?: string;
advertisingDomain?: string;
description?: string;
fullPageText?: string;
}
// Path builders
const collection = (clientId: string) => `clients/${clientId}/applications`;
const document = (clientId: string, applicationId: string) =>
`clients/${clientId}/applications/${applicationId}`;
// Utility functions
const formatSummary = (application: Application.Model): string;
const formatDate = (date: Date | string): string;
const createNew = (
clientId: string,
vacancyId: string,
vacancyData: Partial<Vacancy.Model>
): Application.Model;
const updateStatus = (
application: Application.Model,
newStatus: Application.Model["status"]
): Application.Model;
}AuthUser
namespace AuthUser {
interface Model extends BaseModel {
email: string;
displayName?: string;
photoURL?: string;
lastSignIn?: Date | string;
emailVerified?: boolean;
}
// Path builders
const collection = () => "users";
const document = (userId: string) => `users/${userId}`;
// Utility functions
const fromFirebaseUser = (user: any): AuthUser.Model;
const formatDates = (user: AuthUser.Model): Record<string, string>;
const toFirestore = (user: AuthUser.Model): Record<string, any>;
const fromFirestore = (data: Record<string, any>): AuthUser.Model;
}Vacancy
namespace Vacancy {
interface Model extends BaseModel {
company: string;
position: string;
location: string;
jobId: string;
advertisingUrl: string;
applicationUrl: string;
applicationDomain: string;
advertisingDomain: string;
description: string;
fullPageText: string;
status: "active" | "inactive";
}
// Path builders
const collection = () => "vacancies";
const document = (vacancyId: string) => `vacancies/${vacancyId}`;
}Question
namespace Question {
interface Model extends BaseModel {
text: string;
type: "text" | "multiple_choice" | "single_choice";
options?: string[];
required: boolean;
order: number;
}
// Path builders
const collection = () => "questions";
const document = (questionId: string) => `questions/${questionId}`;
}UserQuestion
namespace UserQuestion {
interface Model extends BaseModel {
clientId: string;
questionId: string;
answer: string;
}
// Path builders
const collection = (clientId: string) => `clients/${clientId}/questions`;
const document = (clientId: string, questionId: string) =>
`clients/${clientId}/questions/${questionId}`;
}ClientData
namespace ClientData {
interface Model extends BaseModel {
clientId: string;
key: string;
value: any;
}
// Path builders
const collection = (clientId: string) => `clients/${clientId}/data`;
const document = (clientId: string, key: string) =>
`clients/${clientId}/data/${key}`;
}ClientLogin
namespace ClientLogin {
interface Model extends BaseModel {
clientId: string;
ipAddress: string;
userAgent: string;
}
// Path builders
const collection = (clientId: string) => `clients/${clientId}/logins`;
const document = (clientId: string, loginId: string) =>
`clients/${clientId}/logins/${loginId}`;
}VacancySuggestion
namespace VacancySuggestion {
interface Model extends BaseModel {
clientId: string;
vacancyId: string;
status: "pending" | "accepted" | "rejected";
}
// Path builders
const collection = (clientId: string) => `clients/${clientId}/suggestions`;
const document = (clientId: string, suggestionId: string) =>
`clients/${clientId}/suggestions/${suggestionId}`;
}Services
For data access, use the provided services instead of directly accessing Firestore. Services provide a consistent interface for data operations and handle error cases.
ClientDataService
import { ClientDataService } from "@jobsearch-works/services";
// Get client data
const clientData = await ClientDataService.getData(userId);Usage
Import the models and services in your application:
import { Client } from "@jsw/firestore-models";
import { ClientDataService } from "@jobsearch-works/services";
// Create a new client
const newClient = Client.createNew("John Doe", "john@example.com");
// Use services for data access
const clientData = await ClientDataService.getData("123");
// Use the utility functions
const formattedClient = Client.formatClient(newClient);Contributing
When adding new models or modifying existing ones:
- Update the TypeScript interfaces
- Add corresponding path builders
- Update any validation or transformation utilities
- Update this documentation
- Ensure backward compatibility when possible
License
MIT