This Document is for Skeet v2.

Basic Architecture - Firestore

The basic structure of the Skeet Framework backend is as follows.

Features required for common backendsSkeet Framework
DatabaseFirestore
Login AuthenticationFirebase Authentication
APICloud Functions for Firebase 2nd Gen
Load BalancerCloud Load Balancer
Schedule TasksCloud Scheduler
Pub/SubCloud Pub/Sub
DomainsCloud DNS
SecurityCloud Armor

Basic Structure of Skeet Framework

Since the Skeet Framework backend is serverless, You can start writing from functions right away.

website, webapp, mobile will contain the frontend source code.

The Cloud Functions for Firebase project will be placed under the functions directory.

You can add multiple functions to functions.

bash
root ├── common ├── functions ├── mobile ├── sql ├── webapp ├── website ├── package.json ├── pnpm-workspace.yaml ├── tsconfig.json ├── skeet-cloud.config.json └── vitest.config.ts
DirectoryDescription
commonCommon source code
webappWeb application source code
websiteWebsite source code
mobileMobile application source code
functionsCloud Functions for Firebase source code
sqlSQL source code
package.jsonBackend package management
skeet-cloud.config.jsonSkeet Framework configuration file
tsconfig.jsonTypeScript configuration
vitest.config.tsVite Test configuration file
pnpm-workspace.yamlPNPM configuration file
firebase.jsonFirebase configuration file

Basic Structure of Skeet Functions

Skeet Functions are based on Cloud Functions for Firebase. The Cloud Functions for Firebase project will be placed under the functions directory. You can add multiple functions to functions.

e.g. functions/skeet-func

bash
. ├── build.ts ├── devBuild.ts ├── dist │ └── index.js ├── nodemon.json ├── package.json ├── src │ ├── index.ts │ ├── lib │ └── routings └── tsconfig.json
DirectoryDescription
build.tsBuild script
devBuild.tsDevelopment build script
distBuild output directory
nodemon.jsonNodemon configuration
package.jsonFunctions package management
srcSource code directory
src/index.tsEntry point
src/libLibrary
src/routingsRoutings
src/scriptsScripts
src/utilsUtilities
tsconfig.jsonTypeScript configuration

Instance types for Skeet Functions

Instance typeDescription
HttpFunction that receives HTTP requests
OnCallFunction that receives Callable functions
PubSubfunction that receives PubSub messages
SchedulerScheduled Functions
FirestoreFunctions that receive triggers for creating, updating, deleting, etc. documents in Firestore
AuthFunctions that receive triggers for creating, deleting, etc. users in Firebase Auth

Basic Structure of Skeet Routings

Routing settings differ depending on the instance type. Also, Cloud Functions for Firebase option settings are located under routings/options.

bash
├── auth │ ├── authOnCreateUser.ts │ └── index.ts ├── firestore │ ├── firestoreExample.ts │ └── index.ts ├── http │ ├── addUserChatRoomMessage.ts │ ├── createUserChatRoom.ts │ ├── getUserChatRoomMessages.ts │ ├── index.ts │ └── root.ts ├── onCall │ ├── onCallExample.ts │ └── index.ts ├── index.ts ├── options │ ├── authOptions.ts │ ├── firestoreOptions.ts │ ├── httpOptions.ts │ ├── index.ts │ ├── pubsubOptions.ts │ └── schedulerOptions.ts ├── pubsub │ ├── index.ts │ └── pubsubExample.ts └── scheduler ├── index.ts └── schedulerExample.ts

Http Instance Settings

Http Default Option

routings/options/http/httpOptions.ts

ts
import { HttpsOptions } from 'firebase-functions/v2/https' import skeetOptions from '../../../skeetOptions.json' const appName = skeetOptions.name const project = skeetOptions.projectId const region = skeetOptions.region const serviceAccount = `${appName}@${project}.iam.gserviceaccount.com` const vpcConnector = `${appName}-con` const cors = true export const publicHttpOption: HttpsOptions = { region, cpu: 1, memory: '1GiB', maxInstances: 100, minInstances: 0, concurrency: 1, timeoutSeconds: 540, invoker: 'public', labels: { skeet: 'http', }, } export const privateHttpOption: HttpsOptions = { region, cpu: 1, memory: '1GiB', maxInstances: 100, minInstances: 0, concurrency: 80, serviceAccount, ingressSettings: 'ALLOW_INTERNAL_AND_GCLB', vpcConnector, vpcConnectorEgressSettings: 'PRIVATE_RANGES_ONLY', cors, timeoutSeconds: 540, invoker: 'private', labels: { skeet: 'http', }, }

Define Http Instance Settings routings/http/{httpInstance}.ts

routings/http/root.ts

ts
import { onRequest } from 'firebase-functions/v2/https' import { publicHttpOption } from '@/routings/options' import { TypedRequestBody } from '@/index' import { RootParams } from '@/types/http/rootParams' export const root = onRequest( publicHttpOption, async (req: TypedRequestBody<RootParams>, res) => { try { res.json({ status: 'success', message: 'Skeet Backend is running!', name: req.body.name || 'Anonymous', }) } catch (error) { const errorLog = `root - ${error}` console.log(errorLog) res.status(500).json({ status: 'error', message: String(error) }) } } )

