Skip to content

Implement Users service, proto definition, and bootstrap integration #1

@rowan-stein

Description

@rowan-stein

User Request

Implement the Users service according to the specification in agynio/architecture/architecture/users.md, following new service standards. Add it to bootstrap.

Update: Replaced nickname with email in the user model.

Specification

Scope

This issue covers three deliverables:

  1. Proto definition — Add proto/agynio/api/users/v1/users.proto to agynio/api
  2. Service implementation — Full agynio/users repo following agynio/teams patterns
  3. Bootstrap integration — Register users service + PostgreSQL in agynio/bootstrap

1. Proto Definition (agynio/api)

Add proto/agynio/api/users/v1/users.proto:

  • Package: agynio.api.users.v1
  • Go package: github.com/agynio/api/gen/agynio/api/users/v1;usersv1
  • Service: UsersService with 5 RPCs:
    • ResolveOrCreateUser — Upsert by OIDC subject, returns User + created bool
    • GetUser — Lookup by identity_id
    • GetUserByOIDCSubject — Lookup by OIDC subject
    • BatchGetUsers — Batch lookup by identity IDs (max 100, silent omission for missing)
    • UpdateUser — Partial update of profile fields (name, email, photo_url)
  • Messages: EntityMeta, User, request/response pairs for each RPC

User Model

Field Type Description
identity_id string (UUID) Platform identity identifier
oidc_subject string Subject claim from the OIDC ID token. Unique
name string Display name
email string User email address
photo_url string Profile photo URL
created_at timestamp When the user was first provisioned
updated_at timestamp Last profile update

2. Service Implementation (agynio/users)

Follow agynio/teams patterns exactly:

  • Go gRPC service with PostgreSQL backend
  • Migration (0001_init.sql): users table with identity_id UUID PK, unique oidc_subject index
  • Store layer: ResolveOrCreateUser (select-then-insert with unique violation retry), GetUser, GetUserByOIDCSubject, BatchGetUsers (ANY query), UpdateUser
  • Server layer: gRPC handlers with validation, status code mapping
  • Identity service call: TODO stub — generate identity_id locally (Identity service not implemented yet)
  • Dockerfile: Multi-arch, buf generate, same pattern as teams
  • Helm chart: charts/users/ with service-base dependency
  • DevSpace config: dev mode, watch mode, e2e test pipeline
  • CI workflows: ci.yml + release.yaml
  • E2E tests: Cover all 5 RPCs + negative paths
  • README: Standard template

3. Bootstrap Integration (agynio/bootstrap)

Add to stacks/platform/:

  • variables.tf: users_chart_version, users_image_tag, users_db_password, users_db_pvc_size
  • main.tf locals: resolved_users_image_tag, users_chart_name, users_db_values, users_values
  • main.tf resources: argocd_application.users_db (sync-wave 8), argocd_application.users (sync-wave 17)

gRPC Status Code Contract

Condition Code
Empty/invalid required fields INVALID_ARGUMENT
User not found NOT_FOUND
Batch size > 100 INVALID_ARGUMENT
Missing IDs in batch Silent omission (success)
No optional fields set on update INVALID_ARGUMENT
Internal/DB error INTERNAL

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions