fix(conductor): move plugin to plugins/ directory for proper discovery

Conductor plugin was at root level instead of plugins/ directory,
causing slash commands to not be recognized by Claude Code.
This commit is contained in:
Seth Hobson
2026-01-15 20:34:57 -05:00
parent efb75ac1fc
commit 1408671cb7
28 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,600 @@
# C# Style Guide
C# conventions and best practices for .NET development.
## Naming Conventions
### General Rules
```csharp
// PascalCase for public members, types, namespaces
public class UserService { }
public void ProcessOrder() { }
public string FirstName { get; set; }
// camelCase for private fields, parameters, locals
private readonly ILogger _logger;
private int _itemCount;
public void DoWork(string inputValue) { }
// Prefix interfaces with I
public interface IUserRepository { }
public interface INotificationService { }
// Suffix async methods with Async
public async Task<User> GetUserAsync(int id) { }
public async Task ProcessOrderAsync(Order order) { }
// Constants: PascalCase (not SCREAMING_CASE)
public const int MaxRetryCount = 3;
public const string DefaultCurrency = "USD";
```
### Field and Property Naming
```csharp
public class Order
{
// Private fields: underscore prefix + camelCase
private readonly IOrderRepository _repository;
private int _itemCount;
// Public properties: PascalCase
public int Id { get; set; }
public string CustomerName { get; set; }
public DateTime CreatedAt { get; init; }
// Boolean properties: Is/Has/Can prefix
public bool IsActive { get; set; }
public bool HasDiscount { get; set; }
public bool CanEdit { get; }
}
```
## Async/Await Patterns
### Basic Async Usage
```csharp
// Always use async/await for I/O operations
public async Task<User> GetUserAsync(int id)
{
var user = await _repository.FindAsync(id);
if (user == null)
{
throw new NotFoundException($"User {id} not found");
}
return user;
}
// Don't block on async code
// Bad
var user = GetUserAsync(id).Result;
// Good
var user = await GetUserAsync(id);
```
### Async Best Practices
```csharp
// Use ConfigureAwait(false) in library code
public async Task<Data> FetchDataAsync()
{
var response = await _httpClient.GetAsync(url)
.ConfigureAwait(false);
return await response.Content.ReadAsAsync<Data>()
.ConfigureAwait(false);
}
// Avoid async void except for event handlers
// Bad
public async void ProcessOrder() { }
// Good
public async Task ProcessOrderAsync() { }
// Event handler exception
private async void Button_Click(object sender, EventArgs e)
{
try
{
await ProcessOrderAsync();
}
catch (Exception ex)
{
HandleError(ex);
}
}
```
### Parallel Async Operations
```csharp
// Execute independent operations in parallel
public async Task<DashboardData> LoadDashboardAsync()
{
var usersTask = _userService.GetActiveUsersAsync();
var ordersTask = _orderService.GetRecentOrdersAsync();
var statsTask = _statsService.GetDailyStatsAsync();
await Task.WhenAll(usersTask, ordersTask, statsTask);
return new DashboardData
{
Users = await usersTask,
Orders = await ordersTask,
Stats = await statsTask
};
}
// Use SemaphoreSlim for throttling
public async Task ProcessItemsAsync(IEnumerable<Item> items)
{
using var semaphore = new SemaphoreSlim(10); // Max 10 concurrent
var tasks = items.Select(async item =>
{
await semaphore.WaitAsync();
try
{
await ProcessItemAsync(item);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);
}
```
## LINQ
### Query Syntax vs Method Syntax
```csharp
// Method syntax (preferred for simple queries)
var activeUsers = users
.Where(u => u.IsActive)
.OrderBy(u => u.Name)
.ToList();
// Query syntax (for complex queries with joins)
var orderSummary =
from order in orders
join customer in customers on order.CustomerId equals customer.Id
where order.Total > 100
group order by customer.Name into g
select new { Customer = g.Key, Total = g.Sum(o => o.Total) };
```
### LINQ Best Practices
```csharp
// Use appropriate methods
var hasItems = items.Any(); // Not: items.Count() > 0
var firstOrDefault = items.FirstOrDefault(); // Not: items.First()
var count = items.Count; // Property, not Count()
// Avoid multiple enumerations
// Bad
if (items.Any())
{
foreach (var item in items) { }
}
// Good
var itemList = items.ToList();
if (itemList.Count > 0)
{
foreach (var item in itemList) { }
}
// Project early to reduce memory
var names = users
.Where(u => u.IsActive)
.Select(u => u.Name) // Select only what you need
.ToList();
```
### Common LINQ Operations
```csharp
// Filtering
var adults = people.Where(p => p.Age >= 18);
// Transformation
var names = people.Select(p => $"{p.FirstName} {p.LastName}");
// Aggregation
var total = orders.Sum(o => o.Amount);
var average = scores.Average();
var max = values.Max();
// Grouping
var byDepartment = employees
.GroupBy(e => e.Department)
.Select(g => new { Department = g.Key, Count = g.Count() });
// Joining
var result = orders
.Join(customers,
o => o.CustomerId,
c => c.Id,
(o, c) => new { Order = o, Customer = c });
// Flattening
var allOrders = customers.SelectMany(c => c.Orders);
```
## Dependency Injection
### Service Registration
```csharp
// In Program.cs or Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Transient: new instance each time
services.AddTransient<IEmailService, EmailService>();
// Scoped: one instance per request
services.AddScoped<IUserRepository, UserRepository>();
// Singleton: one instance for app lifetime
services.AddSingleton<ICacheService, MemoryCacheService>();
// Factory registration
services.AddScoped<IDbConnection>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
return new SqlConnection(config.GetConnectionString("Default"));
});
}
```
### Constructor Injection
```csharp
public class OrderService : IOrderService
{
private readonly IOrderRepository _repository;
private readonly ILogger<OrderService> _logger;
private readonly IEmailService _emailService;
public OrderService(
IOrderRepository repository,
ILogger<OrderService> logger,
IEmailService emailService)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_emailService = emailService ?? throw new ArgumentNullException(nameof(emailService));
}
public async Task<Order> CreateOrderAsync(OrderRequest request)
{
_logger.LogInformation("Creating order for customer {CustomerId}", request.CustomerId);
var order = new Order(request);
await _repository.SaveAsync(order);
await _emailService.SendOrderConfirmationAsync(order);
return order;
}
}
```
### Options Pattern
```csharp
// Configuration class
public class EmailSettings
{
public string SmtpServer { get; set; }
public int Port { get; set; }
public string FromAddress { get; set; }
}
// Registration
services.Configure<EmailSettings>(
configuration.GetSection("Email"));
// Usage
public class EmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> options)
{
_settings = options.Value;
}
}
```
## Testing
### xUnit Basics
```csharp
public class CalculatorTests
{
[Fact]
public void Add_TwoPositiveNumbers_ReturnsSum()
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Add(2, 3);
// Assert
Assert.Equal(5, result);
}
[Theory]
[InlineData(1, 1, 2)]
[InlineData(0, 0, 0)]
[InlineData(-1, 1, 0)]
public void Add_VariousNumbers_ReturnsCorrectSum(int a, int b, int expected)
{
var calculator = new Calculator();
Assert.Equal(expected, calculator.Add(a, b));
}
}
```
### Mocking with Moq
```csharp
public class OrderServiceTests
{
private readonly Mock<IOrderRepository> _mockRepository;
private readonly Mock<ILogger<OrderService>> _mockLogger;
private readonly OrderService _service;
public OrderServiceTests()
{
_mockRepository = new Mock<IOrderRepository>();
_mockLogger = new Mock<ILogger<OrderService>>();
_service = new OrderService(_mockRepository.Object, _mockLogger.Object);
}
[Fact]
public async Task GetOrderAsync_ExistingOrder_ReturnsOrder()
{
// Arrange
var expectedOrder = new Order { Id = 1, Total = 100m };
_mockRepository
.Setup(r => r.FindAsync(1))
.ReturnsAsync(expectedOrder);
// Act
var result = await _service.GetOrderAsync(1);
// Assert
Assert.Equal(expectedOrder.Id, result.Id);
_mockRepository.Verify(r => r.FindAsync(1), Times.Once);
}
[Fact]
public async Task GetOrderAsync_NonExistingOrder_ThrowsNotFoundException()
{
// Arrange
_mockRepository
.Setup(r => r.FindAsync(999))
.ReturnsAsync((Order)null);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(
() => _service.GetOrderAsync(999));
}
}
```
### Integration Testing
```csharp
public class ApiIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public ApiIntegrationTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetUsers_ReturnsSuccessAndCorrectContentType()
{
// Act
var response = await _client.GetAsync("/api/users");
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal("application/json; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
```
## Common Patterns
### Null Handling
```csharp
// Null-conditional operators
var length = customer?.Address?.Street?.Length;
var name = user?.Name ?? "Unknown";
// Null-coalescing assignment
list ??= new List<Item>();
// Pattern matching for null checks
if (user is not null)
{
ProcessUser(user);
}
// Guard clauses
public void ProcessOrder(Order order)
{
ArgumentNullException.ThrowIfNull(order);
if (order.Items.Count == 0)
{
throw new ArgumentException("Order must have items", nameof(order));
}
// Process...
}
```
### Records and Init-Only Properties
```csharp
// Record for immutable data
public record User(int Id, string Name, string Email);
// Record with additional members
public record Order
{
public int Id { get; init; }
public string CustomerName { get; init; }
public decimal Total { get; init; }
public bool IsHighValue => Total > 1000;
}
// Record mutation via with expression
var updatedUser = user with { Name = "New Name" };
```
### Pattern Matching
```csharp
// Type patterns
public decimal CalculateDiscount(object customer) => customer switch
{
PremiumCustomer p => p.PurchaseTotal * 0.2m,
RegularCustomer r when r.YearsActive > 5 => r.PurchaseTotal * 0.1m,
RegularCustomer r => r.PurchaseTotal * 0.05m,
null => 0m,
_ => throw new ArgumentException("Unknown customer type")
};
// Property patterns
public string GetShippingOption(Order order) => order switch
{
{ Total: > 100, IsPriority: true } => "Express",
{ Total: > 100 } => "Standard",
{ IsPriority: true } => "Priority",
_ => "Economy"
};
// List patterns (C# 11)
public bool IsValidSequence(int[] numbers) => numbers switch
{
[1, 2, 3] => true,
[1, .., 3] => true,
[_, _, ..] => numbers.Length >= 2,
_ => false
};
```
### Disposable Pattern
```csharp
public class ResourceManager : IDisposable
{
private bool _disposed;
private readonly FileStream _stream;
public ResourceManager(string path)
{
_stream = File.OpenRead(path);
}
public void DoWork()
{
ObjectDisposedException.ThrowIf(_disposed, this);
// Work with _stream
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
_stream?.Dispose();
}
_disposed = true;
}
}
// Using statement
using var manager = new ResourceManager("file.txt");
manager.DoWork();
```
## Code Organization
### File Structure
```csharp
// One type per file (generally)
// Filename matches type name: UserService.cs
// Order of members
public class UserService
{
// 1. Constants
private const int MaxRetries = 3;
// 2. Static fields
private static readonly object _lock = new();
// 3. Instance fields
private readonly IUserRepository _repository;
// 4. Constructors
public UserService(IUserRepository repository)
{
_repository = repository;
}
// 5. Properties
public int TotalUsers { get; private set; }
// 6. Public methods
public async Task<User> GetUserAsync(int id) { }
// 7. Private methods
private void ValidateUser(User user) { }
}
```
### Project Structure
```
Solution/
├── src/
│ ├── MyApp.Api/ # Web API project
│ ├── MyApp.Core/ # Domain/business logic
│ ├── MyApp.Infrastructure/ # Data access, external services
│ └── MyApp.Shared/ # Shared utilities
├── tests/
│ ├── MyApp.UnitTests/
│ └── MyApp.IntegrationTests/
└── MyApp.sln
```

View File

