Skip to content

Conversation

jjchen01
Copy link
Collaborator

@jjchen01 jjchen01 commented Sep 24, 2025

  • One organization for the entire platform.
  • Initialize the organization on startup.
  • Add an administrator on startup (ORGANIZATION_ADMIN_EMAIL).
  • The administrator can send invitations to add other administrators.
  • End-users can manage their own API keys within their projects.

// set DEFAULT_ORGANIZATION
organization.DEFAULT_ORGANIZATION = orgEntity

email := environment_variables.EnvironmentVariables.ORGANIZATION_ADMIN_EMAIL
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy with admin's email

Comment on lines 80 to 84
err = s.organizationService.AddMember(ctx, &organization.OrganizationMember{
UserID: user.ID,
UserID: admin.ID,
OrganizationID: orgEntity.ID,
Role: organization.OrganizationMemberRoleOwner,
IsPrimary: true,
})
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add member -> update role on conflict.

Comment on lines +129 to +132
_, ok = auth.GetAdminOrganizationMemberFromContext(reqCtx)
if !ok {
projectFilter.MemberID = &user.ID
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

admin can view all projects.
end-users can view projects if they are on the project member list.

authService *auth.AuthService
}

func (d *DataInitializer) Install(ctx context.Context) error {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add data on startup.

@locnguyen1986
Copy link
Contributor

Can users be members of more than 2 organizations? as I understand, users is tightly with one organization now. As the auth service returns default organization now

}
}

var DEFAULT_ORGANIZATION *Organization
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that thread safe :|

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, definitely not, but it will be loaded only when the server starts.
Let me try using the mechanism once.

return nil, nil
}
if len(projectEntities) != 1 {
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should return specific errors "cannot greater than 1"

Copy link
Collaborator Author

@jjchen01 jjchen01 Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindOne(ctx context.Context, filter ProjectFilter) (*Project, error)

  • returns a pointer to indicate the possibility of no records found.

In the usecase would be simple to understand like:

if err != nil {
   // it must be internal error
   return
}

if project == nil {
   create a project here
}

instead of

import a specific error from somewhere
if err != nil {
   if !errors.Is(err, recordNotFoundErr) {
      create ...
   } else {
       abort and return
   }
}

WDYT?

string(organization.OrganizationMemberRoleReader): true,
}

func (s *AuthService) getOrganizationMember(reqCtx *gin.Context) (*organization.OrganizationMember, bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be GetDefaultOrganizationMember

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a private function for internal use, but I understand your point.
-> getDefaultOrganizationMember

return membership, true
}

func (s *AuthService) OrganizationMemberOptionalMiddleware() gin.HandlerFunc {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, with default

if len(memberEntities) == 0 {
return nil, nil
}
if len(memberEntities) != 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should introduce new error here

})
return
}
if exists != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should check Name is change or not before update, We won't update user every login

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a trade-off: if we add fields to the user, it's harder to notice that we need to add the new field comparison here.

Copy link
Contributor

@locnguyen1986 locnguyen1986 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's go

@jjchen01
Copy link
Collaborator Author

Can users be members of more than 2 organizations? as I understand, users is tightly with one organization now. As the auth service returns default organization now

I just want to keep the organization table for now, as we may change the design.
(OpenAI allows users to create multiple organizations.)

@jjchen01 jjchen01 merged commit 908be5d into main Sep 24, 2025
1 check passed
@jjchen01 jjchen01 deleted the feat/platform-for-organization branch September 24, 2025 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants