Files
alla-allaos-fullstack/AGENTS.md
phaichayon 7a390cf0df init
2026-06-11 12:46:57 +07:00

12 KiB

AGENTS.md - AI Coding Agent Reference

This file provides project-specific guidance for AI coding agents working in this repository. It reflects the current architecture and migration status of the codebase.


Project Overview

This project is a Next.js admin dashboard starter that is being migrated from template scaffolding to an app-owned architecture.

Current core stack:

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript 5.7
  • UI: shadcn/ui + Tailwind CSS v4
  • Authentication: Auth.js
  • Persistence: PostgreSQL + Drizzle ORM
  • Data Fetching: TanStack React Query
  • URL State: nuqs
  • Forms: TanStack Form + Zod
  • Charts: Recharts
  • Monitoring: Sentry
  • Package Manager: Bun preferred, npm acceptable

Current migration status:

  • Auth has been moved to Auth.js
  • Multi-tenant data now uses app-owned users, organizations, and memberships
  • products has been migrated to Route Handlers + Drizzle
  • users has been migrated to Route Handlers + Drizzle
  • RBAC now uses a global users.system_role plus organization-scoped memberships.role
  • self-service sign-up is disabled; accounts must be created by an admin
  • some legacy pages still exist as placeholders or transitional seams

Technology Stack Details

Core Runtime

  • Next.js 16.x with App Router
  • React 19.x
  • TypeScript strict mode

Styling & UI

  • Tailwind CSS v4
  • shadcn/ui components
  • CSS custom properties and theme registry

State Management

  • Zustand for local UI state
  • nuqs for URL search params
  • TanStack Form + Zod for forms

Data Fetching

  • TanStack React Query for server state
  • server prefetch with HydrationBoundary + dehydrate
  • useSuspenseQuery() for client consumption of prefetched data

Authentication & Authorization

  • Auth.js for authentication
  • app-owned organizations and memberships for multi-tenant access
  • global system role stored on users.system_role
  • organization role and permissions stored on memberships
  • client-side nav filtering is UX-only; real protection must be server-side

