@company-manager/docs

API Reference

Documentation complète de l'API de Company Manager.

API Reference

Documentation complète de l'API REST et tRPC de Company Manager.

API REST

Authentication

// POST /api/auth/login
interface LoginRequest {
  email: string;
  password: string;
}

interface LoginResponse {
  token: string;
  user: {
    id: string;
    email: string;
    role: string;
  };
}

// POST /api/auth/refresh
interface RefreshRequest {
  refreshToken: string;
}

interface RefreshResponse {
  token: string;
  refreshToken: string;
}

Users

// GET /api/users
interface GetUsersQuery {
  page?: number;
  limit?: number;
  search?: string;
  role?: string;
}

interface GetUsersResponse {
  data: User[];
  total: number;
  page: number;
  pageSize: number;
}

// POST /api/users
interface CreateUserRequest {
  email: string;
  name: string;
  role: string;
  tenantId: string;
}

// PUT /api/users/:id
interface UpdateUserRequest {
  name?: string;
  role?: string;
  status?: 'active' | 'inactive';
}

Orders

// GET /api/orders
interface GetOrdersQuery {
  page?: number;
  limit?: number;
  status?: OrderStatus;
  customerId?: string;
  startDate?: string;
  endDate?: string;
}

interface GetOrdersResponse {
  data: Order[];
  total: number;
  page: number;
  pageSize: number;
}

// POST /api/orders
interface CreateOrderRequest {
  customerId: string;
  items: {
    productId: string;
    quantity: number;
    price: number;
  }[];
  shipping: {
    address: string;
    method: string;
  };
  billing: {
    address: string;
    method: string;
  };
}

// PUT /api/orders/:id
interface UpdateOrderRequest {
  status?: OrderStatus;
  shipping?: Partial<ShippingInfo>;
  billing?: Partial<BillingInfo>;
}

API tRPC

Configuration

// server/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import { Context } from './context';

const t = initTRPC.context<Context>().create({
  errorFormatter({ shape, error }) {
    return {
      ...shape,
      data: {
        ...shape.data,
        zodError:
          error.code === 'BAD_REQUEST' &&
          error.cause instanceof ZodError
            ? error.cause.flatten()
            : null,
      },
    };
  },
});

export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);

Routers

Users Router

// server/routers/users.ts
export const usersRouter = router({
  list: protectedProcedure
    .input(
      z.object({
        page: z.number().optional(),
        limit: z.number().optional(),
        search: z.string().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const users = await ctx.prisma.user.findMany({
        where: {
          tenantId: ctx.tenant.id,
          OR: input.search
            ? [
                { name: { contains: input.search } },
                { email: { contains: input.search } },
              ]
            : undefined,
        },
        take: input.limit,
        skip: input.page * input.limit,
      });

      return users;
    }),

  create: protectedProcedure
    .input(createUserSchema)
    .mutation(async ({ ctx, input }) => {
      return ctx.prisma.user.create({
        data: {
          ...input,
          tenantId: ctx.tenant.id,
        },
      });
    }),
});

Orders Router

// server/routers/orders.ts
export const ordersRouter = router({
  list: protectedProcedure
    .input(
      z.object({
        page: z.number().optional(),
        limit: z.number().optional(),
        status: z.enum(['draft', 'pending', 'completed']).optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const orders = await ctx.prisma.order.findMany({
        where: {
          tenantId: ctx.tenant.id,
          status: input.status,
        },
        include: {
          customer: true,
          items: true,
        },
        take: input.limit,
        skip: input.page * input.limit,
      });

      return orders;
    }),

  create: protectedProcedure
    .input(createOrderSchema)
    .mutation(async ({ ctx, input }) => {
      return ctx.prisma.order.create({
        data: {
          ...input,
          tenantId: ctx.tenant.id,
          status: 'draft',
        },
      });
    }),
});

Middleware

Authentication

// server/middleware/auth.ts
const isAuthed = t.middleware(async ({ ctx, next }) => {
  if (!ctx.user) {
    throw new TRPCError({
      code: 'UNAUTHORIZED',
      message: 'Not authenticated',
    });
  }
  return next({
    ctx: {
      user: ctx.user,
    },
  });
});

Tenant

// server/middleware/tenant.ts
const withTenant = t.middleware(async ({ ctx, next }) => {
  const tenantId = ctx.headers['x-tenant-id'];
  if (!tenantId) {
    throw new TRPCError({
      code: 'BAD_REQUEST',
      message: 'Tenant ID required',
    });
  }

  const tenant = await ctx.prisma.tenant.findUnique({
    where: { id: tenantId },
  });

  if (!tenant) {
    throw new TRPCError({
      code: 'NOT_FOUND',
      message: 'Tenant not found',
    });
  }

  return next({
    ctx: {
      ...ctx,
      tenant,
    },
  });
});

Utilisation Client

Configuration

// utils/trpc.ts
import { createTRPCNext } from '@trpc/next';
import { httpBatchLink, loggerLink } from '@trpc/client';
import type { AppRouter } from '../server/routers/_app';

export const trpc = createTRPCNext<AppRouter>({
  config() {
    return {
      links: [
        loggerLink(),
        httpBatchLink({
          url: '/api/trpc',
          headers() {
            return {
              'x-tenant-id': getTenantId(),
            };
          },
        }),
      ],
    };
  },
  ssr: false,
});

Hooks

// Exemple d'utilisation
const UserList = () => {
  const { data, isLoading } = trpc.users.list.useQuery({
    page: 0,
    limit: 10,
  });

  const { mutate: createUser } = trpc.users.create.useMutation({
    onSuccess: () => {
      // Invalidation du cache
      utils.users.list.invalidate();
    },
  });

  return (
    <div>
      {data?.map(user => (
        <UserCard key={user.id} user={user} />
      ))}
    </div>
  );
};

Bonnes Pratiques

Sécurité

  1. Validation des entrées avec Zod
  2. Authentification et autorisation systématiques
  3. Rate limiting et protection CSRF
  4. Sanitization des données

Performance

  1. Pagination et filtrage côté serveur
  2. Mise en cache appropriée
  3. Optimisation des requêtes N+1
  4. Batch requests avec tRPC

Maintenance

  1. Versioning de l'API
  2. Documentation OpenAPI/Swagger
  3. Tests d'intégration
  4. Monitoring des erreurs