Friday, January 10th 2025

Multi-Organization & Monorepo

Announcing the latest version of Achromatic with multi-organization support and monorepo integration, providing better project management and improved development workflows.

We’re excited to introduce multi-organization support and Turborepo in Achromatic! This update enables users to seamlessly manage and switch between multiple organizations while improving project structure and performance with Turborepo. The changes include database updates, UI refinements, business logic enhancements and a more modular architecture.

Features

1. Organization Management

  • Create, update, delete, and search organizations.
  • Upload or remove organization logos.
  • Invite and manage members within an organization.
  • Transfer ownership of an organization.
  • Identify organizations by a slug.

2. Organization Switching

  • Switch between organizations using a dropdown or menu.
  • Derive organization context from the slug.

3. UI/UX Updates

  • Updated navigation and layouts to support multi-organization views.
  • Context-aware components, data functions, and server actions.
  • A design approach similar to Linear, Campsite, and Stripe.

Key Changes

  1. New Membership Table: Tracks user roles and organization access.
  2. Auth.js Simplicity: No more organizationId in sessions; organizations derive from slugs.
  3. Organization Enhancements: Removed completedOnboarding, added slug and logo and introduced OrganizationLogo.
  4. Streamlined Onboarding: New invitation step and reduced component complexity.
  5. Sidebar Redesign: More intuitive settings layout and improved space efficiency.
  6. UI Refinements: Text adjustments for better density and readability.
  7. Improved Invitation Flow: No more "join" action; users sign in with their invited email.
  8. New replaceOrgSlug() Helper: Simplifies route construction for organizations.
  9. Organization-Specific Caching: Ensures data integrity across different organizations.
  10. Refactored Authentication & Context Handling: Removed @/lib/auth/organizations.ts, replacing it with context-based authentication.
  11. Added Turborepo support for better modularization and performance.
  12. Overhauled the auth pages with a new desig
  13. Minimized env variables (and ensured consistent naming).
  14. Improved the sidebar resize, collapse and animation state.

Context Handling

Achromatic now uses structured context retrieval for both actions and data functions to ensure seamless organization-aware workflows.

1. Actions

Example: Adding a contact with authOrganizationActionClient

apps/dashboard/actions/add-contact.ts
export const addContact = authOrganizationActionClient  .metadata({ actionName: 'addContact' })  .schema(addContactSchema)  .action(async ({ parsedInput, ctx }) => {    const user = ctx.session.user;    const organizationId = ctx.organization.id;    const memberships = ctx.organization.memberships;  });

2. Data Functions

Fetching contact details with getAuthOrganizationContext:

apps/dashboard/data/contacts/get-contact.ts
export async function getContact(input: GetContactSchema): Promise<ContactDto> {  const ctx = await getAuthOrganizationContext();  const user = ctx.session.user;  const organizationId = ctx.organization.id;}

3. Standard Authentication Context

Used outside an organization context (e.g., onboarding):

apps/dashboard/data/get-some-data.ts
export async function getSomeData(): Promise<Data> {  const ctx = await getAuthContext();  const user = ctx.session.user;}

Middleware: Automatic Slug Handling

To avoid passing organization slugs manually through components, we introduced a middleware that automatically attaches the organization slug as a request header.

apps/dashboard/middleware.ts
export function middleware(request: NextRequest) {  const pathSegments = request.nextUrl.pathname.split('/').filter(Boolean);  let slug =    pathSegments.length >= 2 && pathSegments[0] === 'organizations'      ? pathSegments[1]      : null;  const response = NextResponse.next();  if (slug) response.headers.set('x-organization-slug', slug);  return response;}export const config = { matcher: ['/organizations/:path*'] };

Provider & Hook

A new useActiveOrganization hook provides quick access to the active organization in client components.

apps/dashboard/components/client-component.tsx
'use client';export function Component(): React.JSX.Element {  const activeOrganization = useActiveOrganization();  return <>{activeOrganization.name}</>;}

Screenshots

add organization invite members organizations organization organization general settings delete organization