Persistence & APIs

  • PostgreSQL + Drizzle ORM
  • Route Handlers under src/app/api/** are the main server boundary
  • feature services call those route handlers through src/lib/api-client.ts
  • mock APIs remain only as legacy migration seams

Current Auth Model

The current auth model is app-owned and centered around:

  • users
  • organizations
  • memberships

Important files:

  • src/auth.ts - Auth.js config and exported helpers
  • src/lib/auth/session.ts - shared server-side auth helpers
  • src/proxy.ts - route protection
  • src/db/schema.ts - current database schema

Current behavior:

  • authentication uses an Auth.js Credentials provider
  • passwords are verified against users.password_hash
  • global RBAC uses users.system_role with super_admin | user
  • organization RBAC uses memberships.role with admin | user
  • the user row stores active_organization_id
  • session enrichment loads organization and membership data on each request
  • self-service sign-up is disabled
  • initial super admin bootstrap is done with the seed script, not through the UI

Preferred server-side helpers:

  • requireSession()
  • requireSystemRole()
  • requireOrganizationAccess(options?)

Do not introduce new Clerk usage.


Project Structure

/src
├── app/                    # Next.js App Router
│   ├── auth/               # Auth pages
│   ├── dashboard/          # Dashboard routes
│   ├── api/                # Route handlers
│   ├── layout.tsx          # Root layout
│   └── page.tsx            # Landing / redirect entry
│
├── components/
│   ├── ui/                 # shadcn/ui and app UI primitives
│   ├── layout/             # Sidebar, header, providers
│   ├── forms/              # Form field wrappers
│   ├── themes/             # Theme system
│   └── icons.tsx           # Single icon registry
│
├── db/
│   └── schema.ts           # Drizzle schema
│
├── features/
│   ├── auth/
│   ├── overview/
│   ├── products/           # Migrated: React Query + Route Handlers + Drizzle
│   ├── users/              # Migrated: React Query + Route Handlers + Drizzle + RBAC
│   ├── react-query-demo/
│   ├── kanban/
│   ├── chat/
│   ├── notifications/
│   └── profile/
│
├── config/
│   └── nav-config.ts
│
├── hooks/
│   ├── use-nav.ts
│   └── use-data-table.ts
│
├── lib/
│   ├── api-client.ts
│   ├── auth/
│   ├── db.ts
│   ├── query-client.ts
│   └── searchparams.ts
│
├── styles/
└── types/

Relevant docs/plans:

  • plans/req.md
  • plans/implementation-plan.md
  • docs/themes.md
  • docs/nav-rbac.md
  • docs/clerk_setup.md is legacy historical reference only

Build & Development Commands

# Install dependencies
bun install
# or
npm install

# Development server
bun run dev
# or
npm run dev

# Build
bun run build
# or
npm run build

# Start
bun run start
# or
npm run start

# Lint
bun run lint
# or
npm run lint

# Format
bun run format
# or
npm run format

Environment Configuration

Copy env.example.txt to .env.local and configure:

Required

AUTH_SECRET=your-long-random-secret
DATABASE_URL=postgres://postgres:postgres@localhost:5432/training_system
SUPER_ADMIN_EMAIL=admin@example.com
SUPER_ADMIN_PASSWORD=change-this-password

Optional for Sentry

NEXT_PUBLIC_SENTRY_DSN=https://...@....ingest.sentry.io/...
NEXT_PUBLIC_SENTRY_ORG=your-org
NEXT_PUBLIC_SENTRY_PROJECT=your-project
SENTRY_AUTH_TOKEN=sntrys_...
NEXT_PUBLIC_SENTRY_DISABLED="false"

Notes:

  • keep auth and database secrets server-only
  • OAuth providers can be added later through Auth.js
  • billing is currently modeled as app-owned organization plan data, not a live provider integration
  • run npm run setup:db on first setup to apply migrations and seed the initial super admin

Code Style Guidelines

TypeScript

  • strict mode enabled
  • use explicit return types for public functions when useful
  • prefer interface for object contracts
  • use @/* imports from src

Component Conventions

  • use function declarations for components
  • server components by default
  • add 'use client' only when needed
  • use cn() for className merging

Forms

  • use TanStack Form via useAppForm from @/components/ui/tanstack-form
  • use Zod for submit validation
  • avoid useState inside AppField render props

Buttons

  • use <Button isLoading={isPending}> for loading states

Navigation & RBAC

Navigation is configured in src/config/nav-config.ts.

Current access properties:

  • systemRole
  • requireOrg
  • permission
  • role
  • plan
  • feature

Notes:

  • systemRole is for global access such as super_admin
  • requireOrg remains a compatibility seam and means the user must have an active organization
  • nav filtering in src/hooks/use-nav.ts uses Auth.js session data
  • server routes and server pages must enforce real access independently

Authentication Patterns

Protected Routes

Dashboard routes are protected through src/proxy.ts.

Example protected page:

import { auth } from '@/auth';
import { redirect } from 'next/navigation';

export default async function Page() {
  const session = await auth();

  if (!session?.user) {
    redirect('/auth/sign-in');
  }

  if (!session.user.activeOrganizationId) {
    redirect('/dashboard/workspaces');
  }

  return <div>Protected</div>;
}

Shared Server Helpers

Prefer:

  • requireSession()
  • requireSystemRole()
  • requireOrganizationAccess(options?)

Plan / Feature Gating

Do not use vendor-specific gating components.

Read plan or feature state from app-owned organization data and enforce it server-side.


Data Fetching Patterns

Service Layer Architecture

Each feature should use:

src/features/<name>/api/
  types.ts
  service.ts
  queries.ts
  mutations.ts   # when mutations exist

Rules:

  • components import types from types.ts
  • components call query options from queries.ts
  • services call local route handlers through apiClient
  • route handlers talk to Drizzle / database

Backend Patterns

Preferred patterns in this repo:

Pattern Guidance
Route Handlers + ORM Preferred for app-owned features
Server Actions + ORM Acceptable when it fits the feature well
BFF Acceptable when proxying to an external backend
Mock Legacy only, not the preferred path

React Query

Preferred pattern for new pages:

  1. define query options in queries.ts
  2. prefetch in the server page
  3. hydrate with HydrationBoundary
  4. read with useSuspenseQuery()

URL State

Use nuqs for table search params and list filters.

Tables

Use:

  • TanStack Table
  • React Query
  • useDataTable
  • column definitions under the feature component tree

Current Migration Guidance

Use the migrated products feature as the main reference for new CRUD work.

Important current status:

  • products is migrated to Auth.js + Route Handlers + Drizzle
  • users is migrated to Auth.js + Route Handlers + Drizzle
  • new features should follow the products and users pattern, not the old mock pattern

Legacy seams still present:

  • src/constants/mock-api.ts
  • src/constants/mock-api-users.ts
  • some placeholder pages under workspaces, billing, profile, and exclusive sections

Treat those as migration seams, not target architecture.


Deployment Notes

Production Requirements

Ensure these are set:

  • AUTH_SECRET
  • DATABASE_URL
  • SUPER_ADMIN_EMAIL
  • SUPER_ADMIN_PASSWORD
  • relevant SENTRY_* variables if using Sentry

Build Considerations

  • app builds as standalone
  • database migrations must be applied before runtime
  • production secrets must not be exposed as NEXT_PUBLIC_*

Troubleshooting

Auth fails in development

  • verify AUTH_SECRET
  • verify DATABASE_URL
  • verify migrations are applied
  • verify the super admin seed has run and seeded users have valid password_hash

Theme not applying

  • verify theme CSS import in src/styles/theme.css
  • verify theme registration in theme.config.ts

Navigation items not showing

  • check access in nav-config.ts
  • verify session has active organization, role, or permissions as needed

Feature data looks stale

  • verify mutation invalidates the feature query key factory
  • verify filters are included in the query key

External Documentation


Notes for AI Agents

  1. Always use cn() for className merging.
  2. Respect the feature-based structure and keep new work inside src/features/.
  3. Server components are the default.
  4. Avoid any; keep contracts explicit.
  5. Use PageContainer for page headers instead of importing Heading directly in pages.
  6. Use TanStack Form + Zod via the existing project wrappers.
  7. Use icons only through @/components/icons.
  8. For new app-owned features, prefer Route Handlers + Drizzle + React Query.
  9. Never import from @/constants/mock-api* directly in components.
  10. Use @/auth and src/lib/auth/session.ts for auth and organization checks.
  11. Do not introduce new Clerk usage.
  12. Treat legacy mock-backed modules as migration seams.
  13. Follow the migrated products and users feature patterns when building new CRUD modules.
  14. Do not re-enable self-service sign-up unless the product requirement changes explicitly.