Define Http Instance Type src/types/http/{httpInstance}Params.ts

types/http/rootParams.ts

ts
export type RootParams = { name?: string }

PubSub Instance Settings

PubSub Default Option

routings/options/pubsub/pubsubOptions.ts

ts
import { PubSubOptions } from 'firebase-functions/v2/pubsub' import skeetOptions from '../../../skeetOptions.json' const appName = skeetOptions.name const project = skeetOptions.projectId const region = skeetOptions.region const serviceAccount = `${appName}@${project}.iam.gserviceaccount.com` const vpcConnector = `${appName}-con` export const pubsubDefaultOption = (topic: string): PubSubOptions => ({ topic, region, cpu: 1, memory: '1GiB', maxInstances: 100, minInstances: 0, concurrency: 1, serviceAccount, ingressSettings: 'ALLOW_INTERNAL_ONLY', vpcConnector, vpcConnectorEgressSettings: 'PRIVATE_RANGES_ONLY', timeoutSeconds: 540, labels: { skeet: 'pubsub', }, })

Define PubSub Instance Settings routings/pubsub/{pubsubInstance}.ts

routings/pubsub/pubsubExample.ts

ts
import { onMessagePublished } from 'firebase-functions/v2/pubsub' import { pubsubDefaultOption } from '@/routings/options' import { parsePubSubMessage } from '@/lib/pubsub' import { PubsubExampleParams } from '@/types/pubsub/pubsubExampleParams' export const pubsubTopic = 'pubsubExample' export const pubsubExample = onMessagePublished( pubsubDefaultOption(pubsubTopic), async (event) => { try { const pubsubObject = parsePubSubMessage<PubsubExampleParams>(event) console.log({ status: 'success', topic: pubsubTopic, event, pubsubObject, }) } catch (error) { console.error({ status: 'error', message: String(error) }) } } )

Define PubSub Instance Types src/types/pubsub/{pubsubInstance}Params.ts

types/pubsub/pubsubExampleParams.ts

ts
export type PubsubExampleParams = { message?: string }

Scheduler Instance Settings

Scheduler Default Option

routings/options/scheduler/schedulerOptions.ts

ts
import { ScheduleOptions } from 'firebase-functions/v2/scheduler' import skeetOptions from '../../../skeetOptions.json' const appName = skeetOptions.name const project = skeetOptions.projectId const region = skeetOptions.region const serviceAccount = `${appName}@${project}.iam.gserviceaccount.com` const vpcConnector = `${appName}-con` export const scheduleDefaultOption: ScheduleOptions = { region, schedule: 'every 1 hours', timeZone: 'UTC', retryCount: 3, maxRetrySeconds: 60, minBackoffSeconds: 1, maxBackoffSeconds: 10, serviceAccount, ingressSettings: 'ALLOW_INTERNAL_ONLY', vpcConnector, vpcConnectorEgressSettings: 'PRIVATE_RANGES_ONLY', timeoutSeconds: 540, labels: { skeet: 'schedule', }, }

Define Scheduler Instance Settingsroutings/scheduler/{schedulerInstance}.ts

routings/scheduler/schedulerExample.ts

ts
import { onSchedule } from 'firebase-functions/v2/scheduler' import { scheduleDefaultOption } from '@/routings/options' export const scheduleExample = onSchedule( scheduleDefaultOption, async (event) => { try { console.log({ status: 'success' }) } catch (error) { console.log({ status: 'error', message: String(error) }) } } )

Firestore Instance Settings1

Firestore Default Option

routings/options/firestore/firestoreOptions.ts

ts
import { DocumentOptions } from 'firebase-functions/v2/firestore' import skeetOptions from '../../../skeetOptions.json' const appName = skeetOptions.name const project = skeetOptions.projectId const region = skeetOptions.region const serviceAccount = `${appName}@${project}.iam.gserviceaccount.com` const vpcConnector = `${appName}-con` export const firestoreDefaultOption = (document: string): DocumentOptions => ({ document, region, cpu: 1, memory: '1GiB', maxInstances: 100, minInstances: 0, concurrency: 1, serviceAccount, ingressSettings: 'ALLOW_INTERNAL_ONLY', vpcConnector, vpcConnectorEgressSettings: 'PRIVATE_RANGES_ONLY', timeoutSeconds: 540, labels: { skeet: 'firestore', }, })

Define Firestore Instance Settings in routings/firestore/{firestoreInstance}

routings/firestore/firestoreExample.ts

ts
import { onDocumentCreated } from 'firebase-functions/v2/firestore' import { firestoreDefaultOption } from '@/routings/options' export const firestoreExample = onDocumentCreated( firestoreDefaultOption('User/{userId}'), (event) => { console.log('firestoreExample triggered') try { console.log(event.params) } catch (error) { console.log({ status: 'error', message: String(error) }) } } )

