## Key Principles
- **Code Quality & Style**
- Write concise, maintainable, and strongly typed code with accurate TypeScript implementations.
- Embrace functional, declarative programming. Avoid OOP and classes.
- Limit files to a maximum of 150 lines; refactor into smaller modules if exceeded.
- Prefer iteration and modularization over duplication.
- Use descriptive, semantic variable names with auxiliary verbs (e.g., `isLoading`, `hasError`).
- Use lowercase with dashes for directories and files (e.g., `components/auth-wizard`).
- Favor named exports for components.
- Adopt RORO (Receive an Object, Return an Object) for function parameters/returns.
- Always attain to use DRY (Don't Repeat Yourself) principles.
- Conduct regular code reviews and frequent refactoring sessions to ensure consistency and quality.
- Check and improve Web Vitals (LCP, CLS, FID) to maintain performance and user experience.
- **Create 'Build Notes':**
- You must create a 'Build Notes' file for each task group to track the progress of the task group we work on.
- **Clarity & Brevity:** Keep notes concise, direct, and focused on the task at hand.
- **Logical Naming:** Use a consistent naming convention that ties each notes file to a specific task and date.
- **Incremental Updates:** Update notes as plans evolve or tasks are completed. Append rather than overwrite.
- **Traceability:** Ensure that each decision or change in approach is recorded and easy to follow.
- **Review 'Project Contexts':**
- You must review the `projectContext.md` as we need to ensure that the project context is up to date and accurate.
- **Stability:** Treat context files as stable references, not daily scratchpads.
- **Selective Updates:** Update context files only when there are significant, approved changes to requirements or project scope.
- **Accessibility:** Make context files easily understandable and organized so future developers can quickly grasp the project's core guidance.
- **Stack and Framework Conventions**
- Target **Next.js 15+** and leverage the App Router, React Server Components (RSC), and SSR capabilities.
- Use Zustand for state management in client components when necessary.
- Maintain proper Shadcn UI management using `npx shadcn@latest add` for new components.
- Follow a mobile-first approach and responsive design patterns.
- Emphasize server-side logic, minimizing the usage of `use client` and other client-only APIs.
- Structure project as Progressive Web App (PWA) with offline capabilities, app-like experience, and installability across devices.
- **Monorepo & Tooling**
- If using a monorepo structure, place shared code in a `packages/` directory and app-specific code in `app/`.
- Use `Taskfile.yml` commands for development, testing, and deployment tasks.
- Keep environment variables and sensitive data outside of code and access them through `.env` files or similar configuration.
Below is a structured guideline to provide to the AI development agent, incorporating key principles and detailed rules for maintaining the `/ProjectDocs/Build_Notes/` and `/ProjectDocs/contexts/` directories.
---
### Rules for Build Notes Files
1. **Location & Naming:**
- Store all notes files in `/ProjectDocs/Build_Notes/`.
- Use a logical, descriptive naming convention, e.g., `build-title_phase-#_task-group-name.md`.
- Use the `<build-title>` to describe the build task.
- Use the `<phase-#>` to apply the Phase # to the build task.
- Use the `<task-group-name>` to describe the task group name.
- Example: `supabase-schema-standardization_phase-1_preparation-and-code-analysis.md`
- `supabase-schema-standardization` is the build title
- `phase-1` is the phase number
- `preparation-and-code-analysis` is the task group name
2. **Content Structure:**
- Begin with a brief **Task Objective** that summarizes what you aim to achieve.
- Provide **Current State Assessment**: a short description of the current state of the project pertaining to the build tasks.
- Provide **Future State Goal**: a short description of the future state of the project pertaining to the build tasks.
- Follow with a **Implementation Plan**: a numbered list of **steps** containing checklist **tasks** to achieve the future state.
- Update the **Implementation Plan** as tasks are completed and line out not applicable tasks. NEVER DELETE TASKS FROM THE PLAN.
- If the plan changes or evolves, add new **steps** or **tasks**, rather than overwriting previous content.
3. **When to Update:**
- **At Task Start:** Create or open the task-specific notes file and record the initial plan before coding.
- **During Task Execution:** Add updates when plans change, difficulties arise, or new insights emerge.
- **At Task Completion:** Append a summary of what was done and verify it aligns with the original objective.
4. **Style & Tone:**
- Keep notes succinct, on-topic, and free of unrelated commentary.
- Maintain a logical sequence so that future readers can understand the decision-making process without confusion.
5. **Completion of Build Notes:**
- Once the build notes are complete, move the file to the `/ProjectDocs/Build_Notes/completed/` directory.
- If build notes are deprecated and no longer needed, move the file to the `/ProjectDocs/Build_Notes/archived/` directory.
---
### Rules for Context Files
1. **Master Project Context (`projectContext.md`):**
- Located in `/ProjectDocs/contexts/`.
- Provides the overarching project scope, requirements, and design principles.
- Only update this file if there are major changes to the project's fundamental direction or scope.
2. **Additional Context Files:**
- Supplementary files (e.g., `uiContext.md`, `featureAContext.md`) may be created for more detailed specifications on certain functionalities, designs, or areas of the application.
- Keep these files stable. Update them only when new, approved changes need to be documented.
- Reference these files frequently to ensure development aligns with established guidelines.
3. **Change Management:**
- Record any changes to context files within the corresponding build notes file for that task.
- Maintain a clear rationale for context changes to preserve transparency and alignment with the core project goals.
---
## Project Structure
Adopt a clear, modular directory structure:
```
├── app/
│ ├── (auth)/ # Auth-related routes/pages
│ ├── (dashboard)/ # Dashboard routes/pages
│ ├── api/ # API routes
│ └── layout.tsx # Root layout
├── components/
│ ├── shared/ # Shared, reusable UI components
│ │ ├── buttons/
│ │ ├── forms/
│ │ └── layout/
│ ├── features/ # Feature-specific components
│ │ ├── auth/
│ │ └── dashboard/
│ └── ui/ # Shadcn UI components
├── lib/
│ ├── supabase/ # Supabase client and utilities
│ │ ├── current/ # Current schema and types
│ │ └── domain/ # Domain-specific schema and types
│ │ ├── user/ # User domain schema and types
│ │ │ ├── index.ts # Exports all supabase utilities
│ │ │ ├── queries.ts # Supabase queries
│ │ │ ├── services.ts # Supabase services
│ │ │ └── types.ts # Supabase types
│ │ ├── roles/ # Roles domain schema and types
│ │ └── ... # Add more domains as needed
│ ├── constants/ # Global constants and configuration
│ │ ├── auth/ # Authentication constants
│ │ └── ui/ # UI constants
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth/ # Authentication hooks
│ │ └── useUI/ # UI hooks
│ ├── middleware/ # Custom middleware
│ │ ├── auth/ # Authentication middleware
│ │ ├── rbac/ # Role-based access control middleware
│ │ └── ui/ # UI middleware
│ └── utils/ # Shared utility functions
├── public/ # Static assets
├── services/ # Business logic and data-fetching services
├── types/ # Global TypeScript types and interfaces
└── config/ # Configuration files (env, tailwind, etc.)
```
**Naming & Organization:**
- Use semantic, descriptive names.
- Keep file names lowercase with dashes.
- Use `feature/`, `bugfix/`, `hotfix/`, `refactor/`, `docs/` prefixes for branches.
- Export from `index.ts` files in feature directories for cleaner imports.
---
## JavaScript/TypeScript Standards
- Use TypeScript everywhere. Prefer `interface` for public-facing contracts.
- Use `function` keyword for defining components and pure functions (avoid arrow functions for components).
- Omit semicolons for a cleaner look.
- Maintain a logical file order:
1. Exported component
2. Subcomponents
3. Helpers/internal utilities
4. Static content/constants
5. Types and interfaces at the bottom
- Write concise conditionals:
- Avoid unnecessary braces in single-line conditionals.
- Use early returns to handle edge cases and errors upfront.
- Model expected errors as return values instead of using exceptions in server actions.
Example:
```typescript
function formatInput({ input }: { input: string }) {
if (!input) return null
return input.trim()
}
```
---
## Error Handling, Validation, and Services
- Handle errors at the start of functions with guard clauses and early returns.
- Keep the "happy path" visible at the bottom of the function.
- Avoid `else` statements by using if-return patterns to reduce nesting.
- Use Zod for schema validation and form validation.
- Use `react-hook-form` with `useActionState` to manage form state and submission flows.
- In `services/` directories, always throw user-friendly errors that can be caught upstream and displayed to the user.
- Implement proper error logging and user-friendly messages.
- Employ error boundaries (`error.tsx`, `global-error.tsx`) for unexpected errors.
- Use `next-safe-action` for secure and type-safe server actions.
---
## AI Integration
- Use the Vercel AI SDK UI and Core to implement streaming chat and AI-driven features.
- Handle rate limiting, quota, and model availability gracefully.
- Implement fallback logic if AI models are unavailable.
- Sanitize user inputs before sending them to the AI.
- Store API keys and sensitive information in environment variables.
- Provide clear, user-friendly error messages in case of AI service failures.
---
## React/Next.js Component Development
- **Functional Components**: Use function declarations and TypeScript interfaces for props.
- **Minimal Props & Composition**: Keep components small, focused, and composed of reusable subcomponents.
- **Server Components First**: Prefer React Server Components and SSR data fetching to minimize client overhead.
- **Zustand for State**: Use Zustand for complex local state if necessary, ensuring minimal `use client` usage.
- **Client Components**: Only use `use client` for components that require browser APIs or local user interaction.
- **Responsive Design**: Use Tailwind CSS utility classes, with a mobile-first approach.
- **UI Libraries**: Use Shadcn UI and Radix UI for base components and interactions.
- **Static Content & Types**: Place static text, constants, and types at the end of each file.
- **Dynamic Loading**: Dynamically import non-critical components to improve initial load times.
- **Optimize Images**: Use WebP format, appropriate sizing, and lazy loading for images.
---
## Supabase, Database, and GraphQL
- Fetch latest Supabase documentation from https://supabase.com/docs/reference/javascript;
- **Schema Management**: Keep migrations folder under `supabase/migrations` updated with remote changes.
- **Types Management**: Keep `database.types.ts` updated regularly with the latest schema changes.
- **Migrations**: Use Supabase CLI for local development and database migrations. Test all changes before staging/production.
- **RLS & RBAC**: Implement Row Level Security and role-based access control. Assign default roles in `handle_new_user` functions.
- **CRUD-based Policies**: Follow INSERT, UPDATE, SELECT, DELETE policies and document them.
- **Enum Tables**: Use enum tables for predefined values.
- **Relationships**: Document all table relationships and data flows.
- **Genql**: Use Genql for type-safe GraphQL queries against Supabase. Fetch only necessary data.
Example user creation:
```typescript
async function handleNewUser({ userId, email }: { userId: string; email: string }) {
const defaultRole = await getDefaultRole()
await supabase.from('profiles').insert({
id: userId,
email,
role_id: defaultRole.id,
created_at: new Date().toISOString(),
})
}
```
### Follow Supabase's guidelines for using the `@supabase/ssr` package and Server-Side Auth. Specifically, there should be:
- A utility function to create a client on the client side
- A utility function create a client on the server side, using the Next.js `cookies` API to access the cookies. Use the latest version of the API, where `cookies` must be awaited.
- A utility function to handle refreshing the user session in middleware.
## Working with cookies
Use the latest version of `@supabase/ssr`, where cookie options are defined with the `getAll` and `setAll` functions, like so:
```
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
```
No other cookie options should be provided.
## Middleware
The middleware should use the following `updateSession` function:
```
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// IMPORTANT: Avoid writing any logic between createServerClient and
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
// issues with users being randomly logged out.
const {
data: { user },
} = await supabase.auth.getUser()
if (
!user &&
!request.nextUrl.pathname.startsWith('/login') &&
!request.nextUrl.pathname.startsWith('/auth')
) {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone()
url.pathname = '/login'
return NextResponse.redirect(url)
}
// IMPORTANT: You *must* return the supabaseResponse object as it is. If you're
// creating a new response object with NextResponse.next() make sure to:
// 1. Pass the request in it, like so:
// const myNewResponse = NextResponse.next({ request })
// 2. Copy over the cookies, like so:
// myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
// 3. Change the myNewResponse object to fit your needs, but avoid changing
// the cookies!
// 4. Finally:
// return myNewResponse
// If this is not done, you may be causing the browser and server to go out
// of sync and terminate the user's session prematurely!
return supabaseResponse
}
```
### Postgres SQL Style Guide
## General
- Use lowercase for SQL reserved words to maintain consistency and readability.
- Employ consistent, descriptive identifiers for tables, columns, and other database objects.
- Use white space and indentation to enhance the readability of your code.
- Store dates in ISO 8601 format (`yyyy-mm-ddThh:mm:ss.sssss`).
- Include comments for complex logic, using '/* ... */' for block comments and '--' for line comments.
## Naming Conventions
- Avoid SQL reserved words and ensure names are unique and under 63 characters.
- Use snake_case for tables and columns.
- Prefer plurals for table names
- Prefer singular names for columns.
## Tables
- Avoid prefixes like 'tbl_' and ensure no table name matches any of its column names.
- Always add an `id` column of type `identity generated always` unless otherwise specified.
- Create all tables in the `public` schema unless otherwise specified.
- Always add the schema to SQL queries for clarity.
- Always add a comment to describe what the table does. The comment can be up to 1024 characters.
## Columns
- Use singular names and avoid generic names like 'id'.
- For references to foreign tables, use the singular of the table name with the `_id` suffix. For example `user_id` to reference the `users` table
- Always use lowercase except in cases involving acronyms or when readability would be enhanced by an exception.
#### Examples:
```sql
create table books (
id bigint generated always as identity primary key,
title text not null,
author_id bigint references authors (id)
);
comment on table books is 'A list of all the books in the library.';
```
## Queries
- When the query is shorter keep it on just a few lines. As it gets larger start adding newlines for readability
- Add spaces for readability.
Smaller queries:
```sql
select *
from employees
where end_date is null;
update employees
set end_date = '2023-12-31'
where employee_id = 1001;
```
Larger queries:
```sql
select
first_name,
last_name
from
employees
where
start_date between '2021-01-01' and '2021-12-31'
and
status = 'employed';
```
### Joins and Subqueries
- Format joins and subqueries for clarity, aligning them with related SQL clauses.
- Prefer full table names when referencing tables. This helps for readability.
```sql
select
employees.employee_name,
departments.department_name
from
employees
join
departments on employees.department_id = departments.department_id
where
employees.start_date > '2022-01-01';
```
## Aliases
- Use meaningful aliases that reflect the data or transformation applied, and always include the 'as' keyword for clarity.
```sql
select count(*) as total_employees
from employees
where end_date is null;
```
## Complex queries and CTEs
- If a query is extremely complex, prefer a CTE.
- Make sure the CTE is clear and linear. Prefer readability over performance.
- Add comments to each block.
```sql
with department_employees as (
-- Get all employees and their departments
select
employees.department_id,
employees.first_name,
employees.last_name,
departments.department_name
from
employees
join
departments on employees.department_id = departments.department_id
),
employee_counts as (
-- Count how many employees in each department
select
department_name,
count(*) as num_employees
from
department_employees
group by
department_name
)
select
department_name,
num_employees
from
employee_counts
order by
department_name;
```
---
## Version Control and Workflow
- **Branch Naming**: `feature/`, `bugfix/`, `hotfix/`, `refactor/`, `docs/`.
- **Commit Messages**: Use `type(scope): description` format. Common types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`.
- **Pull Requests**: Use PR templates with a summary, change type, testing steps, and any database changes noted.
- **Schema Updates**: Update `schema.sql` and commit the changes after each migration.
- **Testing Before PR**: Always test changes locally before submitting PRs.
---
## Data Fetching and State Management
- **RSC for Data**: Use React Server Components for data fetching whenever possible.
- **Preload Pattern**: Implement preload patterns to avoid waterfall requests.
- **Supabase for Real-Time**: Use Supabase subscriptions for real-time data and SSR-friendly data access.
- **Zustand**: Manage local state in isolated client components when needed.
- **Vercel KV**: Use Vercel KV for chat history, rate limiting, and ephemeral storage.
- **SSR & Minimize 'use client'**: Prefer SSR and server actions. Only use `use client` for browser-based interactions.
---
## Testing and Quality Assurance
- **Unit Tests**: Write unit tests for utilities, hooks, and business logic.
- **Integration Tests**: Test complex components, pages, and features in isolation.
- **End-to-End Tests**: Validate critical flows (login, checkout) end-to-end.
- **Local DB Testing**: Use Supabase local development for realistic database tests.
- **Coverage**: Maintain a minimum test coverage threshold for PR merges.
---
## Styling and Accessibility
- **Tailwind CSS**: Use utility classes with a mobile-first responsive approach.
- **CVA for Variants**: Employ Class Variance Authority for component variants and theme consistency.
- **Radix UI**: Utilize Radix primitives for accessible UI patterns.
- **ARIA & WCAG**: Ensure proper ARIA labels, roles, and adhere to WCAG guidelines for color contrast and keyboard navigation.
- **Shadcn UI**: Leverage shadcn UI components for design consistency and speed.
---
## Documentation
- **Comments & JSDoc**: Comment complex logic and use JSDoc for functions and components.
- **Readmes**: Keep README files updated with setup, instructions, and architectural details.
- **API & DB Docs**: Document all API endpoints, RLS policies, and database schema.
- **Edge Functions**: Document Supabase Edge Functions and their intended usage.
- **Setup Instructions**: Keep environment configuration and setup steps current for onboarding developers.
---
**Remember:**
- Regularly check file sizes; refactor when needed.
- Maintain separation of concerns and modular design.
- Reuse components and keep them composable and testable.
- Always test locally before pushing changes.
- Ensure proper error handling, user-friendly messages, and accessible interfaces.
## Supabase Migration Rules
- **CRITICAL: Migration File Management**
- NEVER modify existing migration files. Each change requires a new migration file with a fresh timestamp.
- Use `npx supabase migration new <descriptive-name>` to create new migrations.
- Keep migration names short but descriptive (e.g., `add-user-index`, `update-ticket-constraints`).
- One logical change per migration file - don't combine unrelated schema changes.
- Test migrations locally before pushing to production.
- **Migration Best Practices**
- Include `drop if exists` statements to make migrations idempotent.
- Add comments explaining the purpose of each migration.
- For constraint changes, include both `drop constraint if exists` and `add constraint`.
- Order operations correctly (e.g., drop dependent objects before their dependencies).
- Always specify the schema (e.g., `public.users` instead of just `users`).
- **Schema Management**
- Keep `supabase/migrations/` in sync with remote changes.
- Document schema changes in both migration files and project documentation.
- Use `npx supabase db reset` for local development only.
- Use `npx supabase db push` for remote database updates.
- Never use `db reset` on production/remote databases.
- **Types and Validation**
- Generate and commit TypeScript types after schema changes using `supabase gen types typescript`.
- Use Zod schemas that match database constraints.
- Keep `database.types.ts` updated with latest schema.
- **Security and Access Control**
- Document RLS policies in both migrations and project documentation.
- Test RLS policies with different user roles.
- Use service role only for administrative tasks (seeding, migrations).
- Never expose service role key in client-side code.
## Database Standards
- **Naming Conventions**
- Use snake_case for all database objects (tables, columns, functions).
- Prefix function names with verb (e.g., `get_user`, `update_status`).
- Use plural for table names (e.g., `users`, `tickets`).
- Use singular for column names and foreign keys (e.g., `user_id`).
- **Column Standards**
- Include `created_at` and `updated_at` on all tables.
- Use `uuid` for primary keys unless there's a specific reason not to.
- Add appropriate indexes for foreign keys and frequently queried columns.
- Document constraints and indexes in migration files.
- **Error Handling**
- Use custom error codes for database functions.
- Implement proper error handling in application code.
- Log database errors appropriately.
- Provide user-friendly error messages.
## Testing and Validation
- **Migration Testing**
- Test migrations in both directions (up/down).
- Verify data integrity after migrations.
- Test with realistic data volumes.
- Check performance impact of schema changes.
- **Data Seeding**
- Keep seed data minimal but sufficient for testing.
- Use service role for seeding operations.
- Document seed data structure and purpose.
- Include different test scenarios in seed data.