Files
probo/contrib/claude/gid.md
Bryan Frimin ab52dc0a34 Clean agent rules
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-19 11:42:50 +02:00

85 lines
2.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GID — Global Identifiers (`pkg/gid`)
Every entity ID in the system is a 24-byte tenant-scoped GID, serialized as base64url in the database, JSON, and API surfaces.
## GID layout (24 bytes / 192 bits)
| Bytes | Size | Content |
|-------|------|---------|
| 0–7 | 8 bytes | Tenant ID |
| 8–9 | 2 bytes | Entity type (`uint16`) |
| 10–17 | 8 bytes | Timestamp (milliseconds since epoch) |
| 18–23 | 6 bytes | Random data |
## Creating a GID
GIDs are created in the **service layer** (e.g. `pkg/probo/*_service.go`), not in coredata `Insert` methods. The entity type constant comes from `pkg/coredata/entity_type_reg.go`:
```go
assetID := gid.New(s.svc.scope.GetTenantID(), coredata.AssetEntityType)
asset := &coredata.Asset{
ID: assetID,
OrganizationID: req.OrganizationID,
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
}
err := asset.Insert(ctx, conn, s.svc.scope)
```
`gid.New` panics on random source failure (should never happen). Use `gid.NewGID` if you need the error.
## Extracting fields
```go
id.TenantID() // TenantID (first 8 bytes)
id.EntityType() // uint16 (bytes 8–9)
id.Timestamp() // time.Time (bytes 10–17)
```
## Parsing and serialization
- `gid.ParseGID(encoded)` — base64url string to GID
- `gid.String()` — GID to base64url string
- Implements `sql.Scanner`, `driver.Valuer`, `MarshalText`, `UnmarshalText`
- `gid.Nil` — zero-value GID
## TenantID
`TenantID` is an 8-byte type with its own layout:
| Bytes | Size | Content |
|-------|------|---------|
| 0–2 | 3 bytes | Machine ID (random per process) |
| 3–5 | 3 bytes | Timestamp (truncated Unix seconds) |
| 6–7 | 2 bytes | Atomic counter |
Create with `gid.NewTenantID()`. Check with `tenantID.IsValid()` (non-nil). Same serialization interfaces as GID (base64url, SQL scanner/valuer).
## Entity type registry
All entity type constants live in `pkg/coredata/entity_type_reg.go` as sequential `uint16` values:
```go
const (
OrganizationEntityType uint16 = 0
FrameworkEntityType uint16 = 1
MeasureEntityType uint16 = 2
// ...
_ uint16 = 8 // PeopleEntityType - removed
// ...
)
```
**Never reuse removed type numbers.** Use `_` placeholders with a comment noting what was removed. New types get the next available number.
`NewEntityFromID(id gid.GID) (any, bool)` switches on `id.EntityType()` and returns a pointer to the concrete coredata struct with `ID: id` set, or `nil, false` for unknown types. Add a case here when registering a new entity type.
## New entity checklist (GID-related steps)
1. Add `FooEntityType uint16 = N` in the `const` block in `entity_type_reg.go` (next sequential number)
2. Add a `case FooEntityType` in `NewEntityFromID` returning `&Foo{ID: id}, true`
3. In the service `Create` method, call `gid.New(scope.GetTenantID(), coredata.FooEntityType)` to generate the ID before `Insert`