@@ -0,0 +1,668 @@
# Dart/Flutter Style Guide
Dart language conventions and Flutter-specific patterns.
## Null Safety
### Enable Sound Null Safety
```dart
// pubspec.yaml
environment:
sdk: '>=3.0.0 <4.0.0'
// All types are non-nullable by default
String name = 'John'; // Cannot be null
String? nickname; // Can be null
// Late initialization
late final Database database;
```
### Null-Aware Operators
```dart
// Null-aware access
final length = user?.name?.length;
// Null-aware assignment
nickname ??= 'Anonymous';
// Null assertion (use sparingly)
final definitelyNotNull = maybeNull!;
// Null-aware cascade
user
?..name = 'John'
..email = 'john@example.com';
// Null coalescing
final displayName = user.nickname ?? user.name ?? 'Unknown';
```
### Null Handling Patterns
```dart
// Guard clause with null check
void processUser(User? user) {
if (user == null) {
throw ArgumentError('User cannot be null');
}
// user is promoted to non-nullable here
print(user.name);
}
// Pattern matching (Dart 3)
void handleResult(Result? result) {
switch (result) {
case Success(data: final data):
handleSuccess(data);
case Error(message: final message):
handleError(message);
case null:
handleNull();
}
}
```
## Async/Await
### Future Basics
```dart
// Async function
Future<User> fetchUser(int id) async {
final response = await http.get(Uri.parse('/users/$id'));
if (response.statusCode != 200) {
throw HttpException('Failed to fetch user');
}
return User.fromJson(jsonDecode(response.body));
}
// Error handling
Future<User?> safeFetchUser(int id) async {
try {
return await fetchUser(id);
} on HttpException catch (e) {
logger.error('HTTP error: ${e.message}');
return null;
} catch (e) {
logger.error('Unexpected error: $e');
return null;
}
}
```
### Parallel Execution
```dart
// Wait for all futures
Future<Dashboard> loadDashboard() async {
final results = await Future.wait([
fetchUsers(),
fetchOrders(),
fetchStats(),
]);
return Dashboard(
users: results[0] as List<User>,
orders: results[1] as List<Order>,
stats: results[2] as Stats,
);
}
// With typed results
Future<(List<User>, List<Order>)> loadData() async {
final (users, orders) = await (
fetchUsers(),
fetchOrders(),
).wait;
return (users, orders);
}
```
### Streams
```dart
// Stream creation
Stream<int> countStream(int max) async* {
for (var i = 0; i < max; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
// Stream transformation
Stream<String> userNames(Stream<User> users) {
return users.map((user) => user.name);
}
// Stream consumption
void listenToUsers() {
userStream.listen(
(user) => print('New user: ${user.name}'),
onError: (error) => print('Error: $error'),
onDone: () => print('Stream closed'),
);
}
```
## Widgets
### Stateless Widgets
```dart
class UserCard extends StatelessWidget {
const UserCard({
super.key,
required this.user,
this.onTap,
});
final User user;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(user.avatarUrl),
),
title: Text(user.name),
subtitle: Text(user.email),
onTap: onTap,
),
);
}
}
```
### Stateful Widgets
```dart
class Counter extends StatefulWidget {
const Counter({super.key, this.initialValue = 0});
final int initialValue;
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
late int _count;
@override
void initState() {
super.initState();
_count = widget.initialValue;
}
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}
```
### Widget Best Practices
```dart
// Use const constructors
class MyWidget extends StatelessWidget {
const MyWidget({super.key}); // const constructor
@override
Widget build(BuildContext context) {
return const Column(
children: [
Text('Hello'), // const widget
SizedBox(height: 8), // const widget
],
);
}
}
// Extract widgets for reusability
class PrimaryButton extends StatelessWidget {
const PrimaryButton({
super.key,
required this.label,
required this.onPressed,
this.isLoading = false,
});
final String label;
final VoidCallback? onPressed;
final bool isLoading;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: isLoading ? null : onPressed,
child: isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Text(label),
);
}
}
```
## State Management
### Provider Pattern
```dart
// Model with ChangeNotifier
class CartModel extends ChangeNotifier {
final List<Item> _items = [];
List<Item> get items => List.unmodifiable(_items);
double get totalPrice => _items.fold(0, (sum, item) => sum + item.price);
void addItem(Item item) {
_items.add(item);
notifyListeners();
}
void removeItem(Item item) {
_items.remove(item);
notifyListeners();
}
}
// Provider setup
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CartModel(),
child: const MyApp(),
),
);
}
// Consuming provider
class CartPage extends StatelessWidget {
const CartPage({super.key});
@override
Widget build(BuildContext context) {
return Consumer<CartModel>(
builder: (context, cart, child) {
return ListView.builder(
itemCount: cart.items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(cart.items[index].name),
);
},
);
},
);
}
}
```
### Riverpod Pattern
```dart
// Provider definition
final userProvider = FutureProvider<User>((ref) async {
final repository = ref.read(userRepositoryProvider);
return repository.fetchCurrentUser();
});
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// Consumer widget
class UserProfile extends ConsumerWidget {
const UserProfile({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider);
return userAsync.when(
data: (user) => Text('Hello, ${user.name}'),
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('Error: $error'),
);
}
}
```
### BLoC Pattern
```dart
// Events
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
// State
class CounterState {
final int count;
const CounterState(this.count);
}
// BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(const CounterState(0)) {
on<IncrementEvent>((event, emit) {
emit(CounterState(state.count + 1));
});
on<DecrementEvent>((event, emit) {
emit(CounterState(state.count - 1));
});
}
}
// Usage
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text('Count: ${state.count}');
},
);
}
}
```
## Testing
### Unit Tests
```dart
import 'package:test/test.dart';
void main() {
group('Calculator', () {
late Calculator calculator;
setUp(() {
calculator = Calculator();
});
test('adds two positive numbers', () {
expect(calculator.add(2, 3), equals(5));
});
test('handles negative numbers', () {
expect(calculator.add(-1, 1), equals(0));
});
});
}
```
### Widget Tests
```dart
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments', (WidgetTester tester) async {
// Build widget
await tester.pumpWidget(const MaterialApp(home: Counter()));
// Verify initial state
expect(find.text('Count: 0'), findsOneWidget);
// Tap increment button
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify incremented state
expect(find.text('Count: 1'), findsOneWidget);
});
testWidgets('shows loading indicator', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: UserProfile(isLoading: true),
),
);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
}
```
### Mocking
```dart
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
@GenerateMocks([UserRepository])
void main() {
late MockUserRepository mockRepository;
late UserService service;
setUp(() {
mockRepository = MockUserRepository();
service = UserService(mockRepository);
});
test('fetches user by id', () async {
final user = User(id: 1, name: 'John');
when(mockRepository.findById(1)).thenAnswer((_) async => user);
final result = await service.getUser(1);
expect(result, equals(user));
verify(mockRepository.findById(1)).called(1);
});
}
```
## Common Patterns
### Factory Constructors
```dart
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory from JSON
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
email: json['email'] as String,
);
}
// Factory for default user
factory User.guest() {
return const User(
id: 0,
name: 'Guest',
email: 'guest@example.com',
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
```
### Extension Methods
```dart
extension StringExtensions on String {
String capitalize() {
if (isEmpty) return this;
return '${this[0].toUpperCase()}${substring(1)}';
}
bool get isValidEmail {
return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this);
}
}
extension DateTimeExtensions on DateTime {
String get formatted => '${day.toString().padLeft(2, '0')}/'
'${month.toString().padLeft(2, '0')}/$year';
bool get isToday {
final now = DateTime.now();
return year == now.year && month == now.month && day == now.day;
}
}
// Usage
final name = 'john'.capitalize(); // 'John'
final isValid = 'test@example.com'.isValidEmail; // true
```
### Sealed Classes (Dart 3)
```dart
sealed class Result<T> {}
class Success<T> extends Result<T> {
final T data;
Success(this.data);
}
class Error<T> extends Result<T> {
final String message;
Error(this.message);
}
class Loading<T> extends Result<T> {}
// Usage with exhaustive pattern matching
Widget buildResult(Result<User> result) {
return switch (result) {
Success(data: final user) => Text(user.name),
Error(message: final msg) => Text('Error: $msg'),
Loading() => const CircularProgressIndicator(),
};
}
```
### Freezed for Immutable Data
```dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
class User with _$User {
const factory User({
required int id,
required String name,
required String email,
@Default(false) bool isActive,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
// Usage
final user = User(id: 1, name: 'John', email: 'john@example.com');
final updatedUser = user.copyWith(name: 'Jane');
```
## Project Structure
### Feature-Based Organization
```
lib/
├── main.dart
├── app.dart
├── core/
│ ├── constants/
│ ├── extensions/
│ ├── utils/
│ └── widgets/
├── features/
│ ├── auth/
│ │ ├── data/
│ │ ├── domain/
│ │ └── presentation/
│ ├── home/
│ │ ├── data/
│ │ ├── domain/
│ │ └── presentation/
│ └── profile/
└── shared/
├── models/
├── services/
└── widgets/
```
### Naming Conventions
```dart
// Files: snake_case
// user_repository.dart
// home_screen.dart
// Classes: PascalCase
class UserRepository {}
class HomeScreen extends StatelessWidget {}
// Variables and functions: camelCase
final userName = 'John';
void fetchUserData() {}
// Constants: camelCase or SCREAMING_SNAKE_CASE
const defaultPadding = 16.0;
const API_BASE_URL = 'https://api.example.com';
// Private: underscore prefix
class _HomeScreenState extends State<HomeScreen> {}
final _internalCache = <String, dynamic>{};
```

View File

@@ -0,0 +1,235 @@
# General Code Style Guide
Universal coding principles that apply across all languages and frameworks.
## Readability
### Code is Read More Than Written
- Write code for humans first, computers second
- Favor clarity over cleverness
- If code needs a comment to explain what it does, consider rewriting it
### Formatting
- Consistent indentation (use project standard)
- Reasonable line length (80-120 characters)
- Logical grouping with whitespace
- One statement per line
### Structure
- Keep functions/methods short (ideally < 20 lines)
- One level of abstraction per function
- Early returns to reduce nesting
- Group related code together
## Naming Conventions
### General Principles
- Names should reveal intent
- Avoid abbreviations (except universally understood ones)
- Be consistent within codebase
- Length proportional to scope
### Variables
```
# Bad
d = 86400 # What is this?
temp = getUserData() # Temp what?
# Good
secondsPerDay = 86400
userData = getUserData()
```
### Functions/Methods
- Use verbs for actions: `calculateTotal()`, `validateInput()`
- Use `is/has/can` for booleans: `isValid()`, `hasPermission()`
- Be specific: `sendEmailNotification()` not `send()`
### Constants
- Use SCREAMING_SNAKE_CASE or language convention
- Group related constants
- Document magic numbers
### Classes/Types
- Use nouns: `User`, `OrderProcessor`, `ValidationResult`
- Avoid generic names: `Manager`, `Handler`, `Data`
## Comments
### When to Comment
- WHY, not WHAT (code shows what, comments explain why)
- Complex algorithms or business logic
- Non-obvious workarounds with references
- Public API documentation
### When NOT to Comment
- Obvious code
- Commented-out code (delete it)
- Change history (use git)
- TODOs without tickets (create tickets instead)
### Comment Quality
```
# Bad
i += 1 # Increment i
# Good
# Retry limit based on SLA requirements (see JIRA-1234)
maxRetries = 3
```
## Error Handling
### Principles
- Fail fast and explicitly
- Handle errors at appropriate level
- Preserve error context
- Log for debugging, throw for callers
### Patterns
```
# Bad: Silent failure
try:
result = riskyOperation()
except:
pass
# Good: Explicit handling
try:
result = riskyOperation()
except SpecificError as e:
logger.error(f"Operation failed: {e}")
raise OperationFailed("Unable to complete operation") from e
```
### Error Messages
- Be specific about what failed
- Include relevant context
- Suggest remediation when possible
- Avoid exposing internal details to users
## Functions and Methods
### Single Responsibility
- One function = one task
- If you need "and" to describe it, split it
- Extract helper functions for clarity
### Parameters
- Limit parameters (ideally ≤ 3)
- Use objects/structs for many parameters
- Avoid boolean parameters (use named options)
- Order: required first, optional last
### Return Values
- Return early for edge cases
- Consistent return types
- Avoid returning null/nil when possible
- Consider Result/Option types for failures
## Code Organization
### File Structure
- One primary concept per file
- Related helpers in same file or nearby
- Consistent file naming
- Logical directory structure
### Import/Dependency Order
1. Standard library
2. External dependencies
3. Internal dependencies
4. Local/relative imports
### Coupling and Cohesion
- High cohesion within modules
- Low coupling between modules
- Depend on abstractions, not implementations
- Avoid circular dependencies
## Testing Considerations
### Testable Code
- Pure functions where possible
- Dependency injection
- Avoid global state
- Small, focused functions
### Test Naming
```
# Describe behavior, not implementation
test_user_can_login_with_valid_credentials()
test_order_total_includes_tax_and_shipping()
```
## Security Basics
### Input Validation
- Validate all external input
- Sanitize before use
- Whitelist over blacklist
- Fail closed (deny by default)
### Secrets
- Never hardcode secrets
- Use environment variables or secret managers
- Don't log sensitive data
- Rotate credentials regularly
### Data Handling
- Minimize data collection
- Encrypt sensitive data
- Secure data in transit and at rest
- Follow principle of least privilege
## Performance Mindset
### Premature Optimization
- Make it work, then make it fast
- Measure before optimizing
- Optimize bottlenecks, not everything
- Document performance-critical code
### Common Pitfalls
- N+1 queries
- Unnecessary allocations in loops
- Missing indexes
- Synchronous operations that could be async
## Code Review Checklist
- [ ] Does it work correctly?
- [ ] Is it readable and maintainable?
- [ ] Are edge cases handled?
- [ ] Is error handling appropriate?
- [ ] Are there security concerns?
- [ ] Is it tested adequately?
- [ ] Does it follow project conventions?
- [ ] Is there unnecessary complexity?

View File

@@ -0,0 +1,562 @@
# Go Style Guide
Go idioms and conventions for clean, maintainable code.
## gofmt and Standard Formatting
### Always Use gofmt
```bash
# Format a single file
gofmt -w file.go
# Format entire project
gofmt -w .
# Use goimports for imports management
goimports -w .
```
### Formatting Rules (Enforced by gofmt)
- Tabs for indentation
- No trailing whitespace
- Consistent brace placement
- Standardized spacing
## Error Handling
### Explicit Error Checking
```go
// Always check errors explicitly
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("opening file %s: %w", filename, err)
}
defer file.Close()
// Don't ignore errors with _
// Bad
data, _ := json.Marshal(obj)
// Good
data, err := json.Marshal(obj)
if err != nil {
return nil, fmt.Errorf("marshaling object: %w", err)
}
```
### Error Wrapping
```go
// Use %w to wrap errors for unwrapping later
func processFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("reading file %s: %w", path, err)
}
if err := validate(data); err != nil {
return fmt.Errorf("validating data: %w", err)
}
return nil
}
// Check wrapped errors
if errors.Is(err, os.ErrNotExist) {
// Handle file not found
}
var validationErr *ValidationError
if errors.As(err, &validationErr) {
// Handle validation error
}
```
### Custom Error Types
```go
// Sentinel errors for expected conditions
var (
ErrNotFound = errors.New("resource not found")
ErrUnauthorized = errors.New("unauthorized access")
ErrInvalidInput = errors.New("invalid input")
)
// Custom error type with additional context
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}
// Error constructor
func NewValidationError(field, message string) error {
return &ValidationError{Field: field, Message: message}
}
```
## Interfaces
### Small, Focused Interfaces
```go
// Good: Single-method interface
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Compose interfaces
type ReadWriter interface {
Reader
Writer
}
// Bad: Large interfaces
type Repository interface {
Find(id string) (*User, error)
FindAll() ([]*User, error)
Create(user *User) error
Update(user *User) error
Delete(id string) error
FindByEmail(email string) (*User, error)
// Too many methods - hard to implement and test
}
```
### Accept Interfaces, Return Structs
```go
// Good: Accept interface, return concrete type
func NewUserService(repo UserRepository) *UserService {
return &UserService{repo: repo}
}
// Interface defined by consumer
type UserRepository interface {
Find(ctx context.Context, id string) (*User, error)
Save(ctx context.Context, user *User) error
}
// Concrete implementation
type PostgresUserRepo struct {
db *sql.DB
}
func (r *PostgresUserRepo) Find(ctx context.Context, id string) (*User, error) {
// Implementation
}
```
### Interface Naming
```go
// Single-method interfaces: method name + "er"
type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type Closer interface { Close() error }
type Stringer interface { String() string }
// Multi-method interfaces: descriptive name
type UserStore interface {
Get(ctx context.Context, id string) (*User, error)
Put(ctx context.Context, user *User) error
}
```
## Package Structure
### Standard Layout
```
myproject/
├── cmd/
│ └── myapp/
│ └── main.go # Application entry point
├── internal/
│ ├── auth/
│ │ ├── auth.go
│ │ └── auth_test.go
│ ├── user/
│ │ ├── user.go
│ │ ├── repository.go
│ │ └── service.go
│ └── config/
│ └── config.go
├── pkg/ # Public packages (optional)
│ └── api/
│ └── client.go
├── go.mod
├── go.sum
└── README.md
```
### Package Guidelines
```go
// Package names: short, lowercase, no underscores
package user // Good
package userService // Bad
package user_service // Bad
// Package comment at top of primary file
// Package user provides user management functionality.
package user
// Group imports: stdlib, external, internal
import (
"context"
"fmt"
"github.com/google/uuid"
"github.com/lib/pq"
"myproject/internal/config"
)
```
### Internal Packages
```go
// internal/ packages cannot be imported from outside the module
// Use for implementation details you don't want to expose
// myproject/internal/cache/cache.go
package cache
// This can only be imported by code in myproject/
```
## Testing
### Test File Organization
```go
// user_test.go - same package
package user
import (
"testing"
)
func TestUserValidation(t *testing.T) {
// Test implementation details
}
// user_integration_test.go - external test package
package user_test
import (
"testing"
"myproject/internal/user"
)
func TestUserService(t *testing.T) {
// Test public API
}
```
### Table-Driven Tests
```go
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -1, -2},
{"mixed numbers", -1, 5, 4},
{"zeros", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}
```
### Test Helpers
```go
// Helper functions should call t.Helper()
func newTestUser(t *testing.T) *User {
t.Helper()
return &User{
ID: uuid.New().String(),
Name: "Test User",
Email: "test@example.com",
}
}
func assertNoError(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func assertEqual[T comparable](t *testing.T, got, want T) {
t.Helper()
if got != want {
t.Errorf("got %v; want %v", got, want)
}
}
```
### Mocking with Interfaces
```go
// Define interface for dependency
type UserRepository interface {
Find(ctx context.Context, id string) (*User, error)
Save(ctx context.Context, user *User) error
}
// Mock implementation for testing
type mockUserRepo struct {
users map[string]*User
}
func newMockUserRepo() *mockUserRepo {
return &mockUserRepo{users: make(map[string]*User)}
}
func (m *mockUserRepo) Find(ctx context.Context, id string) (*User, error) {
user, ok := m.users[id]
if !ok {
return nil, ErrNotFound
}
return user, nil
}
func (m *mockUserRepo) Save(ctx context.Context, user *User) error {
m.users[user.ID] = user
return nil
}
// Test using mock
func TestUserService_GetUser(t *testing.T) {
repo := newMockUserRepo()
repo.users["123"] = &User{ID: "123", Name: "Test"}
service := NewUserService(repo)
user, err := service.GetUser(context.Background(), "123")
assertNoError(t, err)
assertEqual(t, user.Name, "Test")
}
```
## Common Patterns
### Options Pattern
```go
// Option function type
type ServerOption func(*Server)
// Option functions
func WithPort(port int) ServerOption {
return func(s *Server) {
s.port = port
}
}
func WithTimeout(timeout time.Duration) ServerOption {
return func(s *Server) {
s.timeout = timeout
}
}
func WithLogger(logger *slog.Logger) ServerOption {
return func(s *Server) {
s.logger = logger
}
}
// Constructor using options
func NewServer(opts ...ServerOption) *Server {
s := &Server{
port: 8080, // defaults
timeout: 30 * time.Second,
logger: slog.Default(),
}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
server := NewServer(
WithPort(9000),
WithTimeout(time.Minute),
)
```
### Context Usage
```go
// Always pass context as first parameter
func (s *Service) ProcessRequest(ctx context.Context, req *Request) (*Response, error) {
// Check for cancellation
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
// Use context for timeouts
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
result, err := s.repo.Find(ctx, req.ID)
if err != nil {
return nil, fmt.Errorf("finding item: %w", err)
}
return &Response{Data: result}, nil
}
```
### Defer for Cleanup
```go
func processFile(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close() // Always executed on return
// Process file...
return nil
}
// Multiple defers execute in LIFO order
func transaction(db *sql.DB) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback() // Safe: no-op if committed
// Do work...
return tx.Commit()
}
```
### Concurrency Patterns
```go
// Worker pool
func processItems(items []Item, workers int) []Result {
jobs := make(chan Item, len(items))
results := make(chan Result, len(items))
// Start workers
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for item := range jobs {
results <- process(item)
}
}()
}
// Send jobs
for _, item := range items {
jobs <- item
}
close(jobs)
// Wait and collect
go func() {
wg.Wait()
close(results)
}()
var out []Result
for r := range results {
out = append(out, r)
}
return out
}
```
## Code Quality
### Linting with golangci-lint
```yaml
# .golangci.yml
linters:
enable:
- errcheck
- govet
- ineffassign
- staticcheck
- unused
- gosimple
- gocritic
- gofmt
- goimports
linters-settings:
govet:
check-shadowing: true
errcheck:
check-type-assertions: true
issues:
exclude-rules:
- path: _test\.go
linters:
- errcheck
```
### Common Commands
```bash
# Format code
go fmt ./...
# Run linter
golangci-lint run
# Run tests
go test ./...
# Run tests with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Check for race conditions
go test -race ./...
# Build
go build ./...
```

View File

@@ -0,0 +1,618 @@
# HTML & CSS Style Guide
Web standards for semantic markup, maintainable styling, and accessibility.
## Semantic HTML
### Document Structure
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Page description for SEO" />
<title>Page Title | Site Name</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header>
<nav aria-label="Main navigation">
<!-- Navigation -->
</nav>
</header>
<main>
<article>
<!-- Primary content -->
</article>
<aside>
<!-- Supplementary content -->
</aside>
</main>
<footer>
<!-- Footer content -->
</footer>
</body>
</html>
```
### Semantic Elements
```html
<!-- Use appropriate semantic elements -->
<!-- Navigation -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<!-- Article with header and footer -->
<article>
<header>
<h1>Article Title</h1>
<time datetime="2024-01-15">January 15, 2024</time>
</header>
<p>Article content...</p>
<footer>
<p>Written by <address>Author Name</address></p>
</footer>
</article>
<!-- Sections with headings -->
<section aria-labelledby="features-heading">
<h2 id="features-heading">Features</h2>
<p>Section content...</p>
</section>
<!-- Figures with captions -->
<figure>
<img src="chart.png" alt="Sales data showing 20% growth">
<figcaption>Q4 2024 Sales Performance</figcaption>
</figure>
<!-- Definition lists -->
<dl>
<dt>HTML</dt>
<dd>HyperText Markup Language</dd>
<dt>CSS</dt>
<dd>Cascading Style Sheets</dd>
</dl>
```
### Form Elements
```html
<form action="/submit" method="POST">
<!-- Text input with label -->
<div class="form-group">
<label for="email">Email Address</label>
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
aria-describedby="email-hint"
/>
<span id="email-hint" class="hint">We'll never share your email.</span>
</div>
<!-- Select with label -->
<div class="form-group">
<label for="country">Country</label>
<select id="country" name="country" required>
<option value="">Select a country</option>
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
</select>
</div>
<!-- Radio group with fieldset -->
<fieldset>
<legend>Preferred Contact Method</legend>
<div>
<input type="radio" id="contact-email" name="contact" value="email" />
<label for="contact-email">Email</label>
</div>
<div>
<input type="radio" id="contact-phone" name="contact" value="phone" />
<label for="contact-phone">Phone</label>
</div>
</fieldset>
<!-- Submit button -->
<button type="submit">Submit</button>
</form>
```
## BEM Naming Convention
### Block, Element, Modifier
```css
/* Block: Standalone component */
.card {
}
/* Element: Part of block (double underscore) */
.card__header {
}
.card__body {
}
.card__footer {
}
/* Modifier: Variation (double hyphen) */
.card--featured {
}
.card--compact {
}
.card__header--centered {
}
```
### BEM Examples
```html
<!-- Card component -->
<article class="card card--featured">
<header class="card__header">
<h2 class="card__title">Card Title</h2>
</header>
<div class="card__body">
<p class="card__text">Card content goes here.</p>
</div>
<footer class="card__footer">
<button class="card__button card__button--primary">Action</button>
</footer>
</article>
<!-- Navigation component -->
<nav class="nav nav--horizontal">
<ul class="nav__list">
<li class="nav__item nav__item--active">
<a class="nav__link" href="/">Home</a>
</li>
<li class="nav__item">
<a class="nav__link" href="/about">About</a>
</li>
</ul>
</nav>
```
### BEM Best Practices
```css
/* Avoid deep nesting */
/* Bad */
.card__header__title__icon {
}
/* Good - flatten structure */
.card__title-icon {
}
/* Avoid styling elements without class */
/* Bad */
.card h2 {
}
/* Good */
.card__title {
}
/* Modifiers extend base styles */
.button {
padding: 8px 16px;
border-radius: 4px;
}
.button--large {
padding: 12px 24px;
}
.button--primary {
background: blue;
color: white;
}
```
## Accessibility
### ARIA Attributes
```html
<!-- Live regions for dynamic content -->
<div aria-live="polite" aria-atomic="true">Status updates appear here</div>
<!-- Landmarks -->
<nav aria-label="Main navigation"></nav>
<nav aria-label="Footer navigation"></nav>
<!-- Current page in navigation -->
<a href="/about" aria-current="page">About</a>
<!-- Expanded/collapsed state -->
<button aria-expanded="false" aria-controls="menu">Toggle Menu</button>
<div id="menu" hidden>Menu content</div>
<!-- Disabled vs aria-disabled -->
<button disabled>Can't click (removed from tab order)</button>
<button aria-disabled="true">Can't click (stays in tab order)</button>
<!-- Loading states -->
<button aria-busy="true">
<span aria-hidden="true">Loading...</span>
<span class="visually-hidden">Please wait</span>
</button>
```
### Keyboard Navigation
```html
<!-- Skip link -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Focusable elements should be obvious -->
<style>
:focus-visible {
outline: 2px solid blue;
outline-offset: 2px;
}
</style>
<!-- Tabindex usage -->
<!-- tabindex="0": Add to tab order -->
<div tabindex="0" role="button">Custom button</div>
<!-- tabindex="-1": Programmatically focusable only -->
<div id="modal" tabindex="-1">Modal content</div>
<!-- Never use tabindex > 0 -->
```
### Screen Reader Support
```css
/* Visually hidden but accessible */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Hide from screen readers */
[aria-hidden="true"] {
/* Decorative content */
}
```
```html
<!-- Icon buttons need accessible names -->
<button aria-label="Close dialog">
<svg aria-hidden="true"><!-- icon --></svg>
</button>
<!-- Decorative images -->
<img src="decoration.png" alt="" role="presentation" />
<!-- Informative images -->
<img src="chart.png" alt="Sales increased 20% in Q4 2024" />
<!-- Complex images -->
<figure>
<img
src="flowchart.png"
alt="User registration process"
aria-describedby="flowchart-desc"
/>
<figcaption id="flowchart-desc">
Step 1: Enter email. Step 2: Verify email. Step 3: Create password.
</figcaption>
</figure>
```
## Responsive Design
### Mobile-First Approach
```css
/* Base styles for mobile */
.container {
padding: 16px;
}
.grid {
display: grid;
gap: 16px;
grid-template-columns: 1fr;
}
/* Tablet and up */
@media (min-width: 768px) {
.container {
padding: 24px;
}
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Desktop and up */
@media (min-width: 1024px) {
.container {
padding: 32px;
max-width: 1200px;
margin: 0 auto;
}
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
```
### Flexible Units
```css
/* Use relative units */
body {
font-size: 16px; /* Base size */
}
h1 {
font-size: 2rem; /* Relative to root */
margin-bottom: 1em; /* Relative to element */
}
.container {
max-width: 75ch; /* Character width for readability */
padding: 1rem;
}
/* Fluid typography */
h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
}
/* Fluid spacing */
.section {
padding: clamp(2rem, 5vw, 4rem);
}
```
### Responsive Images
```html
<!-- Responsive image with srcset -->
<img
src="image-800.jpg"
srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Description"
loading="lazy"
/>
<!-- Art direction with picture -->
<picture>
<source media="(min-width: 1024px)" srcset="hero-desktop.jpg" />
<source media="(min-width: 768px)" srcset="hero-tablet.jpg" />
<img src="hero-mobile.jpg" alt="Hero image" />
</picture>
```
## CSS Best Practices
### Custom Properties (CSS Variables)
```css
:root {
/* Colors */
--color-primary: #0066cc;
--color-primary-dark: #004c99;
--color-secondary: #6c757d;
--color-success: #28a745;
--color-error: #dc3545;
/* Typography */
--font-family-base: system-ui, sans-serif;
--font-family-mono: ui-monospace, monospace;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
/* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* Borders */
--border-radius: 4px;
--border-color: #dee2e6;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--color-primary: #4da6ff;
--color-background: #1a1a1a;
--color-text: #ffffff;
}
}
/* Usage */
.button {
background: var(--color-primary);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius);
}
```
### Modern Layout
```css
/* Flexbox for 1D layouts */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--spacing-md);
}
/* Grid for 2D layouts */
.page-layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header {
grid-area: header;
}
.sidebar {
grid-area: sidebar;
}
.main {
grid-area: main;
}
.footer {
grid-area: footer;
}
/* Auto-fit grid */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-lg);
}
```
### Performance
```css
/* Avoid expensive properties in animations */
/* Bad - triggers layout */
.animate-bad {
animation: move 1s;
}
@keyframes move {
to {
left: 100px;
top: 100px;
}
}
/* Good - uses transform */
.animate-good {
animation: move-optimized 1s;
}
@keyframes move-optimized {
to {
transform: translate(100px, 100px);
}
}
/* Use will-change sparingly */
.will-animate {
will-change: transform;
}
/* Contain for layout isolation */
.card {
contain: layout style;
}
/* Content-visibility for off-screen content */
.below-fold {
content-visibility: auto;
contain-intrinsic-size: 500px;
}
```
## HTML Best Practices
### Validation and Attributes
```html
<!-- Use proper input types -->
<input type="email" autocomplete="email" />
<input type="tel" autocomplete="tel" />
<input type="url" />
<input type="number" min="0" max="100" step="1" />
<input type="date" min="2024-01-01" />
<!-- Required and validation -->
<input type="text" required minlength="2" maxlength="50" pattern="[A-Za-z]+" />
<!-- Autocomplete for better UX -->
<input type="text" name="name" autocomplete="name" />
<input type="text" name="address" autocomplete="street-address" />
<input type="text" name="cc-number" autocomplete="cc-number" />
```
### Performance Attributes
```html
<!-- Lazy loading -->
<img src="image.jpg" loading="lazy" alt="Description" />
<iframe src="video.html" loading="lazy"></iframe>
<!-- Preload critical resources -->
<link rel="preload" href="critical.css" as="style" />
<link rel="preload" href="hero.jpg" as="image" />
<link rel="preload" href="font.woff2" as="font" crossorigin />
<!-- Preconnect to origins -->
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://analytics.example.com" />
<!-- Async/defer scripts -->
<script src="analytics.js" async></script>
<script src="app.js" defer></script>
```
### Microdata and SEO
```html
<!-- Schema.org markup -->
<article itemscope itemtype="https://schema.org/Article">
<h1 itemprop="headline">Article Title</h1>
<time itemprop="datePublished" datetime="2024-01-15"> January 15, 2024 </time>
<div itemprop="author" itemscope itemtype="https://schema.org/Person">
<span itemprop="name">Author Name</span>
</div>
<div itemprop="articleBody">Article content...</div>
</article>
<!-- Open Graph for social sharing -->
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Page description" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:url" content="https://example.com/page" />
```

View File

@@ -0,0 +1,569 @@
# JavaScript Style Guide
Modern JavaScript (ES6+) best practices and conventions.
## ES6+ Features
### Use Modern Syntax
```javascript
// Prefer const and let over var
const immutableValue = "fixed";
let mutableValue = "can change";
// Never use var
// var outdated = 'avoid this';
// Template literals over concatenation
const greeting = `Hello, ${name}!`;
// Destructuring
const { id, name, email } = user;
const [first, second, ...rest] = items;
// Spread operator
const merged = { ...defaults, ...options };
const combined = [...array1, ...array2];
// Arrow functions for short callbacks
const doubled = numbers.map((n) => n * 2);
```
### Object Shorthand
```javascript
// Property shorthand
const name = "John";
const age = 30;
const user = { name, age };
// Method shorthand
const calculator = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
},
};
// Computed property names
const key = "dynamic";
const obj = {
[key]: "value",
[`${key}Method`]() {
return "result";
},
};
```
### Default Parameters and Rest
```javascript
// Default parameters
function greet(name = "Guest", greeting = "Hello") {
return `${greeting}, ${name}!`;
}
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
// Named parameters via destructuring
function createUser({ name, email, role = "user" }) {
return { name, email, role, createdAt: new Date() };
}
```
## Async/Await
### Prefer async/await Over Promises
```javascript
// Bad: Promise chains
function fetchUserPosts(userId) {
return fetch(`/users/${userId}`)
.then((res) => res.json())
.then((user) => fetch(`/posts?userId=${user.id}`))
.then((res) => res.json());
}
// Good: async/await
async function fetchUserPosts(userId) {
const userRes = await fetch(`/users/${userId}`);
const user = await userRes.json();
const postsRes = await fetch(`/posts?userId=${user.id}`);
return postsRes.json();
}
```
### Parallel Execution
```javascript
// Sequential (slow)
async function loadDataSequentially() {
const users = await fetchUsers();
const posts = await fetchPosts();
const comments = await fetchComments();
return { users, posts, comments };
}
// Parallel (fast)
async function loadDataParallel() {
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments(),
]);
return { users, posts, comments };
}
```
### Error Handling
```javascript
// try/catch with async/await
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("Fetch failed:", error.message);
throw error;
}
}
// Error handling utility
async function safeAsync(promise) {
try {
const result = await promise;
return [result, null];
} catch (error) {
return [null, error];
}
}
// Usage
const [data, error] = await safeAsync(fetchData("/api/users"));
if (error) {
handleError(error);
}
```
## Error Handling
### Custom Errors
```javascript
class AppError extends Error {
constructor(message, code, statusCode = 500) {
super(message);
this.name = "AppError";
this.code = code;
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor);
}
}
class ValidationError extends AppError {
constructor(message, field) {
super(message, "VALIDATION_ERROR", 400);
this.name = "ValidationError";
this.field = field;
}
}
class NotFoundError extends AppError {
constructor(resource, id) {
super(`${resource} with id ${id} not found`, "NOT_FOUND", 404);
this.name = "NotFoundError";
this.resource = resource;
this.resourceId = id;
}
}
```
### Error Handling Patterns
```javascript
// Centralized error handler
function handleError(error) {
if (error instanceof ValidationError) {
showFieldError(error.field, error.message);
} else if (error instanceof NotFoundError) {
showNotFound(error.resource);
} else {
showGenericError("Something went wrong");
reportError(error);
}
}
// Error boundary pattern (for React)
function withErrorBoundary(Component) {
return class extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
reportError(error, info);
}
render() {
if (this.state.hasError) {
return <ErrorFallback />;
}
return <Component {...this.props} />;
}
};
}
```
## Module Patterns
### ES Modules
```javascript
// Named exports
export const API_URL = "/api";
export function fetchData(endpoint) {
/* ... */
}
export class ApiClient {
/* ... */
}
// Re-exports
export { User, Post } from "./types.js";
export * as utils from "./utils.js";
// Imports
import { fetchData, API_URL } from "./api.js";
import * as api from "./api.js";
import defaultExport from "./module.js";
```
### Module Organization
```javascript
// Feature-based organization
// features/user/
// index.js - Public exports
// api.js - API calls
// utils.js - Helper functions
// constants.js - Feature constants
// index.js - Barrel export
export { UserService } from "./service.js";
export { validateUser } from "./utils.js";
export { USER_ROLES } from "./constants.js";
```
### Dependency Injection
```javascript
// Constructor injection
class UserService {
constructor(apiClient, logger) {
this.api = apiClient;
this.logger = logger;
}
async getUser(id) {
this.logger.info(`Fetching user ${id}`);
return this.api.get(`/users/${id}`);
}
}
// Factory function
function createUserService(config = {}) {
const api = config.apiClient || new ApiClient();
const logger = config.logger || console;
return new UserService(api, logger);
}
```
## Functional Patterns
### Pure Functions
```javascript
// Impure: Modifies external state
let count = 0;
function incrementCount() {
count++;
return count;
}
// Pure: No side effects
function increment(value) {
return value + 1;
}
// Pure: Same input = same output
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
```
### Array Methods
```javascript
const users = [
{ id: 1, name: "Alice", active: true },
{ id: 2, name: "Bob", active: false },
{ id: 3, name: "Charlie", active: true },
];
// map - transform
const names = users.map((user) => user.name);
// filter - select
const activeUsers = users.filter((user) => user.active);
// find - first match
const user = users.find((user) => user.id === 2);
// some/every - boolean check
const hasActive = users.some((user) => user.active);
const allActive = users.every((user) => user.active);
// reduce - accumulate
const userMap = users.reduce((map, user) => {
map[user.id] = user;
return map;
}, {});
// Chaining
const activeNames = users
.filter((user) => user.active)
.map((user) => user.name)
.sort();
```
### Composition
```javascript
// Compose functions
const compose =
(...fns) =>
(x) =>
fns.reduceRight((acc, fn) => fn(acc), x);
const pipe =
(...fns) =>
(x) =>
fns.reduce((acc, fn) => fn(acc), x);
// Usage
const processUser = pipe(validateUser, normalizeUser, enrichUser);
const result = processUser(rawUserData);
```
## Classes
### Modern Class Syntax
```javascript
class User {
// Private fields
#password;
// Static properties
static ROLES = ["admin", "user", "guest"];
constructor(name, email) {
this.name = name;
this.email = email;
this.#password = null;
}
// Getter
get displayName() {
return `${this.name} <${this.email}>`;
}
// Setter
set password(value) {
if (value.length < 8) {
throw new Error("Password too short");
}
this.#password = hashPassword(value);
}
// Instance method
toJSON() {
return { name: this.name, email: this.email };
}
// Static method
static fromJSON(json) {
return new User(json.name, json.email);
}
}
```
### Inheritance
```javascript
class Entity {
constructor(id) {
this.id = id;
this.createdAt = new Date();
}
equals(other) {
return other instanceof Entity && this.id === other.id;
}
}
class User extends Entity {
constructor(id, name, email) {
super(id);
this.name = name;
this.email = email;
}
toJSON() {
return {
id: this.id,
name: this.name,
email: this.email,
createdAt: this.createdAt.toISOString(),
};
}
}
```
## Common Patterns
### Null Safety
```javascript
// Optional chaining
const city = user?.address?.city;
const firstItem = items?.[0];
const result = obj?.method?.();
// Nullish coalescing
const name = user.name ?? "Anonymous";
const count = value ?? 0;
// Combining both
const displayName = user?.profile?.name ?? "Unknown";
```
### Debounce and Throttle
```javascript
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
function throttle(fn, limit) {
let inThrottle;
return function (...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
```
### Memoization
```javascript
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// Usage
const expensiveCalculation = memoize((n) => {
// Complex computation
return fibonacci(n);
});
```
## Best Practices
### Avoid Common Pitfalls
```javascript
// Avoid loose equality
// Bad
if (value == null) {
}
// Good
if (value === null || value === undefined) {
}
if (value == null) {
} // Only acceptable for null/undefined check
// Avoid implicit type coercion
// Bad
if (items.length) {
}
// Good
if (items.length > 0) {
}
// Avoid modifying function arguments
// Bad
function process(options) {
options.processed = true;
return options;
}
// Good
function process(options) {
return { ...options, processed: true };
}
```
### Performance Tips
```javascript
// Avoid creating functions in loops
// Bad
items.forEach(function (item) {
item.addEventListener("click", function () {});
});
// Good
function handleClick(event) {}
items.forEach((item) => {
item.addEventListener("click", handleClick);
});
// Use appropriate data structures
// For frequent lookups, use Map/Set instead of Array
const userMap = new Map(users.map((u) => [u.id, u]));
const userIds = new Set(users.map((u) => u.id));
```

View File

@@ -0,0 +1,566 @@
# Python Style Guide
Python conventions following PEP 8 and modern best practices.
## PEP 8 Fundamentals
### Naming Conventions
```python
# Variables and functions: snake_case
user_name = "John"
def calculate_total(items):
pass
# Constants: SCREAMING_SNAKE_CASE
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT = 30
# Classes: PascalCase
class UserAccount:
pass
# Private: single underscore prefix
class User:
def __init__(self):
self._internal_state = {}
# Name mangling: double underscore prefix
class Base:
def __init__(self):
self.__private = "truly private"
# Module-level "private": single underscore
_module_cache = {}
```
### Indentation and Line Length
```python
# 4 spaces per indentation level
def function():
if condition:
do_something()
# Line length: 88 characters (Black) or 79 (PEP 8)
# Break long lines appropriately
result = some_function(
argument_one,
argument_two,
argument_three,
)
# Implicit line continuation in brackets
users = [
"alice",
"bob",
"charlie",
]
```
### Imports
```python
# Standard library
import os
import sys
from pathlib import Path
from typing import Optional, List
# Third-party
import requests
from pydantic import BaseModel
# Local application
from myapp.models import User
from myapp.utils import format_date
# Avoid wildcard imports
# Bad: from module import *
# Good: from module import specific_item
```
## Type Hints
### Basic Type Annotations
```python
from typing import Optional, List, Dict, Tuple, Union, Any
# Variables
name: str = "John"
age: int = 30
active: bool = True
scores: List[int] = [90, 85, 92]
# Functions
def greet(name: str) -> str:
return f"Hello, {name}!"
def find_user(user_id: int) -> Optional[User]:
"""Returns User or None if not found."""
pass
def process_items(items: List[str]) -> Dict[str, int]:
"""Returns count of each item."""
pass
```
### Advanced Type Hints
```python
from typing import (
TypeVar, Generic, Protocol, Callable,
Literal, TypedDict, Final
)
# TypeVar for generics
T = TypeVar('T')
def first(items: List[T]) -> Optional[T]:
return items[0] if items else None
# Protocol for structural typing
class Renderable(Protocol):
def render(self) -> str: ...
def display(obj: Renderable) -> None:
print(obj.render())
# Literal for specific values
Status = Literal["pending", "active", "completed"]
def set_status(status: Status) -> None:
pass
# TypedDict for dictionary shapes
class UserDict(TypedDict):
id: int
name: str
email: Optional[str]
# Final for constants
MAX_SIZE: Final = 100
```
### Type Hints in Classes
```python
from dataclasses import dataclass
from typing import ClassVar, Self
@dataclass
class User:
id: int
name: str
email: str
active: bool = True
# Class variable
_instances: ClassVar[Dict[int, 'User']] = {}
def deactivate(self) -> Self:
self.active = False
return self
class Builder:
def __init__(self) -> None:
self._value: str = ""
def append(self, text: str) -> Self:
self._value += text
return self
```
## Docstrings
### Function Docstrings
```python
def calculate_discount(
price: float,
discount_percent: float,
min_price: float = 0.0
) -> float:
"""Calculate the discounted price.
Args:
price: Original price of the item.
discount_percent: Discount percentage (0-100).
min_price: Minimum price floor. Defaults to 0.0.
Returns:
The discounted price, not less than min_price.
Raises:
ValueError: If discount_percent is not between 0 and 100.
Example:
>>> calculate_discount(100.0, 20.0)
80.0
"""
if not 0 <= discount_percent <= 100:
raise ValueError("Discount must be between 0 and 100")
discounted = price * (1 - discount_percent / 100)
return max(discounted, min_price)
```
### Class Docstrings
```python
class UserService:
"""Service for managing user operations.
This service handles user CRUD operations and authentication.
It requires a database connection and optional cache.
Attributes:
db: Database connection instance.
cache: Optional cache for user lookups.
Example:
>>> service = UserService(db_connection)
>>> user = service.get_user(123)
"""
def __init__(
self,
db: DatabaseConnection,
cache: Optional[Cache] = None
) -> None:
"""Initialize the UserService.
Args:
db: Active database connection.
cache: Optional cache instance for performance.
"""
self.db = db
self.cache = cache
```
## Virtual Environments
### Setup Commands
```bash
# Create virtual environment
python -m venv .venv
# Activate (Unix/macOS)
source .venv/bin/activate
# Activate (Windows)
.venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Freeze dependencies
pip freeze > requirements.txt
```
### Modern Tools
```bash
# Using uv (recommended)
uv venv
uv pip install -r requirements.txt
# Using poetry
poetry init
poetry add requests
poetry install
# Using pipenv
pipenv install
pipenv install requests
```
### Project Structure
```
project/
├── .venv/ # Virtual environment (gitignored)
├── src/
│ └── myapp/
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ └── test_main.py
├── pyproject.toml # Modern project config
├── requirements.txt # Pinned dependencies
└── README.md
```
## Testing
### pytest Basics
```python
import pytest
from myapp.calculator import add, divide
def test_add_positive_numbers():
assert add(2, 3) == 5
def test_add_negative_numbers():
assert add(-1, -1) == -2
def test_divide_by_zero_raises():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
# Parametrized tests
@pytest.mark.parametrize("a,b,expected", [
(1, 1, 2),
(0, 0, 0),
(-1, 1, 0),
])
def test_add_parametrized(a, b, expected):
assert add(a, b) == expected
```
### Fixtures
```python
import pytest
from myapp.database import Database
from myapp.models import User
@pytest.fixture
def db():
"""Provide a clean database for each test."""
database = Database(":memory:")
database.create_tables()
yield database
database.close()
@pytest.fixture
def sample_user(db):
"""Create a sample user in the database."""
user = User(name="Test User", email="test@example.com")
db.save(user)
return user
def test_user_creation(db, sample_user):
found = db.find_user(sample_user.id)
assert found.name == "Test User"
```
### Mocking
```python
from unittest.mock import Mock, patch, MagicMock
import pytest
def test_api_client_with_mock():
# Create mock
mock_response = Mock()
mock_response.json.return_value = {"id": 1, "name": "Test"}
mock_response.status_code = 200
with patch('requests.get', return_value=mock_response) as mock_get:
result = fetch_user(1)
mock_get.assert_called_once_with('/users/1')
assert result['name'] == "Test"
@patch('myapp.service.external_api')
def test_with_patch_decorator(mock_api):
mock_api.get_data.return_value = {"status": "ok"}
result = process_data()
assert result["status"] == "ok"
```
## Error Handling
### Exception Patterns
```python
# Define custom exceptions
class AppError(Exception):
"""Base exception for application errors."""
pass
class ValidationError(AppError):
"""Raised when validation fails."""
def __init__(self, field: str, message: str):
self.field = field
self.message = message
super().__init__(f"{field}: {message}")
class NotFoundError(AppError):
"""Raised when a resource is not found."""
def __init__(self, resource: str, identifier: Any):
self.resource = resource
self.identifier = identifier
super().__init__(f"{resource} '{identifier}' not found")
```
### Exception Handling
```python
def get_user(user_id: int) -> User:
try:
user = db.find_user(user_id)
if user is None:
raise NotFoundError("User", user_id)
return user
except DatabaseError as e:
logger.error(f"Database error: {e}")
raise AppError("Unable to fetch user") from e
# Context managers for cleanup
from contextlib import contextmanager
@contextmanager
def database_transaction(db):
try:
yield db
db.commit()
except Exception:
db.rollback()
raise
```
## Common Patterns
### Dataclasses
```python
from dataclasses import dataclass, field
from typing import List, Optional
from datetime import datetime
@dataclass
class User:
id: int
name: str
email: str
active: bool = True
created_at: datetime = field(default_factory=datetime.now)
tags: List[str] = field(default_factory=list)
def __post_init__(self):
self.email = self.email.lower()
@dataclass(frozen=True)
class Point:
"""Immutable point."""
x: float
y: float
def distance_to(self, other: 'Point') -> float:
return ((self.x - other.x)**2 + (self.y - other.y)**2) ** 0.5
```
### Context Managers
```python
from contextlib import contextmanager
from typing import Generator
@contextmanager
def timer(name: str) -> Generator[None, None, None]:
"""Time a block of code."""
import time
start = time.perf_counter()
try:
yield
finally:
elapsed = time.perf_counter() - start
print(f"{name}: {elapsed:.3f}s")
# Usage
with timer("data processing"):
process_large_dataset()
# Class-based context manager
class DatabaseConnection:
def __init__(self, connection_string: str):
self.connection_string = connection_string
self.connection = None
def __enter__(self):
self.connection = connect(self.connection_string)
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
if self.connection:
self.connection.close()
return False # Don't suppress exceptions
```
### Decorators
```python
from functools import wraps
from typing import Callable, TypeVar, ParamSpec
import time
P = ParamSpec('P')
R = TypeVar('R')
def retry(max_attempts: int = 3, delay: float = 1.0):
"""Retry decorator with exponential backoff."""
def decorator(func: Callable[P, R]) -> Callable[P, R]:
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_attempts - 1:
time.sleep(delay * (2 ** attempt))
raise last_exception
return wrapper
return decorator
@retry(max_attempts=3, delay=0.5)
def fetch_data(url: str) -> dict:
response = requests.get(url)
response.raise_for_status()
return response.json()
```
## Code Quality Tools
### Ruff Configuration
```toml
# pyproject.toml
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = ["E501"] # Line too long (handled by formatter)
[tool.ruff.lint.isort]
known-first-party = ["myapp"]
```
### Type Checking with mypy
```toml
# pyproject.toml
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = true
```

View File

@@ -0,0 +1,451 @@
# TypeScript Style Guide
TypeScript-specific conventions and best practices for type-safe development.
## Strict Mode
### Enable Strict Configuration
```json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
```
### Benefits
- Catches errors at compile time
- Better IDE support and autocomplete
- Self-documenting code
- Easier refactoring
## Type Safety
### Avoid `any`
```typescript
// Bad
function processData(data: any): any {
return data.value;
}
// Good
interface DataItem {
value: string;
count: number;
}
function processData(data: DataItem): string {
return data.value;
}
```
### Use `unknown` for Unknown Types
```typescript
// When type is truly unknown
function parseJSON(json: string): unknown {
return JSON.parse(json);
}
// Then narrow with type guards
function isUser(obj: unknown): obj is User {
return (
typeof obj === "object" && obj !== null && "id" in obj && "name" in obj
);
}
```
### Prefer Explicit Types
```typescript
// Bad: Implicit any
const items = [];
// Good: Explicit type
const items: Item[] = [];
// Also good: Type inference when obvious
const count = 0; // number inferred
const name = "John"; // string inferred
```
## Interfaces vs Types
### Use Interfaces for Object Shapes
```typescript
// Preferred for objects
interface User {
id: string;
name: string;
email: string;
}
// Interfaces can be extended
interface AdminUser extends User {
permissions: string[];
}
// Interfaces can be augmented (declaration merging)
interface User {
avatar?: string;
}
```
### Use Types for Unions, Primitives, and Computed Types
```typescript
// Union types
type Status = "pending" | "active" | "completed";
// Primitive aliases
type UserId = string;
// Computed/mapped types
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Tuple types
type Coordinate = [number, number];
```
### Decision Guide
| Use Case | Recommendation |
| ----------------------- | -------------- |
| Object shape | `interface` |
| Union type | `type` |
| Function signature | `type` |
| Class implementation | `interface` |
| Mapped/conditional type | `type` |
| Library public API | `interface` |
## Async Patterns
### Prefer async/await
```typescript
// Bad: Callback hell
function fetchUserData(id: string, callback: (user: User) => void) {
fetch(`/users/${id}`)
.then((res) => res.json())
.then((user) => callback(user));
}
// Good: async/await
async function fetchUserData(id: string): Promise<User> {
const response = await fetch(`/users/${id}`);
return response.json();
}
```
### Error Handling in Async Code
```typescript
// Explicit error handling
async function fetchUser(id: string): Promise<User> {
try {
const response = await fetch(`/users/${id}`);
if (!response.ok) {
throw new ApiError(`Failed to fetch user: ${response.status}`);
}
return response.json();
} catch (error) {
if (error instanceof ApiError) {
throw error;
}
throw new NetworkError("Network request failed", { cause: error });
}
}
```
### Promise Types
```typescript
// Return type annotation for clarity
async function loadData(): Promise<Data[]> {
// ...
}
// Use Promise.all for parallel operations
async function loadAllData(): Promise<[Users, Posts]> {
return Promise.all([fetchUsers(), fetchPosts()]);
}
```
## Module Structure
### File Organization
```
src/
├── types/ # Shared type definitions
│ ├── user.ts
│ └── api.ts
├── utils/ # Pure utility functions
│ ├── validation.ts
│ └── formatting.ts
├── services/ # Business logic
│ ├── userService.ts
│ └── authService.ts
├── components/ # UI components (if applicable)
└── index.ts # Public API exports
```
### Export Patterns
```typescript
// Named exports (preferred)
export interface User { ... }
export function createUser(data: UserInput): User { ... }
export const DEFAULT_USER: User = { ... };
// Re-exports for public API
// index.ts
export { User, createUser } from './user';
export { type Config } from './config';
// Avoid default exports (harder to refactor)
// Bad
export default class UserService { ... }
// Good
export class UserService { ... }
```
### Import Organization
```typescript
// 1. External dependencies
import { useState, useEffect } from "react";
import { z } from "zod";
// 2. Internal absolute imports
import { ApiClient } from "@/services/api";
import { User } from "@/types";
// 3. Relative imports
import { formatDate } from "./utils";
import { UserCard } from "./UserCard";
```
## Utility Types
### Built-in Utility Types
```typescript
// Partial - all properties optional
type UpdateUser = Partial<User>;
// Required - all properties required
type CompleteUser = Required<User>;
// Pick - select properties
type UserPreview = Pick<User, "id" | "name">;
// Omit - exclude properties
type UserWithoutPassword = Omit<User, "password">;
// Record - dictionary type
type UserRoles = Record<string, Role>;
// ReturnType - extract return type
type ApiResponse = ReturnType<typeof fetchData>;
// Parameters - extract parameter types
type FetchParams = Parameters<typeof fetch>;
```
### Custom Utility Types
```typescript
// Make specific properties optional
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
// Make specific properties required
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
// Deep readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
```
## Enums and Constants
### Prefer const Objects Over Enums
```typescript
// Enums have runtime overhead
enum Status {
Pending = "pending",
Active = "active",
}
// Prefer const objects
const Status = {
Pending: "pending",
Active: "active",
} as const;
type Status = (typeof Status)[keyof typeof Status];
```
### When to Use Enums
```typescript
// Numeric enums for bit flags
enum Permissions {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Execute = 1 << 2,
All = Read | Write | Execute,
}
```
## Generics
### Basic Generic Usage
```typescript
// Generic function
function first<T>(items: T[]): T | undefined {
return items[0];
}
// Generic interface
interface Repository<T> {
find(id: string): Promise<T | null>;
save(item: T): Promise<T>;
delete(id: string): Promise<void>;
}
```
### Constraining Generics
```typescript
// Constrain to objects with id
function findById<T extends { id: string }>(
items: T[],
id: string,
): T | undefined {
return items.find((item) => item.id === id);
}
// Multiple constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
```
## Error Types
### Custom Error Classes
```typescript
class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500,
) {
super(message);
this.name = "AppError";
}
}
class ValidationError extends AppError {
constructor(
message: string,
public readonly field: string,
) {
super(message, "VALIDATION_ERROR", 400);
this.name = "ValidationError";
}
}
```
### Type Guards for Errors
```typescript
function isAppError(error: unknown): error is AppError {
return error instanceof AppError;
}
function handleError(error: unknown): void {
if (isAppError(error)) {
console.error(`[${error.code}] ${error.message}`);
} else if (error instanceof Error) {
console.error(`Unexpected error: ${error.message}`);
} else {
console.error("Unknown error occurred");
}
}
```
## Testing Types
### Type Testing
```typescript
// Use type assertions for compile-time checks
type Assert<T, U extends T> = U;
// Test that types work as expected
type _TestUserHasId = Assert<{ id: string }, User>;
// Expect error (compile-time check)
// @ts-expect-error - User should require id
const invalidUser: User = { name: "John" };
```
## Common Patterns
### Builder Pattern
```typescript
class QueryBuilder<T> {
private filters: Array<(item: T) => boolean> = [];
where(predicate: (item: T) => boolean): this {
this.filters.push(predicate);
return this;
}
execute(items: T[]): T[] {
return items.filter((item) => this.filters.every((filter) => filter(item)));
}
}
```
### Result Type
```typescript
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function divide(a: number, b: number): Result<number> {
if (b === 0) {
return { success: false, error: new Error("Division by zero") };
}
return { success: true, data: a / b };
}
```

View File

@@ -0,0 +1,90 @@
# Conductor Hub
## Project: {{PROJECT_NAME}}
Central navigation for all Conductor artifacts and development tracks.
## Quick Links
### Core Documents
| Document | Description | Status |
| --------------------------------------------- | -------------------------- | ---------- |
| [Product Vision](./product.md) | Product overview and goals | {{STATUS}} |
| [Product Guidelines](./product-guidelines.md) | Voice, tone, and standards | {{STATUS}} |
| [Tech Stack](./tech-stack.md) | Technology decisions | {{STATUS}} |
| [Workflow](./workflow.md) | Development process | {{STATUS}} |
### Track Management
| Document | Description |
| ------------------------------- | ---------------------- |
| [Track Registry](./tracks.md) | All development tracks |
| [Active Tracks](#active-tracks) | Currently in progress |
### Style Guides
| Guide | Language/Domain |
| ---------------------------------------------- | ------------------------- |
| [General](./code_styleguides/general.md) | Universal principles |
| [TypeScript](./code_styleguides/typescript.md) | TypeScript conventions |
| [JavaScript](./code_styleguides/javascript.md) | JavaScript best practices |
| [Python](./code_styleguides/python.md) | Python standards |
| [Go](./code_styleguides/go.md) | Go idioms |
| [C#](./code_styleguides/csharp.md) | C# conventions |
| [Dart](./code_styleguides/dart.md) | Dart/Flutter patterns |
| [HTML/CSS](./code_styleguides/html-css.md) | Web standards |
## Active Tracks
| Track | Status | Priority | Spec | Plan |
| -------------- | ---------- | ------------ | ------------------------------------- | ------------------------------------- |
| {{TRACK_NAME}} | {{STATUS}} | {{PRIORITY}} | [spec](./tracks/{{TRACK_ID}}/spec.md) | [plan](./tracks/{{TRACK_ID}}/plan.md) |
## Recent Activity
| Date | Track | Action |
| -------- | --------- | ---------- |
| {{DATE}} | {{TRACK}} | {{ACTION}} |
## Project Status
**Current Phase:** {{CURRENT_PHASE}}
**Overall Progress:** {{PROGRESS_PERCENTAGE}}%
### Milestone Tracker
| Milestone | Target Date | Status |
| --------------- | ----------- | ------------ |
| {{MILESTONE_1}} | {{DATE_1}} | {{STATUS_1}} |
| {{MILESTONE_2}} | {{DATE_2}} | {{STATUS_2}} |
| {{MILESTONE_3}} | {{DATE_3}} | {{STATUS_3}} |
## Getting Started
1. Review [Product Vision](./product.md) for project context
2. Check [Tech Stack](./tech-stack.md) for technology decisions
3. Read [Workflow](./workflow.md) for development process
4. Find your track in [Track Registry](./tracks.md)
5. Follow track spec and plan
## Commands Reference
```bash
# Setup
{{SETUP_COMMAND}}
# Development
{{DEV_COMMAND}}
# Testing
{{TEST_COMMAND}}
# Build
{{BUILD_COMMAND}}
```
---
**Last Updated:** {{LAST_UPDATED}}
**Maintained By:** {{MAINTAINER}}

View File

@@ -0,0 +1,196 @@
# Product Guidelines
## Voice & Tone
### Brand Voice
{{BRAND_VOICE_DESCRIPTION}}
### Voice Attributes
- **{{ATTRIBUTE_1}}:** {{ATTRIBUTE_1_DESCRIPTION}}
- **{{ATTRIBUTE_2}}:** {{ATTRIBUTE_2_DESCRIPTION}}
- **{{ATTRIBUTE_3}}:** {{ATTRIBUTE_3_DESCRIPTION}}
### Tone Variations by Context
| Context | Tone | Example |
| -------------- | -------------------- | ----------------------- |
| Success states | {{SUCCESS_TONE}} | {{SUCCESS_EXAMPLE}} |
| Error states | {{ERROR_TONE}} | {{ERROR_EXAMPLE}} |
| Onboarding | {{ONBOARDING_TONE}} | {{ONBOARDING_EXAMPLE}} |
| Empty states | {{EMPTY_STATE_TONE}} | {{EMPTY_STATE_EXAMPLE}} |
### Words We Use
- {{PREFERRED_WORD_1}}
- {{PREFERRED_WORD_2}}
- {{PREFERRED_WORD_3}}
### Words We Avoid
- {{AVOIDED_WORD_1}}
- {{AVOIDED_WORD_2}}
- {{AVOIDED_WORD_3}}
## Messaging Guidelines
### Core Messages
**Primary Message:**
> {{PRIMARY_MESSAGE}}
**Supporting Messages:**
1. {{SUPPORTING_MESSAGE_1}}
2. {{SUPPORTING_MESSAGE_2}}
3. {{SUPPORTING_MESSAGE_3}}
### Message Hierarchy
1. **Must Communicate:** {{MUST_COMMUNICATE}}
2. **Should Communicate:** {{SHOULD_COMMUNICATE}}
3. **Could Communicate:** {{COULD_COMMUNICATE}}
### Audience-Specific Messaging
| Audience | Key Message | Proof Points |
| -------------- | ------------- | ------------ |
| {{AUDIENCE_1}} | {{MESSAGE_1}} | {{PROOF_1}} |
| {{AUDIENCE_2}} | {{MESSAGE_2}} | {{PROOF_2}} |
## Design Principles
### Principle 1: {{PRINCIPLE_1_NAME}}
{{PRINCIPLE_1_DESCRIPTION}}
**Do:**
- {{PRINCIPLE_1_DO_1}}
- {{PRINCIPLE_1_DO_2}}
**Don't:**
- {{PRINCIPLE_1_DONT_1}}
- {{PRINCIPLE_1_DONT_2}}
### Principle 2: {{PRINCIPLE_2_NAME}}
{{PRINCIPLE_2_DESCRIPTION}}
**Do:**
- {{PRINCIPLE_2_DO_1}}
- {{PRINCIPLE_2_DO_2}}
**Don't:**
- {{PRINCIPLE_2_DONT_1}}
- {{PRINCIPLE_2_DONT_2}}
### Principle 3: {{PRINCIPLE_3_NAME}}
{{PRINCIPLE_3_DESCRIPTION}}
**Do:**
- {{PRINCIPLE_3_DO_1}}
- {{PRINCIPLE_3_DO_2}}
**Don't:**
- {{PRINCIPLE_3_DONT_1}}
- {{PRINCIPLE_3_DONT_2}}
## Accessibility Standards
### Compliance Target
{{ACCESSIBILITY_STANDARD}} (e.g., WCAG 2.1 AA)
### Core Requirements
#### Perceivable
- All images have meaningful alt text
- Color is not the only means of conveying information
- Text has minimum contrast ratio of 4.5:1
- Content is readable at 200% zoom
#### Operable
- All functionality available via keyboard
- No content flashes more than 3 times per second
- Skip navigation links provided
- Focus indicators clearly visible
#### Understandable
- Language is clear and simple
- Navigation is consistent
- Error messages are descriptive and helpful
- Labels and instructions are clear
#### Robust
- Valid HTML markup
- ARIA labels used appropriately
- Compatible with assistive technologies
- Progressive enhancement approach
### Testing Requirements
- Screen reader testing with {{SCREEN_READER}}
- Keyboard-only navigation testing
- Color contrast verification
- Automated accessibility scans
## Error Handling Philosophy
### Error Prevention
- Validate input early and often
- Provide clear constraints and requirements upfront
- Use inline validation where appropriate
- Confirm destructive actions
### Error Communication
#### Principles
1. **Be specific:** Tell users exactly what went wrong
2. **Be helpful:** Explain how to fix the problem
3. **Be human:** Use friendly, non-technical language
4. **Be timely:** Show errors as soon as they're detected
#### Error Message Structure
```
[What happened] + [Why it happened (if relevant)] + [How to fix it]
```
#### Examples
| Bad | Good |
| --------------- | ---------------------------------------------------- |
| "Invalid input" | "Email address must include @ symbol" |
| "Error 500" | "We couldn't save your changes. Please try again." |
| "Failed" | "Unable to connect. Check your internet connection." |
### Error States
| Severity | Visual Treatment | User Action Required |
| -------- | ---------------------- | -------------------- |
| Info | {{INFO_TREATMENT}} | Optional |
| Warning | {{WARNING_TREATMENT}} | Recommended |
| Error | {{ERROR_TREATMENT}} | Required |
| Critical | {{CRITICAL_TREATMENT}} | Immediate |
### Recovery Patterns
- Auto-save user progress where possible
- Provide clear "try again" actions
- Offer alternative paths when primary fails
- Preserve user input on errors

View File

@@ -0,0 +1,102 @@
# Product Vision
## Product Overview
**Name:** {{PRODUCT_NAME}}
**Tagline:** {{ONE_LINE_DESCRIPTION}}
**Description:**
{{DETAILED_DESCRIPTION}}
## Problem Statement
### The Problem
{{PROBLEM_DESCRIPTION}}
### Current Solutions
{{EXISTING_SOLUTIONS}}
### Why They Fall Short
{{SOLUTION_GAPS}}
## Target Users
### Primary Users
{{PRIMARY_USER_PERSONA}}
- **Who:** {{USER_DESCRIPTION}}
- **Goals:** {{USER_GOALS}}
- **Pain Points:** {{USER_PAIN_POINTS}}
- **Technical Proficiency:** {{TECHNICAL_LEVEL}}
### Secondary Users
{{SECONDARY_USER_PERSONA}}
- **Who:** {{USER_DESCRIPTION}}
- **Goals:** {{USER_GOALS}}
- **Relationship to Primary:** {{RELATIONSHIP}}
## Core Value Proposition
### Key Benefits
1. {{BENEFIT_1}}
2. {{BENEFIT_2}}
3. {{BENEFIT_3}}
### Differentiators
- {{DIFFERENTIATOR_1}}
- {{DIFFERENTIATOR_2}}
### Value Statement
> {{VALUE_STATEMENT}}
## Success Metrics
### Key Performance Indicators
| Metric | Target | Measurement Method |
| ------------ | ------------ | ------------------ |
| {{METRIC_1}} | {{TARGET_1}} | {{METHOD_1}} |
| {{METRIC_2}} | {{TARGET_2}} | {{METHOD_2}} |
| {{METRIC_3}} | {{TARGET_3}} | {{METHOD_3}} |
### North Star Metric
{{NORTH_STAR_METRIC}}
### Leading Indicators
- {{LEADING_INDICATOR_1}}
- {{LEADING_INDICATOR_2}}
### Lagging Indicators
- {{LAGGING_INDICATOR_1}}
- {{LAGGING_INDICATOR_2}}
## Out of Scope
### Explicitly Not Included
- {{OUT_OF_SCOPE_1}}
- {{OUT_OF_SCOPE_2}}
- {{OUT_OF_SCOPE_3}}
### Future Considerations
- {{FUTURE_CONSIDERATION_1}}
- {{FUTURE_CONSIDERATION_2}}
### Non-Goals
- {{NON_GOAL_1}}
- {{NON_GOAL_2}}

View File

@@ -0,0 +1,204 @@
# Technology Stack
## Frontend
### Framework
**Choice:** {{FRONTEND_FRAMEWORK}}
**Version:** {{FRONTEND_VERSION}}
**Rationale:**
{{FRONTEND_RATIONALE}}
### State Management
**Choice:** {{STATE_MANAGEMENT}}
**Version:** {{STATE_VERSION}}
**Rationale:**
{{STATE_RATIONALE}}
### Styling
**Choice:** {{STYLING_SOLUTION}}
**Version:** {{STYLING_VERSION}}
**Rationale:**
{{STYLING_RATIONALE}}
### Additional Frontend Libraries
| Library | Purpose | Version |
| ------------ | -------------------- | -------------------- |
| {{FE_LIB_1}} | {{FE_LIB_1_PURPOSE}} | {{FE_LIB_1_VERSION}} |
| {{FE_LIB_2}} | {{FE_LIB_2_PURPOSE}} | {{FE_LIB_2_VERSION}} |
| {{FE_LIB_3}} | {{FE_LIB_3_PURPOSE}} | {{FE_LIB_3_VERSION}} |
## Backend
### Language
**Choice:** {{BACKEND_LANGUAGE}}
**Version:** {{BACKEND_LANGUAGE_VERSION}}
**Rationale:**
{{BACKEND_LANGUAGE_RATIONALE}}
### Framework
**Choice:** {{BACKEND_FRAMEWORK}}
**Version:** {{BACKEND_FRAMEWORK_VERSION}}
**Rationale:**
{{BACKEND_FRAMEWORK_RATIONALE}}
### Database
#### Primary Database
**Choice:** {{PRIMARY_DATABASE}}
**Version:** {{PRIMARY_DB_VERSION}}
**Rationale:**
{{PRIMARY_DB_RATIONALE}}
#### Secondary Database (if applicable)
**Choice:** {{SECONDARY_DATABASE}}
**Purpose:** {{SECONDARY_DB_PURPOSE}}
### Additional Backend Libraries
| Library | Purpose | Version |
| ------------ | -------------------- | -------------------- |
| {{BE_LIB_1}} | {{BE_LIB_1_PURPOSE}} | {{BE_LIB_1_VERSION}} |
| {{BE_LIB_2}} | {{BE_LIB_2_PURPOSE}} | {{BE_LIB_2_VERSION}} |
| {{BE_LIB_3}} | {{BE_LIB_3_PURPOSE}} | {{BE_LIB_3_VERSION}} |
## Infrastructure
### Hosting
**Provider:** {{HOSTING_PROVIDER}}
**Environment:** {{HOSTING_ENVIRONMENT}}
**Services Used:**
- {{HOSTING_SERVICE_1}}
- {{HOSTING_SERVICE_2}}
- {{HOSTING_SERVICE_3}}
### CI/CD
**Platform:** {{CICD_PLATFORM}}
**Pipeline Stages:**
1. {{PIPELINE_STAGE_1}}
2. {{PIPELINE_STAGE_2}}
3. {{PIPELINE_STAGE_3}}
4. {{PIPELINE_STAGE_4}}
### Monitoring
**APM:** {{APM_TOOL}}
**Logging:** {{LOGGING_TOOL}}
**Alerting:** {{ALERTING_TOOL}}
### Additional Infrastructure
| Service | Purpose | Provider |
| ----------- | ------------------- | -------------------- |
| {{INFRA_1}} | {{INFRA_1_PURPOSE}} | {{INFRA_1_PROVIDER}} |
| {{INFRA_2}} | {{INFRA_2_PURPOSE}} | {{INFRA_2_PROVIDER}} |
## Development Tools
### Package Manager
**Choice:** {{PACKAGE_MANAGER}}
**Version:** {{PACKAGE_MANAGER_VERSION}}
### Testing
| Type | Tool | Coverage Target |
| ----------- | ------------------------- | ------------------------- |
| Unit | {{UNIT_TEST_TOOL}} | {{UNIT_COVERAGE}}% |
| Integration | {{INTEGRATION_TEST_TOOL}} | {{INTEGRATION_COVERAGE}}% |
| E2E | {{E2E_TEST_TOOL}} | Critical paths |
### Linting & Formatting
**Linter:** {{LINTER}}
**Formatter:** {{FORMATTER}}
**Config:** {{LINT_CONFIG}}
### Additional Dev Tools
| Tool | Purpose |
| -------------- | ---------------------- |
| {{DEV_TOOL_1}} | {{DEV_TOOL_1_PURPOSE}} |
| {{DEV_TOOL_2}} | {{DEV_TOOL_2_PURPOSE}} |
| {{DEV_TOOL_3}} | {{DEV_TOOL_3_PURPOSE}} |
## Decision Log
### {{DECISION_1_TITLE}}
**Date:** {{DECISION_1_DATE}}
**Status:** {{DECISION_1_STATUS}}
**Context:**
{{DECISION_1_CONTEXT}}
**Decision:**
{{DECISION_1_DECISION}}
**Consequences:**
- {{DECISION_1_CONSEQUENCE_1}}
- {{DECISION_1_CONSEQUENCE_2}}
---
### {{DECISION_2_TITLE}}
**Date:** {{DECISION_2_DATE}}
**Status:** {{DECISION_2_STATUS}}
**Context:**
{{DECISION_2_CONTEXT}}
**Decision:**
{{DECISION_2_DECISION}}
**Consequences:**
- {{DECISION_2_CONSEQUENCE_1}}
- {{DECISION_2_CONSEQUENCE_2}}
---
### {{DECISION_3_TITLE}}
**Date:** {{DECISION_3_DATE}}
**Status:** {{DECISION_3_STATUS}}
**Context:**
{{DECISION_3_CONTEXT}}
**Decision:**
{{DECISION_3_DECISION}}
**Consequences:**
- {{DECISION_3_CONSEQUENCE_1}}
- {{DECISION_3_CONSEQUENCE_2}}
## Version Compatibility Matrix
| Component | Min Version | Max Version | Notes |
| --------------- | ----------- | ----------- | ----------- |
| {{COMPONENT_1}} | {{MIN_1}} | {{MAX_1}} | {{NOTES_1}} |
| {{COMPONENT_2}} | {{MIN_2}} | {{MAX_2}} | {{NOTES_2}} |
| {{COMPONENT_3}} | {{MIN_3}} | {{MAX_3}} | {{NOTES_3}} |

View File

@@ -0,0 +1,10 @@
{
"id": "",
"type": "feature|bug|chore|refactor",
"status": "pending|in_progress|completed",
"created_at": "",
"updated_at": "",
"description": "",
"spec_path": "",
"plan_path": ""
}

View File

@@ -0,0 +1,198 @@
# Implementation Plan: {{TRACK_NAME}}
## Overview
**Track ID:** {{TRACK_ID}}
**Spec:** [spec.md](./spec.md)
**Estimated Effort:** {{EFFORT_ESTIMATE}}
**Target Completion:** {{TARGET_DATE}}
## Progress Summary
| Phase | Status | Progress |
| ------------------------- | ---------- | ------------- |
| Phase 1: {{PHASE_1_NAME}} | {{STATUS}} | {{PROGRESS}}% |
| Phase 2: {{PHASE_2_NAME}} | {{STATUS}} | {{PROGRESS}}% |
| Phase 3: {{PHASE_3_NAME}} | {{STATUS}} | {{PROGRESS}}% |
| Phase 4: {{PHASE_4_NAME}} | {{STATUS}} | {{PROGRESS}}% |
## Phase 1: {{PHASE_1_NAME}}
**Objective:** {{PHASE_1_OBJECTIVE}}
**Estimated Duration:** {{PHASE_1_DURATION}}
### Tasks
- [ ] **1.1 {{TASK_1_1_TITLE}}**
- [ ] {{SUBTASK_1_1_1}}
- [ ] {{SUBTASK_1_1_2}}
- [ ] {{SUBTASK_1_1_3}}
- [ ] **1.2 {{TASK_1_2_TITLE}}**
- [ ] {{SUBTASK_1_2_1}}
- [ ] {{SUBTASK_1_2_2}}
- [ ] **1.3 {{TASK_1_3_TITLE}}**
- [ ] {{SUBTASK_1_3_1}}
- [ ] {{SUBTASK_1_3_2}}
### Verification
- [ ] All Phase 1 tests passing
- [ ] Code coverage meets threshold
- [ ] Code review approved
### Checkpoint
```
Commit: [track-id] checkpoint: phase 1 complete
```
---
## Phase 2: {{PHASE_2_NAME}}
**Objective:** {{PHASE_2_OBJECTIVE}}
**Estimated Duration:** {{PHASE_2_DURATION}}
**Dependencies:** Phase 1 complete
### Tasks
- [ ] **2.1 {{TASK_2_1_TITLE}}**
- [ ] {{SUBTASK_2_1_1}}
- [ ] {{SUBTASK_2_1_2}}
- [ ] {{SUBTASK_2_1_3}}
- [ ] **2.2 {{TASK_2_2_TITLE}}**
- [ ] {{SUBTASK_2_2_1}}
- [ ] {{SUBTASK_2_2_2}}
- [ ] **2.3 {{TASK_2_3_TITLE}}**
- [ ] {{SUBTASK_2_3_1}}
- [ ] {{SUBTASK_2_3_2}}
### Verification
- [ ] All Phase 2 tests passing
- [ ] Integration tests passing
- [ ] Code review approved
### Checkpoint
```
Commit: [track-id] checkpoint: phase 2 complete
```
---
## Phase 3: {{PHASE_3_NAME}}
**Objective:** {{PHASE_3_OBJECTIVE}}
**Estimated Duration:** {{PHASE_3_DURATION}}
**Dependencies:** Phase 2 complete
### Tasks
- [ ] **3.1 {{TASK_3_1_TITLE}}**
- [ ] {{SUBTASK_3_1_1}}
- [ ] {{SUBTASK_3_1_2}}
- [ ] **3.2 {{TASK_3_2_TITLE}}**
- [ ] {{SUBTASK_3_2_1}}
- [ ] {{SUBTASK_3_2_2}}
- [ ] **3.3 {{TASK_3_3_TITLE}}**
- [ ] {{SUBTASK_3_3_1}}
- [ ] {{SUBTASK_3_3_2}}
### Verification
- [ ] All Phase 3 tests passing
- [ ] End-to-end tests passing
- [ ] Code review approved
### Checkpoint
```
Commit: [track-id] checkpoint: phase 3 complete
```
---
## Phase 4: {{PHASE_4_NAME}}
**Objective:** {{PHASE_4_OBJECTIVE}}
**Estimated Duration:** {{PHASE_4_DURATION}}
**Dependencies:** Phase 3 complete
### Tasks
- [ ] **4.1 {{TASK_4_1_TITLE}}**
- [ ] {{SUBTASK_4_1_1}}
- [ ] {{SUBTASK_4_1_2}}
- [ ] **4.2 {{TASK_4_2_TITLE}}**
- [ ] {{SUBTASK_4_2_1}}
- [ ] {{SUBTASK_4_2_2}}
- [ ] **4.3 {{TASK_4_3_TITLE}}**
- [ ] {{SUBTASK_4_3_1}}
- [ ] {{SUBTASK_4_3_2}}
### Verification
- [ ] All tests passing
- [ ] Coverage ≥ 80%
- [ ] Performance benchmarks met
- [ ] Documentation complete
- [ ] Code review approved
### Checkpoint
```
Commit: [track-id] checkpoint: phase 4 complete (track done)
```
---
## Final Verification
### Quality Gates
- [ ] All unit tests passing
- [ ] All integration tests passing
- [ ] All E2E tests passing
- [ ] Code coverage ≥ 80%
- [ ] No critical linting errors
- [ ] Security scan passed
- [ ] Performance requirements met
- [ ] Accessibility requirements met
### Documentation
- [ ] API documentation updated
- [ ] README updated (if applicable)
- [ ] Changelog entry added
### Deployment
- [ ] Staging deployment successful
- [ ] Smoke tests passed
- [ ] Production deployment approved
---
## Deviations Log
| Date | Task | Deviation | Reason | Resolution |
| -------- | -------- | ------------- | ---------- | -------------- |
| {{DATE}} | {{TASK}} | {{DEVIATION}} | {{REASON}} | {{RESOLUTION}} |
## Notes
{{IMPLEMENTATION_NOTES}}
---
**Plan Created:** {{CREATED_DATE}}
**Last Updated:** {{UPDATED_DATE}}

View File

@@ -0,0 +1,169 @@
# Track Specification: {{TRACK_NAME}}
## Overview
**Track ID:** {{TRACK_ID}}
**Type:** {{TRACK_TYPE}} (feature | bug | chore | refactor)
**Priority:** {{PRIORITY}} (critical | high | medium | low)
**Created:** {{CREATED_DATE}}
**Author:** {{AUTHOR}}
### Description
{{TRACK_DESCRIPTION}}
### Background
{{BACKGROUND_CONTEXT}}
## Functional Requirements
### FR-1: {{REQUIREMENT_1_TITLE}}
{{REQUIREMENT_1_DESCRIPTION}}
**Acceptance Criteria:**
- [ ] {{FR1_CRITERIA_1}}
- [ ] {{FR1_CRITERIA_2}}
- [ ] {{FR1_CRITERIA_3}}
### FR-2: {{REQUIREMENT_2_TITLE}}
{{REQUIREMENT_2_DESCRIPTION}}
**Acceptance Criteria:**
- [ ] {{FR2_CRITERIA_1}}
- [ ] {{FR2_CRITERIA_2}}
- [ ] {{FR2_CRITERIA_3}}
### FR-3: {{REQUIREMENT_3_TITLE}}
{{REQUIREMENT_3_DESCRIPTION}}
**Acceptance Criteria:**
- [ ] {{FR3_CRITERIA_1}}
- [ ] {{FR3_CRITERIA_2}}
- [ ] {{FR3_CRITERIA_3}}
## Non-Functional Requirements
### Performance
- {{PERFORMANCE_REQUIREMENT_1}}
- {{PERFORMANCE_REQUIREMENT_2}}
### Security
- {{SECURITY_REQUIREMENT_1}}
- {{SECURITY_REQUIREMENT_2}}
### Scalability
- {{SCALABILITY_REQUIREMENT_1}}
### Accessibility
- {{ACCESSIBILITY_REQUIREMENT_1}}
### Compatibility
- {{COMPATIBILITY_REQUIREMENT_1}}
## Acceptance Criteria
### Must Have (P0)
- [ ] {{P0_CRITERIA_1}}
- [ ] {{P0_CRITERIA_2}}
- [ ] {{P0_CRITERIA_3}}
### Should Have (P1)
- [ ] {{P1_CRITERIA_1}}
- [ ] {{P1_CRITERIA_2}}
### Nice to Have (P2)
- [ ] {{P2_CRITERIA_1}}
- [ ] {{P2_CRITERIA_2}}
## Scope
### In Scope
- {{IN_SCOPE_1}}
- {{IN_SCOPE_2}}
- {{IN_SCOPE_3}}
- {{IN_SCOPE_4}}
### Out of Scope
- {{OUT_OF_SCOPE_1}}
- {{OUT_OF_SCOPE_2}}
- {{OUT_OF_SCOPE_3}}
### Future Considerations
- {{FUTURE_1}}
- {{FUTURE_2}}
## Dependencies
### Upstream Dependencies
| Dependency | Type | Status | Notes |
| ---------- | ---------- | ------------ | ----------- |
| {{DEP_1}} | {{TYPE_1}} | {{STATUS_1}} | {{NOTES_1}} |
| {{DEP_2}} | {{TYPE_2}} | {{STATUS_2}} | {{NOTES_2}} |
### Downstream Impacts
| Component | Impact | Mitigation |
| --------------- | ------------ | ---------------- |
| {{COMPONENT_1}} | {{IMPACT_1}} | {{MITIGATION_1}} |
| {{COMPONENT_2}} | {{IMPACT_2}} | {{MITIGATION_2}} |
### External Dependencies
- {{EXTERNAL_DEP_1}}
- {{EXTERNAL_DEP_2}}
## Risks
### Technical Risks
| Risk | Probability | Impact | Mitigation |
| --------------- | ----------- | ------------ | ---------------- |
| {{TECH_RISK_1}} | {{PROB_1}} | {{IMPACT_1}} | {{MITIGATION_1}} |
| {{TECH_RISK_2}} | {{PROB_2}} | {{IMPACT_2}} | {{MITIGATION_2}} |
### Business Risks
| Risk | Probability | Impact | Mitigation |
| -------------- | ----------- | ------------ | ---------------- |
| {{BIZ_RISK_1}} | {{PROB_1}} | {{IMPACT_1}} | {{MITIGATION_1}} |
### Unknowns
- {{UNKNOWN_1}}
- {{UNKNOWN_2}}
## Open Questions
- [ ] {{QUESTION_1}}
- [ ] {{QUESTION_2}}
- [ ] {{QUESTION_3}}
## References
- {{REFERENCE_1}}
- {{REFERENCE_2}}
- {{REFERENCE_3}}
---
**Approved By:** {{APPROVER}}
**Approval Date:** {{APPROVAL_DATE}}

View File

@@ -0,0 +1,53 @@
# Track Registry
This file maintains the registry of all development tracks for the project. Each track represents a distinct body of work with its own spec and implementation plan.
## Status Legend
| Symbol | Status | Description |
| ------ | ----------- | ------------------------- |
| `[ ]` | Pending | Not yet started |
| `[~]` | In Progress | Currently being worked on |
| `[x]` | Completed | Finished and verified |
## Active Tracks
### [ ] {{TRACK_ID}}: {{TRACK_NAME}}
**Description:** {{TRACK_DESCRIPTION}}
**Priority:** {{PRIORITY}}
**Folder:** [./tracks/{{TRACK_ID}}/](./tracks/{{TRACK_ID}}/)
---
### [ ] {{TRACK_ID}}: {{TRACK_NAME}}
**Description:** {{TRACK_DESCRIPTION}}
**Priority:** {{PRIORITY}}
**Folder:** [./tracks/{{TRACK_ID}}/](./tracks/{{TRACK_ID}}/)
---
## Completed Tracks
<!-- Move completed tracks here -->
---
## Track Creation Checklist
When creating a new track:
1. [ ] Add entry to this registry
2. [ ] Create track folder: `./tracks/{{track-id}}/`
3. [ ] Create spec.md from template
4. [ ] Create plan.md from template
5. [ ] Create metadata.json from template
6. [ ] Update index.md with new track reference
## Notes
- Track IDs should be lowercase with hyphens (e.g., `user-auth`, `api-v2`)
- Keep descriptions concise (one line)
- Prioritize tracks as: critical, high, medium, low
- Archive completed tracks quarterly

View File

@@ -0,0 +1,192 @@
# Development Workflow
## Core Principles
1. **plan.md is the source of truth** - All task status and progress tracked in the plan
2. **Test-Driven Development** - Red → Green → Refactor cycle with 80% coverage target
3. **CI/CD Compatibility** - All changes must pass automated pipelines before merge
4. **Incremental Progress** - Small, verifiable commits with clear purpose
## Task Lifecycle
### Step 1: Task Selection
- Review plan.md for next pending task
- Verify dependencies are complete
- Confirm understanding of acceptance criteria
### Step 2: Progress Marking
- Update task status in plan.md from `[ ]` to `[~]`
- Note start time if tracking velocity
### Step 3: Red Phase (Write Failing Tests)
- Write test(s) that define expected behavior
- Verify test fails for the right reason
- Keep tests focused and minimal
### Step 4: Green Phase (Make Tests Pass)
- Write minimum code to pass tests
- Avoid premature optimization
- Focus on correctness over elegance
### Step 5: Refactor Phase
- Improve code structure without changing behavior
- Apply relevant style guide conventions
- Remove duplication and clarify intent
### Step 6: Coverage Verification
- Run coverage report
- Ensure new code meets 80% threshold
- Add edge case tests if coverage gaps exist
### Step 7: Deviation Documentation
- If implementation differs from spec, document why
- Update spec if change is permanent
- Flag for review if uncertain
### Step 8: Code Commit
- Stage related changes only
- Write clear commit message referencing task
- Format: `[track-id] task: description`
### Step 9: Git Notes (Optional)
- Add implementation notes for complex changes
- Reference relevant decisions or trade-offs
### Step 10: Plan Update
- Mark task as `[x]` completed in plan.md
- Update any affected downstream tasks
- Note blockers or follow-up items
### Step 11: Plan Commit
- Commit plan.md changes separately
- Format: `[track-id] plan: mark task X complete`
## Phase Completion Protocol
### Checkpoint Commits
At the end of each phase:
1. Ensure all phase tasks are `[x]` complete
2. Run full test suite
3. Verify coverage meets threshold
4. Create checkpoint commit: `[track-id] checkpoint: phase N complete`
### Test Verification
```bash
{{TEST_COMMAND}}
{{COVERAGE_COMMAND}}
```
### Manual Approval Gates
Phases requiring approval before proceeding:
- Architecture changes
- API contract modifications
- Database schema changes
- Security-sensitive implementations
## Quality Assurance Gates
All code must pass these criteria before merge:
| Gate | Requirement | Command |
| ----------- | ------------------------ | ------------------------ |
| 1. Tests | All tests passing | `{{TEST_COMMAND}}` |
| 2. Coverage | Minimum 80% | `{{COVERAGE_COMMAND}}` |
| 3. Style | Follows style guide | `{{LINT_COMMAND}}` |
| 4. Docs | Public APIs documented | Manual review |
| 5. Types | No type errors | `{{TYPE_CHECK_COMMAND}}` |
| 6. Linting | No lint errors | `{{LINT_COMMAND}}` |
| 7. Mobile | Responsive if applicable | Manual review |
| 8. Security | No known vulnerabilities | `{{SECURITY_COMMAND}}` |
## Development Commands
### Environment Setup
```bash
{{SETUP_COMMAND}}
```
### Development Server
```bash
{{DEV_COMMAND}}
```
### Pre-Commit Checks
```bash
{{PRE_COMMIT_COMMAND}}
```
### Full Validation
```bash
{{VALIDATE_COMMAND}}
```
## Workflow Diagram
```
┌─────────────┐
│ Select Task │
└──────┬──────┘
┌─────────────┐
│ Mark [~] │
└──────┬──────┘
┌─────────────┐
│ RED: Write │
│ Failing Test│
└──────┬──────┘
┌─────────────┐
│ GREEN: Make │
│ Test Pass │
└──────┬──────┘
┌─────────────┐
│ REFACTOR │
└──────┬──────┘
┌─────────────┐
│ Verify │
│ Coverage │
└──────┬──────┘
┌─────────────┐
│ Commit Code │
└──────┬──────┘
┌─────────────┐
│ Mark [x] │
└──────┬──────┘
┌─────────────┐
│ Commit Plan │
└─────────────┘
```