- name
- phase-2-convention
- context
- fork
- background
- false
- classification
- workflow
- classification-reason
- Process automation persists regardless of model advancement
- deprecation-risk
- none
- effort
- medium
- description
- Define coding rules, conventions, and standards for AI collaboration.
Triggers: convention, coding style, lint, rules
- agent
- bkit:pipeline-guide
- allowed-tools
- ["Read","Write","Glob","Grep"]
- user-invocable
- false
- imports
- ["${PLUGIN_ROOT}/templates/pipeline/phase-2-convention.template.md","${PLUGIN_ROOT}/templates/shared/naming-conventions.md"]
- next-skill
- phase-3-mockup
- pdca-phase
- plan
- task-template
- [Phase-2] {feature}
# Phase 2: Coding Convention
> Define code writing rules
## Purpose
Maintain consistent code style. Especially important when collaborating with AI - clarify what style AI should use when writing code.
## What to Do in This Phase
1. **Naming Rules**: Variables, functions, files, folder names
2. **Code Style**: Indentation, quotes, semicolons, etc.
3. **Structure Rules**: Folder structure, file separation criteria
4. **Pattern Definition**: Frequently used code patterns
## Deliverables
```
Project Root/
├── CONVENTIONS.md # Full conventions
└── docs/01-plan/
├── naming.md # Naming rules
└── structure.md # Structure rules
```
## PDCA Application
- **Plan**: Identify necessary convention items
- **Design**: Design detailed rules
- **Do**: Write convention documents
- **Check**: Review consistency/practicality
- **Act**: Finalize and proceed to Phase 3
## Level-wise Application
| Level | Application Level |
|-------|------------------|
| Starter | Basic (essential rules only) |
| Dynamic | Extended (including API, state management) |
| Enterprise | Extended (per-service rules) |
## Core Convention Items
### Naming
- Components: PascalCase
- Functions: camelCase
- Constants: UPPER_SNAKE_CASE
- Files: kebab-case or PascalCase
### Folder Structure
```
src/
├── components/ # Reusable components
├── features/ # Feature modules
├── hooks/ # Custom hooks
├── utils/ # Utilities
└── types/ # Type definitions
```
---
## Environment Variable Convention
### Why Define at Design Stage?
```
❌ Organizing env vars just before deployment
→ Missing variables, naming inconsistency, deployment delays
✅ Establish convention at design stage
→ Consistent naming, clear categorization, fast deployment
```
### Environment Variable Naming Rules
| Prefix | Purpose | Exposure Scope | Example |
|--------|---------|----------------|---------|
| `NEXT_PUBLIC_` | Client-exposed | Browser | `NEXT_PUBLIC_API_URL` |
| `DB_` | Database | Server only | `DB_HOST`, `DB_PASSWORD` |
| `API_` | External API keys | Server only | `API_STRIPE_SECRET` |
| `AUTH_` | Authentication | Server only | `AUTH_SECRET`, `AUTH_GOOGLE_ID` |
| `SMTP_` | Email service | Server only | `SMTP_HOST`, `SMTP_PASSWORD` |
| `STORAGE_` | File storage | Server only | `STORAGE_S3_BUCKET` |
```
⚠️ Security Principles
- Never expose anything except NEXT_PUBLIC_* to client
- API keys and passwords must be server-only variables
- Never commit sensitive info in .env files
```
### .env File Structure
```
Project Root/
├── .env.example # Template (in Git, values empty)
├── .env.local # Local development (Git ignored)
├── .env.development # Development env defaults
├── .env.staging # Staging env defaults
├── .env.production # Production defaults (no sensitive info)
└── .env.test # Test environment
```
### .env.example Template
```bash
# .env.example - This file is included in Git
# Set actual values in .env.local
# ===== App Settings =====
NODE_ENV=development
NEXT_PUBLIC_APP_URL=http://localhost:3000
# ===== Database =====
DB_HOST=
DB_PORT=5432
DB_NAME=
DB_USER=
DB_PASSWORD=
# ===== Authentication =====
AUTH_SECRET= # openssl rand -base64 32
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
# ===== External Services =====
NEXT_PUBLIC_API_URL=
API_STRIPE_SECRET=
SMTP_HOST=
SMTP_USER=
SMTP_PASSWORD=
```
### Environment-wise Value Classification
| Variable Type | .env.example | .env.local | CI/CD Secrets |
|---------------|:------------:|:----------:|:-------------:|
| App URL | Template | Local value | Per-env value |
| API endpoints | Template | Local/dev | Per-env value |
| DB password | Empty | Local value | ✅ Secrets |
| API keys | Empty | Test key | ✅ Secrets |
| JWT Secret | Empty | Local value | ✅ Secrets |
### Environment Variable Validation
```typescript
// lib/env.ts - Validate env vars at app startup
import { z } from 'zod';
const envSchema = z.object({
// Required
DATABASE_URL: z.string().url(),
AUTH_SECRET: z.string().min(32),
// Optional (with defaults)
NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
// Client-exposed
NEXT_PUBLIC_APP_URL: z.string().url(),
});
// Validation and type inference
export const env = envSchema.parse(process.env);
// Type-safe usage
// env.DATABASE_URL ← autocomplete supported
```
### Environment Variable Checklist
- [ ] **Naming Consistency**
- [ ] Follow prefix rules (NEXT_PUBLIC_, DB_, API_, etc.)
- [ ] Use UPPER_SNAKE_CASE
- [ ] **File Structure**
- [ ] Create .env.example (template)
- [ ] Register .env.local in .gitignore
- [ ] Separate .env files per environment
- [ ] **Security**
- [ ] Classify sensitive info
- [ ] Verify client-exposed variables
- [ ] Organize Secrets list (for Phase 9 deployment)
---
## Clean Architecture Principles
### Why Define at Design Stage?
```
Clean Architecture = Code resilient to change
❌ Developing without architecture
→ Spaghetti code, multiple file changes for each modification
✅ Define layers at design stage
→ Separation of concerns, easy testing, easy maintenance
```
### 4-Layer Architecture (Recommended)
```
src/
├── presentation/ # or app/, pages/
│ ├── components/ # UI components
│ ├── hooks/ # State management hooks
│ └── pages/ # Page components
│
├── application/ # or services/, features/
│ ├── use-cases/ # Business use cases
│ └── services/ # API service wrappers
│
├── domain/ # or types/, entities/
│ ├── entities/ # Domain entities
│ ├── types/ # Type definitions
│ └── constants/ # Domain constants
│
└── infrastructure/ # or lib/, api/
├── api/ # API clients
├── db/ # Database connections
└── external/ # External services
```
### Layer Responsibilities and Rules
| Layer | Responsibility | Can Depend On | Cannot Depend On |
|-------|---------------|---------------|------------------|
| **Presentation** | UI rendering, user events | Application, Domain | Infrastructure directly |
| **Application** | Business logic orchestration | Domain, Infrastructure | Presentation |
| **Domain** | Core business rules, types | Nothing (independent) | All external layers |
| **Infrastructure** | External system connections | Domain | Application, Presentation |
### Dependency Rule
```typescript
// ❌ Bad: Presentation directly calls Infrastructure
// components/UserList.tsx
import { apiClient } from '@/lib/api/client'; // Direct import forbidden!
export function UserList() {
const users = apiClient.get('/users'); // ❌
}
// ✅ Good: Presentation → Application → Infrastructure
// hooks/useUsers.ts
import { userService } from '@/services/user.service';
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: userService.getList, // ✅ Call through Service
});
}
// components/UserList.tsx
import { useUsers } from '@/hooks/useUsers';
export function UserList() {
const { data: users } = useUsers(); // ✅ Call through Hook
}
```
### File Import Rules
```typescript
// ===== Allowed import directions =====
// In presentation/:
import { User } from '@/domain/types'; // ✅ Domain OK
import { useUsers } from '@/hooks/useUsers'; // ✅ Same layer OK
import { userService } from '@/services/user'; // ✅ Application OK
// In application/:
import { User } from '@/domain/types'; // ✅ Domain OK
import { apiClient } from '@/lib/api/client'; // ✅ Infrastructure OK
// In domain/:
// Minimize external imports (pure types/logic only)
// In infrastructure/:
import { User } from '@/domain/types'; // ✅ Domain OK
// ===== Forbidden imports =====
// In domain/:
import { apiClient } from '@/lib/api/client'; // ❌ Infrastructure forbidden
import { Button } from '@/components/ui/button'; // ❌ Presentation forbidden
// In infrastructure/:
import { useUsers } from '@/hooks/useUsers'; // ❌ Presentation forbidden
```
### Level-wise Application
| Level | Architecture Application |
|-------|-------------------------|
| **Starter** | Simple structure (components, lib) |
| **Dynamic** | 3-4 layer separation (recommended structure) |
| **Enterprise** | Strict layer separation + DI container |
### Starter Level Folder Structure
```
src/
├── components/ # UI components
├── lib/ # Utilities, API
└── types/ # Type definitions
```
### Dynamic Level Folder Structure
```
src/
├── components/ # Presentation
│ └── ui/
├── features/ # Feature modules (Application + Presentation)
│ ├── auth/
│ └── product/
├── hooks/ # Presentation (state management)
├── services/ # Application
├── types/ # Domain
└── lib/ # Infrastructure
└── api/
```
### Enterprise Level Folder Structure
```
src/
├── presentation/
│ ├── components/
│ ├── hooks/
│ └── pages/
├── application/
│ ├── use-cases/
│ └── services/
├── domain/
│ ├── entities/
│ └── types/
└── infrastructure/
├── api/
└── db/
```
---
## Phase Connection
Conventions defined in this Phase are verified in later Phases:
| Definition (Phase 2) | Verification (Phase 8) |
|----------------------|------------------------|
| Naming rules | Naming consistency check |
| Folder structure | Structure consistency check |
| Environment variable convention | Env var naming check |
| Clean architecture principles | Dependency direction check |
---
## Template
See `templates/pipeline/phase-2-convention.template.md`
## Next Phase
Phase 3: Mockup Development → Rules are set, now rapid prototyping
---
## 6. Reusability Principles
### 6.1 Function Design
#### Creating Generic Functions
```typescript
// ❌ Handles only specific case
function formatUserName(user: User) {
return `${user.firstName} ${user.lastName}`
}
// ✅ Generic
function formatFullName(firstName: string, lastName: string) {
return `${firstName} ${lastName}`
}
// Usage
formatFullName(user.firstName, user.lastName)
formatFullName(author.first, author.last)
```
#### Parameter Generalization
```typescript
// ❌ Tied to specific type
function calculateOrderTotal(order: Order) {
return order.items.reduce((sum, item) => sum + item.price, 0)
}
// ✅ Generalized with interface
interface HasPrice { price: number }
function calculateTotal<T extends HasPrice>(items: T[]) {
return items.reduce((sum, item) => sum + item.price, 0)
}
// Can be used in various places
calculateTotal(order.items)
calculateTotal(cart.products)
calculateTotal(invoice.lineItems)
```
### 6.2 Component Design
#### Composable Components
Voir sur GitHub