chore: initialize repository with project docs and tooling
- Add persistent docs: PRD, functional design, architecture, repository structure, development guidelines, milestones - Add brainstorming notes (docs/ideas/) - Configure tooling: package.json, tsconfig, eslint, prettier, vitest - Add opencode configuration (commands, skills, agents) - Add .gitignore for node_modules, .env, data/, backups/, build outputs
This commit is contained in:
400
.opencode/skills/repository-structure/guide.md
Normal file
400
.opencode/skills/repository-structure/guide.md
Normal file
@ -0,0 +1,400 @@
|
||||
# Repository Structure Document Authoring Guide
|
||||
|
||||
## Basic Principles
|
||||
|
||||
### 1. Clarify Roles
|
||||
|
||||
Each directory should have a single, well-defined role.
|
||||
|
||||
**Bad example**:
|
||||
```
|
||||
src/
|
||||
├── stuff/ # Vague
|
||||
├── misc/ # Miscellaneous
|
||||
└── utils/ # Too generic
|
||||
```
|
||||
|
||||
**Good example**:
|
||||
```
|
||||
src/
|
||||
├── commands/ # CLI command implementations
|
||||
├── services/ # Business logic
|
||||
├── repositories/ # Data persistence
|
||||
└── validators/ # Input validation
|
||||
```
|
||||
|
||||
### 2. Enforce Layer Separation
|
||||
|
||||
Reflect the architecture's layer structure in the directory structure:
|
||||
|
||||
```
|
||||
src/
|
||||
├── ui/ # UI layer
|
||||
│ └── cli/ # CLI implementation
|
||||
├── services/ # Service layer
|
||||
│ └── task/ # Task management service
|
||||
└── repositories/ # Data layer
|
||||
└── task/ # Task repository
|
||||
```
|
||||
|
||||
### 3. Split by Technical Concern (Baseline)
|
||||
|
||||
Split directories by related technical concerns:
|
||||
|
||||
**Basic structure**:
|
||||
```
|
||||
src/
|
||||
├── commands/ # CLI commands
|
||||
├── services/ # Business logic
|
||||
├── repositories/ # Data persistence
|
||||
└── types/ # Type definitions
|
||||
```
|
||||
|
||||
**Mapping to the layer structure**:
|
||||
```
|
||||
CLI/UI layer → commands/, cli/
|
||||
Service layer → services/
|
||||
Data layer → repositories/, storage/
|
||||
```
|
||||
|
||||
## Designing the Directory Structure
|
||||
|
||||
### Expressing the Layer Structure
|
||||
|
||||
```typescript
|
||||
// Bad example: flat structure
|
||||
src/
|
||||
├── TaskCLI.ts
|
||||
├── TaskService.ts
|
||||
├── TaskRepository.ts
|
||||
├── UserCLI.ts
|
||||
├── UserService.ts
|
||||
└── UserRepository.ts
|
||||
|
||||
// Good example: clear layers
|
||||
src/
|
||||
├── cli/
|
||||
│ ├── TaskCLI.ts
|
||||
│ └── UserCLI.ts
|
||||
├── services/
|
||||
│ ├── TaskService.ts
|
||||
│ └── UserService.ts
|
||||
└── repositories/
|
||||
├── TaskRepository.ts
|
||||
└── UserRepository.ts
|
||||
```
|
||||
|
||||
### Placement of the Test Directory
|
||||
|
||||
**Recommended structure**:
|
||||
```
|
||||
project/
|
||||
├── src/
|
||||
│ └── services/
|
||||
│ └── TaskService.ts
|
||||
└── tests/
|
||||
├── unit/
|
||||
│ └── services/
|
||||
│ └── TaskService.test.ts
|
||||
├── integration/
|
||||
└── e2e/
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Test code is separated from production code
|
||||
- Easy to exclude tests at build time
|
||||
- Can be organized by test type
|
||||
|
||||
## Naming Convention Best Practices
|
||||
|
||||
### Principles for Directory Names
|
||||
|
||||
**1. Use the plural form (layer directories)**
|
||||
```
|
||||
✅ services/
|
||||
✅ repositories/
|
||||
✅ controllers/
|
||||
|
||||
❌ service/
|
||||
❌ repository/
|
||||
❌ controller/
|
||||
```
|
||||
|
||||
Rationale: They hold multiple files
|
||||
|
||||
**2. Use kebab-case**
|
||||
```
|
||||
✅ task-management/
|
||||
✅ user-authentication/
|
||||
|
||||
❌ TaskManagement/
|
||||
❌ userAuthentication/
|
||||
```
|
||||
|
||||
Rationale: Compatibility with URLs and the file system
|
||||
|
||||
**3. Use specific names**
|
||||
```
|
||||
✅ validators/ # Input validation
|
||||
✅ formatters/ # Data formatting
|
||||
✅ parsers/ # Data parsing
|
||||
|
||||
❌ utils/ # Too generic
|
||||
❌ helpers/ # Vague
|
||||
❌ common/ # Meaningless
|
||||
```
|
||||
|
||||
### Principles for File Names
|
||||
|
||||
**1. Class files: PascalCase + role suffix**
|
||||
```typescript
|
||||
// Service classes
|
||||
TaskService.ts
|
||||
UserAuthenticationService.ts
|
||||
|
||||
// Repository classes
|
||||
TaskRepository.ts
|
||||
UserRepository.ts
|
||||
|
||||
// Controller classes
|
||||
TaskController.ts
|
||||
```
|
||||
|
||||
**2. Function files: camelCase + start with a verb**
|
||||
```typescript
|
||||
// Utility functions
|
||||
formatDate.ts
|
||||
validateEmail.ts
|
||||
parseCommandArguments.ts
|
||||
```
|
||||
|
||||
**3. Type definition files: PascalCase or kebab-case**
|
||||
```typescript
|
||||
// Interface definitions
|
||||
Task.ts
|
||||
UserProfile.ts
|
||||
|
||||
// Type definition collections
|
||||
task-types.d.ts
|
||||
api-types.d.ts
|
||||
```
|
||||
|
||||
**4. Constant files: UPPER_SNAKE_CASE or kebab-case**
|
||||
```typescript
|
||||
// Constant definitions
|
||||
API_ENDPOINTS.ts
|
||||
ERROR_MESSAGES.ts
|
||||
|
||||
// or
|
||||
api-endpoints.ts
|
||||
error-messages.ts
|
||||
```
|
||||
|
||||
## Managing Dependencies
|
||||
|
||||
### Dependency Rules Between Layers
|
||||
|
||||
```typescript
|
||||
// ✅ Good example: dependency from an upper layer to a lower layer
|
||||
// cli/TaskCLI.ts
|
||||
import { TaskService } from '../services/TaskService';
|
||||
|
||||
class TaskCLI {
|
||||
constructor(private taskService: TaskService) {}
|
||||
}
|
||||
|
||||
// ❌ Bad example: dependency from a lower layer to an upper layer
|
||||
// services/TaskService.ts
|
||||
import { TaskCLI } from '../cli/TaskCLI'; // Forbidden!
|
||||
```
|
||||
|
||||
### Avoiding Circular Dependencies
|
||||
|
||||
**Problematic code**:
|
||||
```typescript
|
||||
// services/TaskService.ts
|
||||
import { UserService } from './UserService';
|
||||
|
||||
export class TaskService {
|
||||
constructor(private userService: UserService) {}
|
||||
}
|
||||
|
||||
// services/UserService.ts
|
||||
import { TaskService } from './TaskService'; // Circular dependency!
|
||||
|
||||
export class UserService {
|
||||
constructor(private taskService: TaskService) {}
|
||||
}
|
||||
```
|
||||
|
||||
**Solution 1: Extract shared type definitions**
|
||||
```typescript
|
||||
// types/Service.ts
|
||||
export interface ITaskService { /* ... */ }
|
||||
export interface IUserService { /* ... */ }
|
||||
|
||||
// services/TaskService.ts
|
||||
import type { IUserService } from '../types/Service';
|
||||
|
||||
export class TaskService {
|
||||
constructor(private userService: IUserService) {}
|
||||
}
|
||||
|
||||
// services/UserService.ts
|
||||
import type { ITaskService } from '../types/Service';
|
||||
|
||||
export class UserService {
|
||||
constructor(private taskService: ITaskService) {}
|
||||
}
|
||||
```
|
||||
|
||||
**Solution 2: Rethink the dependencies**
|
||||
```typescript
|
||||
// Extract shared functionality into a separate service
|
||||
// services/NotificationService.ts
|
||||
export class NotificationService {
|
||||
notifyTaskAssignment(taskId: string, userId: string): void {
|
||||
// Notification handling
|
||||
}
|
||||
}
|
||||
|
||||
// services/TaskService.ts
|
||||
import { NotificationService } from './NotificationService';
|
||||
|
||||
export class TaskService {
|
||||
constructor(private notificationService: NotificationService) {}
|
||||
}
|
||||
|
||||
// services/UserService.ts
|
||||
import { NotificationService } from './NotificationService';
|
||||
|
||||
export class UserService {
|
||||
constructor(private notificationService: NotificationService) {}
|
||||
}
|
||||
```
|
||||
|
||||
## Scaling Strategy
|
||||
|
||||
### Recommended Structure
|
||||
|
||||
**Standard pattern**:
|
||||
```
|
||||
src/
|
||||
├── commands/
|
||||
│ └── TaskCommand.ts
|
||||
├── services/
|
||||
│ ├── TaskService.ts
|
||||
│ └── UserService.ts
|
||||
├── repositories/
|
||||
│ ├── TaskRepository.ts
|
||||
│ └── UserRepository.ts
|
||||
├── types/
|
||||
│ ├── Task.ts
|
||||
│ └── User.ts
|
||||
├── validators/
|
||||
│ └── TaskValidator.ts
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Responsibilities are clear per layer
|
||||
- No later refactoring required
|
||||
- Easy to standardize across a team
|
||||
|
||||
### Timing for Module Separation
|
||||
|
||||
**Signs that separation should be considered**:
|
||||
1. A directory contains 10 or more files
|
||||
2. Related functionality is grouped together
|
||||
3. It can be tested independently
|
||||
4. It has few dependencies on other features
|
||||
|
||||
**Separation procedure**:
|
||||
```typescript
|
||||
// Before: everything placed in services/
|
||||
services/
|
||||
├── TaskService.ts
|
||||
├── TaskValidationService.ts
|
||||
├── TaskNotificationService.ts
|
||||
├── UserService.ts
|
||||
└── UserAuthService.ts
|
||||
|
||||
// After: modularized by feature
|
||||
modules/
|
||||
├── task/
|
||||
│ ├── TaskService.ts
|
||||
│ ├── TaskValidationService.ts
|
||||
│ └── TaskNotificationService.ts
|
||||
└── user/
|
||||
├── UserService.ts
|
||||
└── UserAuthService.ts
|
||||
```
|
||||
|
||||
## Handling Special Cases
|
||||
|
||||
### Placement of Shared Code
|
||||
|
||||
**shared/ or common/ directory**
|
||||
```
|
||||
src/
|
||||
├── shared/
|
||||
│ ├── utils/ # General-purpose utilities
|
||||
│ ├── types/ # Shared type definitions
|
||||
│ └── constants/ # Shared constants
|
||||
├── commands/
|
||||
├── services/
|
||||
└── repositories/
|
||||
```
|
||||
|
||||
**Rules**:
|
||||
- Only things genuinely used across multiple layers
|
||||
- Do not include anything used in only a single layer
|
||||
|
||||
### Managing Configuration Files (when applicable)
|
||||
|
||||
```
|
||||
config/
|
||||
├── default.ts # Default settings
|
||||
└── constants.ts # Constant definitions
|
||||
```
|
||||
|
||||
### Managing Scripts (when applicable)
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── build.sh # Build script
|
||||
└── dev-tools.ts # Development helper script
|
||||
```
|
||||
|
||||
## Document Placement
|
||||
|
||||
### Document Types and Their Locations
|
||||
|
||||
**Project root**:
|
||||
- `README.md`: Project overview
|
||||
- `CONTRIBUTING.md`: Contribution guide
|
||||
- `LICENSE`: License
|
||||
|
||||
**docs/ directory**:
|
||||
- `product-requirements.md`: PRD
|
||||
- `functional-design.md`: Functional design document
|
||||
- `architecture.md`: Architecture design document
|
||||
- `repository-structure.md`: This document
|
||||
- `development-guidelines.md`: Development guidelines
|
||||
- `glossary.md`: Glossary
|
||||
|
||||
**Within the source code**:
|
||||
- TSDoc/JSDoc comments: Descriptions of functions and classes
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Each directory's role is clearly defined
|
||||
- [ ] The layer structure is reflected in the directories
|
||||
- [ ] Naming conventions are consistent
|
||||
- [ ] The placement policy for test code is decided
|
||||
- [ ] Dependency rules are clear
|
||||
- [ ] There are no circular dependencies
|
||||
- [ ] A scaling strategy has been considered
|
||||
- [ ] Placement rules for shared code are defined
|
||||
- [ ] A management method for configuration files is decided
|
||||
- [ ] Document locations are clear
|
||||
Reference in New Issue
Block a user