Files
clinicpro/.claude/skills/add-admin-endpoint/SKILL.md
T
hamed e88ae9bf9c feat: enhance ClinicDetailPage with dynamic tab management in EditModal
- Added initialTab prop to EditModal for setting the active tab on open.
- Updated state management in ClinicDetailPage to handle initial tab for editing.
- Refactored openEdit function to set the initial tab before opening the edit modal.
- Combined specialties, insurances, and services sections in the sidebar for better organization.
- Improved modal rendering using createPortal for better context handling.

style: increase z-index for modal overlay

- Updated the z-index of the overlay class in styles.css to ensure modals appear above other elements.

feat: implement multi-role dashboard functionality

- Created a new prompt for multi-role dashboard implementation.
- Defined roles and their access levels in the admin panel.
- Updated backend to support user role identification and context retrieval.
- Enhanced frontend to dynamically render components based on user roles.
- Added new routes and components for role-specific dashboards.

chore: add skills for admin endpoint and page creation

- Created SKILL.md files for adding admin endpoints and pages.
- Provided templates and guidelines for implementing new admin features.

chore: sync database after entity changes

- Added a new skill for syncing the database after any entity modifications.
2026-06-11 09:28:51 +03:30

2.9 KiB

name, description
name description
add-admin-endpoint Add a new paginated admin API endpoint to AdminApiController. Use when the user wants to add a backend admin list, stats, or action endpoint — things like "add an endpoint for X", "create an admin API for Y", "I need a route that lists Z".

Target file

src/Admin/Controller/AdminApiController.php

All admin endpoints live here. The class already has #[IsGranted('ROLE_ADMIN')] and injects EntityManagerInterface $em.

Checklist

  1. Stats endpoint (optional but standard): a separate #[Route('/api/v1/admin/{entity}/stats')] method that returns counts via raw SQL ($this->em->getConnection()->fetchOne()). Return with $this->success([...]).

  2. List endpoint: use QueryBuilder with ->getArrayResult() — never load full entities for list queries (entity getters may not exist for all fields). Pattern:

#[Route('/api/v1/admin/{entities}', methods: ['GET'])]
public function list{Entity}(Request $request): JsonResponse
{
    $page  = max(1, (int) $request->query->get('page', 1));
    $limit = min(100, max(1, (int) $request->query->get('limit', 15)));
    $search = trim((string) $request->query->get('search', ''));

    $qb = $this->em->createQueryBuilder()
        ->select('e.id, e.uuid, e.someField, e.createdAt')
        ->from(SomeEntity::class, 'e');

    if ($search !== '') {
        $qb->andWhere('e.name LIKE :s')->setParameter('s', "%$search%");
    }

    $total = (clone $qb)->select('COUNT(e.id)')->getQuery()->getSingleScalarResult();

    $items = $qb
        ->orderBy('e.id', 'DESC')
        ->setFirstResult(($page - 1) * $limit)
        ->setMaxResults($limit)
        ->getQuery()
        ->getArrayResult();

    return $this->paginated($items, (int) $total, $page, $limit);
}
  1. Action endpoints (toggle status, etc.) follow this shape:
#[Route('/api/v1/admin/{entities}/{uuid}/status', methods: ['POST'])]
public function toggle{Entity}Status(string $uuid): JsonResponse
{
    $entity = $this->em->getRepository(SomeEntity::class)->findOneBy(['uuid' => $uuid]);
    if (!$entity) return $this->error('NOT_FOUND', 'Entity not found', 404);

    $entity->setIsActive(!$entity->getIsActive());
    $this->em->flush();

    return $this->success(['is_active' => $entity->getIsActive()]);
}

Critical rules

  • Always use getArrayResult() for list queries. Never call entity getters inside admin list methods.
  • createdAt and updatedAt are Unix integer timestamps — do not format them in PHP, let the frontend handle it.
  • For JOINs to categories (city, state, specialty), use LEFT JOIN in DQL and select the name field directly into the array result.
  • Response shape for lists: $this->paginated($items, $total, $page, $limit) — frontend reads data?.data for items and data?.meta?.totalRecords for count.
  • Add use imports for any new entity class at the top of the file.
  • Run /sync-db only if a new entity or column was added as part of this change.