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
| Property | Value |
|---|---|
| Package | @internal/plugin-homepage-gcp-projects-backend |
| Type | Backend |
| Plugin ID | homepage-gcp-projects |
| Database | PostgreSQL via Knex |
| Integration | GCP Cloud Billing, Resource Manager, BigQuery |
Architecture
API Endpoints
Project Operations
| Method | Endpoint | Description |
|---|---|---|
| GET | /projects | Get user's projects |
| GET | /projects/by-group/:groupRef | Get projects for group |
| POST | /projects | Add new project |
| DELETE | /projects/:id | Delete entire project |
| DELETE | /projects/:id/groups/:groupRef | Remove from group |
| GET | /autocomplete | Search existing projects |
| GET | /user-groups | Get user's groups |
Billing Operations
| Method | Endpoint | Description |
|---|---|---|
| GET | /billing/:projectId | Get billing for project |
| POST | /billing/batch | Get billing for multiple |
Organization Operations
| Method | Endpoint | Description |
|---|---|---|
| GET | /organizations | List organizations |
| GET | /organizations/:orgId/projects | List projects in org |
Database Schema
homepage_gcp_projects
| Column | Type | Description |
|---|---|---|
| id | UUID | Primary key |
| project_id | VARCHAR | GCP Project ID |
| name | VARCHAR | Display name |
| description | TEXT | Optional description |
| group_refs | JSONB | Array of group refs |
| created_by | VARCHAR | Creator user reference |
| created_at | TIMESTAMP | Creation time |
| updated_at | TIMESTAMP | Last 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
Related Documentation
- Homepage Links Frontend - Frontend plugin
- Homepage Repos Backend - Repository management
- Plugins Overview