Skip to main content

Homepage GCP Projects Backend Plugin

The Homepage GCP Projects Backend provides GCP project persistence with billing data integration for the homepage GCP Projects section.

Overview​

PropertyValue
Package@internal/plugin-homepage-gcp-projects-backend
TypeBackend
Plugin IDhomepage-gcp-projects
DatabasePostgreSQL via Knex
IntegrationGCP Cloud Billing, Resource Manager, BigQuery

Architecture​

API Endpoints​

Project Operations​

MethodEndpointDescription
GET/projectsGet user's projects
GET/projects/by-group/:groupRefGet projects for group
POST/projectsAdd new project
DELETE/projects/:idDelete entire project
DELETE/projects/:id/groups/:groupRefRemove from group
GET/autocompleteSearch existing projects
GET/user-groupsGet user's groups

Billing Operations​

MethodEndpointDescription
GET/billing/:projectIdGet billing for project
POST/billing/batchGet billing for multiple

Organization Operations​

MethodEndpointDescription
GET/organizationsList organizations
GET/organizations/:orgId/projectsList projects in org

Database Schema​

homepage_gcp_projects​

ColumnTypeDescription
idUUIDPrimary key
project_idVARCHARGCP Project ID
nameVARCHARDisplay name
descriptionTEXTOptional description
group_refsJSONBArray of group refs
created_byVARCHARCreator user reference
created_atTIMESTAMPCreation time
updated_atTIMESTAMPLast update time

Request/Response Schemas​

Create Project​

// POST /projects
interface CreateProjectRequest {
projectId: string; // GCP Project ID
name?: string; // Display name (defaults to projectId)
description?: string; // Optional description
groupRefs: string[]; // Groups to share with
}

// Zod schema
const createProjectSchema = z.object({
projectId: z.string().regex(/^[a-z][a-z0-9-]{4,28}[a-z0-9]$/),
name: z.string().max(255).optional(),
description: z.string().max(500).optional(),
groupRefs: z.array(z.string()).min(1),
});

Billing Response​

interface BillingInfo {
projectId: string;
billingAccountName?: string;
totalCost: number;
currency: string;
period: {
start: string;
end: string;
};
breakdown?: {
service: string;
cost: number;
}[];
}

Services​

GcpProjectStore​

interface GcpProjectStore {
getProjects(groupRefs: string[]): Promise<GcpProject[]>;
getProjectsByGroup(groupRef: string): Promise<GcpProject[]>;
createProject(
input: CreateProjectInput,
createdBy: string,
): Promise<GcpProject>;
deleteProject(id: string): Promise<void>;
removeProjectFromGroup(id: string, groupRef: string): Promise<void>;
autocomplete(query: string): Promise<GcpProject[]>;
}

BillingService​

interface BillingService {
getBilling(projectId: string, accessToken: string): Promise<BillingInfo>;
getBillingBatch(
projectIds: string[],
accessToken: string,
): Promise<BillingInfo[]>;
}

GcpOrgService​

interface GcpOrgService {
listOrganizations(accessToken: string): Promise<Organization[]>;
listProjects(orgId: string, accessToken: string): Promise<GcpProject[]>;
}

GCP Authentication​

The plugin uses user OAuth tokens for GCP API access:

Important

The X-Gcp-Access-Token header MUST be included in CORS allowedHeaders configuration. Cloud Run reserves X-Google-* headers, so we use X-Gcp-* instead.

Project ID Validation​

GCP Project IDs have specific format requirements:

const projectIdRegex = /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/;

// Valid: my-project-123
// Invalid: MyProject (uppercase)
// Invalid: 123-project (starts with number)
// Invalid: project- (ends with hyphen)
// Invalid: proj (too short)

Usage Examples​

Add GCP Project​

curl -X POST http://localhost:7007/api/homepage-gcp-projects/projects \
-H "Content-Type: application/json" \
-d '{
"projectId": "my-gcp-project",
"name": "My GCP Project",
"description": "Production workloads",
"groupRefs": ["group:default/platform-team"]
}'

Get Billing Information​

curl http://localhost:7007/api/homepage-gcp-projects/billing/my-gcp-project \
-H "X-Gcp-Access-Token: ya29.xxx..."

Response:

{
"projectId": "my-gcp-project",
"billingAccountName": "billingAccounts/xxx",
"totalCost": 1234.56,
"currency": "USD",
"period": {
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-31T23:59:59Z"
},
"breakdown": [
{ "service": "Compute Engine", "cost": 500.0 },
{ "service": "Cloud Storage", "cost": 200.0 },
{ "service": "BigQuery", "cost": 534.56 }
]
}

Batch Billing Request​

curl -X POST http://localhost:7007/api/homepage-gcp-projects/billing/batch \
-H "Content-Type: application/json" \
-H "X-Gcp-Access-Token: ya29.xxx..." \
-d '{
"projectIds": ["project-1", "project-2", "project-3"]
}'

List Organizations​

curl http://localhost:7007/api/homepage-gcp-projects/organizations \
-H "X-Gcp-Access-Token: ya29.xxx..."

BigQuery Integration​

For detailed cost analysis, the plugin can query BigQuery billing exports:

SELECT
service.description AS service,
SUM(cost) AS cost
FROM `billing_export.gcp_billing_export_v1_XXXXXX`
WHERE project.id = @projectId
AND _PARTITIONTIME >= @startDate
AND _PARTITIONTIME < @endDate
GROUP BY service.description
ORDER BY cost DESC