Cloud Firestore function triggers

Event TypeTrigger
onDocumentCreatedTriggered when a document is written to for the first time.
onDocumentDeletedTriggered when a document already exists and has any value changed.
onDocumentUpdatedTriggered when a document is deleted.
onDocumentWrittenTriggered when onDocumentCreated, onDocumentUpdated or onDocumentDeleted is triggered.

Configure Auth instance

Auth Default Option

routings/options/auth/authOptions.ts

ts
import { RuntimeOptions } from 'firebase-functions/v1' import skeetOptions from '../../../skeetOptions.json' const appName = skeetOptions.name const project = skeetOptions.projectId const serviceAccount = `${appName}@${project}.iam.gserviceaccount.com` const vpcConnector = `${appName}-con` export const authPublicOption: RuntimeOptions = { memory: '1GB', maxInstances: 100, minInstances: 0, timeoutSeconds: 300, labels: { skeet: 'auth', }, } export const authPrivateOption: RuntimeOptions = { memory: '1GB', maxInstances: 100, minInstances: 0, timeoutSeconds: 300, serviceAccount, ingressSettings: 'ALLOW_INTERNAL_ONLY', vpcConnector, vpcConnectorEgressSettings: 'PRIVATE_RANGES_ONLY', labels: { skeet: 'auth', }, }

In the Auth instance's default function, When a Firebase user is created, Create user documentation.

Auth instance settings are described in routings/auth/auth{MethoName}.ts.

routings/auth/authOnCreateUser.ts

ts
import { User } from '@/models' import { addCollectionItem } from '@skeet-framework/firestore' import * as functions from 'firebase-functions/v1' import { authPublicOption } from '@/routings' import { gravatarIconUrl } from '@/utils/placeholder' import skeetConfig from '../../../skeetOptions.json' const region = skeetConfig.region export const authOnCreateUser = functions .runWith(authPublicOption) .region(region) .auth.user() .onCreate(async (user) => { try { const { uid, email, displayName, photoURL } = user const userParams = { uid, email: email || '', username: displayName || email?.split('@')[0] || '', iconUrl: photoURL == '' || !photoURL ? gravatarIconUrl(email ?? '[email protected]') : photoURL, } const userRef = await addCollectionItem<User>('User', userParams, uid) console.log({ status: 'success', userRef }) } catch (error) { console.log({ status: 'error', message: String(error) }) } })

Firebase user registration/login in Dev environment

In the Dev environment, For Firebase user registration and login, Use the skeet login command.

Run Skeet App in Dev environment

bash
$ skeet s

Open a new terminal and run the skeet login command.

bash
$ skeet login

画像

Firebase user registration and Firestore user registration are completed.

ACCESS_TOKEN is stored in the local environment variable.

Model definition

Define Models

common/models/{modelName}Models.ts

Or use the skeet ai command to automatically generate the Firestore data model.

bash
$ skeet ai --mode ? 🤖 Select Mode prisma typedoc ❯ firestore function method 🔥 Firestore Model Generating Mode 🔥 ? Please describe your Firestore use case. e.g. I want to create a blog app. You:

For type-safe development with Firestore, Skeet Framework uses the Firestore Data Converter.

The NoSQL data model is so flexible that Model definition is not required, but

for each model

  • CollectionId
  • DocumentId

is recommended to be described as a comment. Increased readability,

In addition, code completion in CodePilot will work.

models/userModels.ts

ts
import { Ref, Timestamp } from '@skeet-framework/firestore' // CollectionId: User // DocumentId: auto // Path: User export const UserCN = 'User' export const genUserPath = () => `${UserCN}` export type User = { id?: string uid: string username: string email: string iconUrl: string userChatRoomIds?: string[] createdAt?: Timestamp | FieldValue updatedAt?: Timestamp | FieldValue }

To Add/Get/Query/Remove Data,

install

@skeet-framework/firestore

ts
import { add, get } from '@skeet-framework/firestore'

Skeet CLI

Skeet CLI is a command line tool for Skeet Framework.

Command List

bash
Usage: skeet [options] [command] CLI for Skeet - Full-stack TypeScript Serverless framework Options: -V, --version output the version number -h, --help display help for command Commands: create [options] <appName> Create Skeet Framework App server|s [options] Run Skeet App deploy [options] Deploy Skeet APP to Firebase init [options] Initialize Google Cloud Setups login Skeet Login Command - Create Firebase Login Token curl [options] <methodName> Skeet Curl Command - Call Firebase Functions Endpoint g|generate Skeet Generate Comannd log [options] Deploy Skeet APP to Firebase docker Docker commands db Database commands iam Skeet IAM Comannd to setup Google Cloud Platform add Skeet Add Comannd to add new functions sync Skeet Sync Comannd to sync backend and frontend delete|d Skeet Delete Command get Get Skeet App List ai [options] Call Skeet AI Assistant config Config commands run [options] Run commands new|n [options] Create Skeet Framework App console|c Call Firebase Console to Test Functions check Check Cloud Configurations test Run tests help [command] display help for command