Back to list
DevXoje

coding-style

by DevXoje

0🍴 0📅 Jan 18, 2026

SKILL.md


name: coding-style description: > Coding style guide and conventions for GeroCare. Provides decision trees and patterns for writing consistent, maintainable code. Trigger: When writing code, refactoring, or making style decisions. license: Apache-2.0 metadata: author: gero-cloud version: "1.0" scope: [root] auto_invoke: "Writing code, refactoring, or making style decisions"

When to Use

Use this skill when:

  • Writing new code or functions
  • Refactoring existing code
  • Making style decisions (ternaries vs if/else, function formatting, etc.)
  • Organizing imports or code structure
  • Naming variables, functions, types, or files
  • Writing Vue components or TypeScript code
  • Handling errors or async operations

Don't use this skill for:

  • Architectural decisions (use feature-development skill)
  • UI component patterns (use ui-components skill)
  • Testing patterns (use testing skill)

Configuration Reference

Prettier

{
  "semi": false,
  "singleQuote": true,
  "printWidth": 100
}

Rules:

  • No semicolons
  • Single quotes
  • Maximum 100 characters per line

ESLint

Key Rules:

  • Prohibit relative imports in src/ (use alias @/)
  • Auto-sort imports with simple-import-sort
  • Allow relative imports only in tests and config files

EditorConfig

Settings:

  • Indentation: 2 spaces
  • Charset: UTF-8
  • End of line: LF
  • Insert final newline: Yes

Decision Trees

Ternaries vs If/Else

Use ternaries when:

  • ✅ Simple expression in return/assignment (1-2 lines)
  • ✅ Conditional value assignment (single value)
  • ✅ Simple 2-option case

Use if/else when:

  • ✅ Multi-line logic
  • ✅ Side effects (multiple assignments, function calls)
  • ✅ Complex conditions with multiple branches
  • ✅ Early returns

Ternary nesting:

  • ✅ Allowed up to 2-3 levels with clear formatting
  • ❌ Avoid more than 3 levels (use if/else instead)

Example - Ternary (correct):

const status = isLoading ? 'loading' : 'ready'

const result = residentId
  ? activeOnly
    ? await repository.findActiveByResident(residentId)
    : await repository.findByResident(residentId)
  : await repository.findAll()

Example - If/Else (correct):

if (result.success) {
  carePlans.value = result.value
  isLoading.value = false
  error.value = null
} else {
  error.value = result.error
  carePlans.value = []
}

Function Parameters Formatting

Inline format (1-2 simple parameters):

async function fetchCarePlan(id: string) { }

Multiline format (3+ parameters or complex types):

async function updateCarePlan(
  id: string,
  updates: Partial<Omit<CarePlan, 'id' | 'createdAt'>>,
  options?: UpdateOptions
) { }

Optional parameters:

  • Use ? for optional: residentId?: string
  • Use defaults when appropriate: status: 'completed' | 'skipped' = 'completed'

Naming Conventions

TypeConventionExample
FilesPascalCase (Vue), camelCase (TS)ResidentForm.vue, useResidents.ts
FunctionscamelCase, descriptive verbsloadResidents, fetchCarePlan
VariablescamelCase, booleans with is/hasisLoading, carePlans, hasError
Types/InterfacesPascalCase, no I prefixCarePlan, ResidentError
ConstantsUPPER_SNAKE_CASE (global), camelCase (local)API_BASE_URL, repository

Critical Patterns

1. Imports Organization

Order (auto-sorted by ESLint):

  1. Side effect imports (import 'something')
  2. Node.js builtins (import fs from 'node:fs')
  3. Packages (import { ref } from 'vue')
  4. Aliases (import { useAuthStore } from '@/business/auth/store')
  5. Parent imports (import { something } from '../domain')
  6. Current directory (import { helper } from './utils')
  7. Styles (import './styles.css')

Grouping:

  • Separate imports with blank lines
  • Group Vue core, then aliases @/, then types

Example:

import { computed, ref } from 'vue'

import { useAuthStore } from '@/business/auth/store'
import type { Resident } from '@/business/residents/domain/Resident'
import { createResidentRepository } from '@/business/residents/infrastructure'

Type imports:

  • Use import type for types-only imports
  • Place type imports on separate line after value imports

2. Async/Await Pattern

Always use async/await (never .then() / .catch()):

// ✅ Correct
async function loadResidents() {
  isLoading.value = true
  try {
    const result = await repository.findAll()
    if (result.success) {
      residents.value = result.value
    }
  } catch {
    error.value = { code: 'UNKNOWN_ERROR', message: 'Failed to load residents' }
  } finally {
    isLoading.value = false
  }
}

Standard pattern:

  1. Set isLoading.value = true before try
  2. Reset error.value = null before try
  3. Try block with async operation
  4. Check result.success if using Result type
  5. Catch block for unexpected errors
  6. Finally block to set isLoading.value = false

3. Result Type Pattern

Always use Result<T, E> in repositories:

async function findById(id: string): Promise<Result<CarePlan | null, CarePlanError>> {
  try {
    const result = await repository.findById(id)
    return Ok(carePlan)
  } catch (error) {
    return Err(createUnknownCarePlanError('Failed to find care plan'))
  }
}

Always check result.success before accessing value:

// ✅ Correct
const result = await repository.findById(id)
if (result.success) {
  carePlan.value = result.value // TypeScript knows value exists
} else {
  error.value = result.error // TypeScript knows error exists
}

// ❌ Incorrect - Direct access without check
const result = await repository.findById(id)
carePlan.value = result.value // Error: value may not exist

4. TypeScript Patterns

Explicit types:

  • Always for function parameters
  • Always for public function returns (when not obvious)
  • Use inference for local variables when type is obvious

Type utilities:

// Omit for removing fields
type CreateInput = Omit<Entity, 'id' | 'createdAt' | 'updatedAt'>

// Partial for updates
updates: Partial<Omit<Entity, 'id' | 'createdAt'>>

// Pick for selecting fields
type Summary = Pick<Entity, 'id' | 'title' | 'status'>

Avoid any, use unknown:

// ✅ Correct
function validate(data: unknown): Result<Entity, Error> { }

// ❌ Incorrect
function validate(data: any): Entity { }

5. Vue Component Structure

<script setup lang="ts">
import { computed, ref } from 'vue'

defineOptions({
  name: 'AppComponentName',
})

interface Props {
  // Props
}

const props = withDefaults(defineProps<Props>(), {
  // Defaults
})

const emit = defineEmits<{
  'event-name': [value: Type]
}>()

// State, computed, methods
</script>

<template>
  <!-- Template -->
</template>

<style scoped>
/* Styles */
</style>

Conventions:

  • Always use <script setup lang="ts">
  • Use defineOptions for component name (App{ComponentName})
  • Type props with interfaces
  • Type emits with defineEmits<{...}>()
  • Always use scoped styles

6. Comments

Comment when:

  • ✅ Explaining "why" (not "what")
  • ✅ Complex business logic requiring context
  • ✅ Public API functions (use JSDoc)

Don't comment:

  • ❌ Obvious code
  • ❌ Temporary refactors without context
  • ❌ Redundant explanations

Example:

// ✅ Good - Explains "why"
// Add current user as assigned caregiver if not already included
// (required for proper permission tracking)
const residentWithCaregiver = {
  ...residentData,
  assignedCaregivers: residentData.assignedCaregivers.includes(authStore.user.uid)
    ? residentData.assignedCaregivers
    : [...residentData.assignedCaregivers, authStore.user.uid],
}

// ❌ Bad - Obvious comment
// Set isLoading to true
isLoading.value = true

JSDoc for public APIs:

/**
 * Validates a resident entity using Zod schema
 * @param resident - The resident data to validate (can be unknown)
 * @returns Result containing validated Resident or validation error
 */
export function validateResident(resident: unknown): Result<Resident, ResidentError> {
  // ...
}

Common Patterns

Error Handling Pattern

async function fetchCarePlan(id: string) {
  isLoading.value = true
  error.value = null

  try {
    const result = await repository.findById(id)
    if (result.success) {
      currentCarePlan.value = result.value
    } else {
      error.value = result.error
    }
  } catch {
    error.value = { code: 'UNKNOWN_ERROR', message: 'Failed to fetch care plan' }
  } finally {
    isLoading.value = false
  }
}

Loading State Pattern

// Before async operation
isLoading.value = true
error.value = null

try {
  // ... async operation
} catch {
  // ... handle error
} finally {
  // Always reset loading state
  isLoading.value = false
}

Early Return Pattern

async function loadResidents() {
  // Early return for invalid state
  if (!authStore.user) {
    error.value = { code: 'AUTH_ERROR', message: 'User not authenticated' }
    return
  }

  // ... rest of function
}

Spacing and Formatting

Blank Lines

  • After imports (between groups)
  • Before return statements
  • Between logical blocks

Line Length

  • Maximum 100 characters (enforced by Prettier)
  • Break long lines at logical points

Indentation

  • Always 2 spaces (never tabs)
  • Consistent indentation for related blocks

Quick Reference

PatternExample
Ternaryconst status = isLoading ? 'loading' : 'ready'
If/Elseif (result.success) { ... } else { ... }
Function params (simple)function fetch(id: string) { }
Function params (complex)function update(id: string, updates: Partial<Entity>) { }
Optional paramfunction fetch(id?: string) { }
Result typeconst result = await repo.findById(id); if (result.success) { ... }
Async/awaitconst result = await repository.findAll()
Type importimport type { Entity } from './Entity'
Alias importimport { useStore } from '@/business/auth/store'

Resources

  • Full Style Guide: docs/CODING_STYLE.md
  • Prettier Config: .prettierrc.json
  • ESLint Config: eslint.config.ts
  • EditorConfig: .editorconfig
  • Result Type: src/shared/domain/Result.ts
  • Example Store: src/business/care-plans/store.ts
  • Example Composable: src/business/residents/app/useResidents.ts
  • Example Component: src/business/residents/presentation/components/ResidentForm.vue

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon