スキル一覧に戻る
Bemyself19

code-professionalization

by Bemyself19

1🍴 0📅 2026年1月25日
GitHubで見るManusで実行

SKILL.md


name: Code Professionalization description: Systematically transform codebase from 6.5/10 to 9/10 professional standards through testing, type safety, refactoring, and best practices

Code Professionalization Skill

Overview

This skill guides the systematic improvement of a codebase to professional engineering standards, specifically designed for the SehatyNet project but applicable to any TypeScript/Node.js application.

Goal: Transform codebase from 6.5/10 to 9/10 professional quality Timeline: 3-6 months (can be accelerated with dedicated effort) Prerequisites: Working application with TypeScript, Node.js, React

Execution Principle

Execute phases sequentially - do not skip ahead. Each phase builds on the previous one and includes validation checkpoints. Track progress in PROGRESS.md file.


Phase 1: Critical Fixes (Week 1-2)

Goal: Fix the most glaring professional deficiencies Time: 1-2 weeks Impact: High - Makes codebase maintainable and testable

1.1 Enable TypeScript Strict Mode

Status: 🔴 Not Started

Steps:

  1. Backup current configuration
cp tsconfig.json tsconfig.json.backup
cp backend/tsconfig.json backend/tsconfig.json.backup
  1. Enable strict mode in backend (easier to start here)
// backend/tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true
  }
}
  1. Run TypeScript compiler to see errors
cd backend && npm run build
  1. Fix errors incrementally by file priority:

    • Start with models (lowest dependency)
    • Then services
    • Then controllers
    • Finally routes and index.ts
  2. Common fixes needed:

    • Add explicit return types to functions
    • Handle null/undefined cases with optional chaining
    • Replace any types with proper interfaces
    • Add type guards for user input
  3. Validate:

cd backend && npm run build
# Should compile with zero errors
  1. Repeat for frontend:
// tsconfig.json (frontend)
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

Checkpoint: ✅ Both frontend and backend compile with strict mode enabled


1.2 Add Testing Infrastructure

Status: 🔴 Not Started

Backend Testing Setup:

  1. Install testing dependencies
cd backend
npm install --save-dev jest @types/jest ts-jest supertest @types/supertest
  1. Create Jest configuration
cat > jest.config.js << 'EOF'
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/**/index.ts'
  ],
  coverageThreshold: {
    global: {
      branches: 50,
      functions: 50,
      lines: 50,
      statements: 50
    }
  }
};
EOF
  1. Update package.json scripts
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}
  1. Create first test file - backend/src/__tests__/auth.controller.test.ts:
import request from 'supertest';
import express from 'express';
import authRoutes from '../routes/auth.routes';

const app = express();
app.use(express.json());
app.use('/api/v1/auth', authRoutes);

describe('Authentication Controller', () => {
  describe('POST /api/v1/auth/register', () => {
    it('should reject registration without email', async () => {
      const response = await request(app)
        .post('/api/v1/auth/register')
        .send({ password: 'Test123!@#' });

      expect(response.status).toBe(400);
    });

    it('should reject weak passwords', async () => {
      const response = await request(app).post('/api/v1/auth/register').send({
        email: 'test@example.com',
        password: '123',
      });

      expect(response.status).toBe(400);
    });
  });
});
  1. Run tests
npm test

Frontend Testing Setup:

  1. Install Vitest and React Testing Library
npm install --save-dev vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom
  1. Create Vitest config - vitest.config.ts:
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: ['node_modules/', 'src/test/'],
    },
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});
  1. Create test setup file - src/test/setup.ts:
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import * as matchers from '@testing-library/jest-dom/matchers';

expect.extend(matchers);

afterEach(() => {
  cleanup();
});
  1. Update package.json
{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage"
  }
}
  1. Create first component test - src/components/__tests__/ProtectedRoute.test.tsx:
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import ProtectedRoute from '../ProtectedRoute';

describe('ProtectedRoute', () => {
  it('should redirect to login when not authenticated', () => {
    const { container } = render(
      <BrowserRouter>
        <ProtectedRoute>
          <div>Protected Content</div>
        </ProtectedRoute>
      </BrowserRouter>
    );

    expect(screen.queryByText('Protected Content')).not.toBeInTheDocument();
  });
});

Checkpoint: ✅ Tests run successfully with npm test in both backend and frontend


1.3 Extract Configuration from Code

Status: 🔴 Not Started

Steps:

  1. Create configuration directory structure
mkdir -p backend/src/config
  1. Extract CORS configuration - backend/src/config/cors.config.ts:
export const getCorsOrigins = (): string[] => {
  const origins = process.env.ALLOWED_ORIGINS?.split(',') || [];

  // Add defaults for development
  if (process.env.NODE_ENV !== 'production') {
    origins.push('https://localhost:5173', 'http://localhost:5173');
  }

  return origins;
};

export const corsOptions = {
  origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
    const allowedOrigins = getCorsOrigins();

    if (!origin || allowedOrigins.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: [
    'Content-Type',
    'Authorization',
    'X-Requested-With',
    'Cache-Control',
    'Pragma',
    'Expires',
    'X-CSRF-Token',
    'X-Session-ID',
  ],
};
  1. Extract rate limiting - backend/src/config/rate-limit.config.ts:
import rateLimit from 'express-rate-limit';

export const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    error: 'Too many login attempts',
    message: 'Too many login attempts, please try again later',
    retryAfter: 15 * 60,
  },
  standardHeaders: true,
  legacyHeaders: false,
  skipSuccessfulRequests: true,
  skipFailedRequests: false,
});

export const registrationLimiter = rateLimit({
  windowMs: 60 * 60 * 1000,
  max: 50,
  message: {
    error: 'Too many registration attempts',
    message: 'Too many registration attempts, please try again later',
    retryAfter: 60 * 60,
  },
  standardHeaders: true,
  legacyHeaders: false,
});

export const generalLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 1000,
  message: {
    error: 'Too many requests',
    message: 'Too many requests, please try again later',
    retryAfter: 15 * 60,
  },
  standardHeaders: true,
  legacyHeaders: false,
});

export const adminLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5000,
  message: {
    error: 'Too many requests',
    message: 'Too many requests, please try again later',
    retryAfter: 15 * 60,
  },
  standardHeaders: true,
  legacyHeaders: false,
});
  1. Extract security headers - backend/src/config/security.config.ts:
import helmet from 'helmet';

export const helmetConfig = helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: [
        "'self'",
        "'unsafe-inline'",
        'https://accounts.google.com',
        'https://apis.google.com',
        'https://www.gstatic.com',
      ],
      imgSrc: ["'self'", 'data:', 'https:', 'https://lh3.googleusercontent.com'],
      connectSrc: [
        "'self'",
        'https://accounts.google.com',
        'https://apis.google.com',
        'https://www.googleapis.com',
      ],
      frameSrc: ["'self'", 'https://accounts.google.com'],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true,
  },
});
  1. Update .env.example with all required variables
cat > .env.example << 'EOF'
# Server
NODE_ENV=development
PORT=5000
FRONTEND_URL=https://localhost:5173

# Database
MONGO_URI=mongodb://localhost:27017/sehatynet
MONGO_SSL=false

# Security
JWT_SECRET=your_secure_jwt_secret_here
ENCRYPTION_KEY=your_encryption_key_here

# CORS
ALLOWED_ORIGINS=https://localhost:5173,http://localhost:5173

# Email (Nodemailer)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_app_password

# Google OAuth
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

# Cloud Storage
GOOGLE_CLOUD_PROJECT_ID=your_project_id
LOCAL_UPLOADS_DIR=./uploads
EOF
  1. Update index.ts to use config modules
import { corsOptions } from './config/cors.config';
import { authLimiter, generalLimiter, adminLimiter } from './config/rate-limit.config';
import { helmetConfig } from './config/security.config';

// Replace hardcoded configs with imported ones
app.use(helmetConfig);
app.use(cors(corsOptions));
app.use('/api/v1/auth/login', authLimiter);
// etc.

Checkpoint: ✅ No hardcoded configuration in code, all via config files and environment variables


1.4 Fix Git Hygiene

Status: 🔴 Not Started

Steps:

  1. Create comprehensive .gitignore
cat > .gitignore << 'EOF'
# Dependencies
node_modules/
backend/node_modules/

# Build outputs
dist/
dist-ssr/
backend/dist/
*.local

# Environment files
.env
.env.*
!.env.example
backend/.env
backend/.env.*

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
backend/logs/

# OS files
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
Thumbs.db

# IDE
.vscode/*
!.vscode/extensions.json
.idea/
*.iml

# Test coverage
coverage/
*.lcov
.nyc_output/

# Temporary files
*.tmp
*.temp
temp/
tmp/
response.json
cookie.txt
test.txt

# Uploads (local development)
uploads/*
!uploads/.gitkeep
backend/uploads/*
!backend/uploads/.gitkeep

# Security
firebase-service-account.json
*.pem
*.key
*.crt
cert/

# Backups (should not be in repo)
*.backup
*backup*/
api-migration-backup-*/
storage-migration-backup-*/

# Python
.venv/
__pycache__/
*.py[cod]

# Generated files
forecasts/
*.csv
!inputs.csv
EOF
  1. Stop tracking sensitive files
# Remove from Git index but keep locally
git rm --cached .env
git rm --cached .env.local
git rm --cached .env.network
git rm --cached backend/.env
git rm -r --cached api-migration-backup-20251017-204040
git rm -r --cached storage-migration-backup-20251017-204233

# Commit the removal
git add .gitignore
git commit -m "chore: remove sensitive files and backups from version control"
  1. Remove sensitive data from Git history (OPTIONAL - rewrites history)
# WARNING: This rewrites Git history
# Only do this if you haven't shared the repo or can coordinate with team

# Install BFG Repo-Cleaner
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar

# Remove .env files from all commits
java -jar bfg-1.14.0.jar --delete-files .env
java -jar bfg-1.14.0.jar --delete-folders api-migration-backup-20251017-204040

# Clean up
git reflog expire --expire=now --all && git gc --prune=now --aggressive

# Force push (coordinate with team!)
# git push --force
  1. Clean up test scripts - Move to proper location
mkdir -p scripts/tests
mv test-*.js scripts/tests/
mv check-*.js scripts/tests/
mv create-test-*.js scripts/tests/

# Update references if needed

Checkpoint: ✅ No sensitive files tracked, clean repository structure


Phase 2: Code Quality Improvements (Week 3-6)

Goal: Establish professional code organization and standards Time: 2-4 weeks Impact: Medium-High - Makes codebase maintainable and scalable

2.1 Refactor Large Files

Status: 🔴 Not Started

Target: Break down files > 300 lines

Steps:

  1. Refactor backend/src/index.ts (863 lines)

Create new structure:

backend/src/
├── server/
│   ├── app.ts              # Express app setup
│   ├── middleware.ts       # All middleware configuration
│   ├── routes.ts           # Route registration
│   ├── websocket.ts        # WebSocket server handling
│   └── shutdown.ts         # Graceful shutdown logic
├── config/                 # Already created in Phase 1
└── index.ts                # Minimal entry point

New backend/src/server/app.ts:

import express from 'express';
import { setupMiddleware } from './middleware';
import { setupRoutes } from './routes';

export const createApp = (): express.Application => {
  const app = express();

  // Trust proxy for reverse proxy setups
  app.set('trust proxy', 1);

  // Setup all middleware
  setupMiddleware(app);

  // Setup all routes
  setupRoutes(app);

  return app;
};

New backend/src/server/middleware.ts:

import express from 'express';
import cors from 'cors';
import { corsOptions } from '../config/cors.config';
import { helmetConfig } from '../config/security.config';
import { authLimiter, generalLimiter, adminLimiter } from '../config/rate-limit.config';
import { requestLogger, errorLogger } from '../middleware/logger.middleware';
import { CSRFProtection } from '../middleware/csrf.middleware';

export const setupMiddleware = (app: express.Application): void => {
  // Security headers
  app.use(helmetConfig);

  // CORS
  app.use(cors(corsOptions));

  // Rate limiting
  app.use('/api/v1/auth/login', authLimiter);
  app.use('/api/v1/auth/register', registrationLimiter);
  app.use('/api/v1/', generalLimiter);

  // Logging
  app.use(requestLogger);

  // Body parsing
  app.use(express.json({ limit: '10mb' }));
  app.use(express.urlencoded({ extended: true }));

  // CSRF protection
  app.use(CSRFProtection.verifyToken);

  // Error logging
  app.use(errorLogger);
};

Continue this pattern for routes.ts, websocket.ts, and shutdown.ts

  1. Refactor backend/src/controllers/auth.controller.ts (1,087 lines)

Break into:

backend/src/controllers/auth/
├── index.ts                          # Export all
├── register.controller.ts            # Registration logic
├── login.controller.ts               # Login/admin login
├── google-auth.controller.ts         # Google SSO
├── password.controller.ts            # Password reset/change
├── email-verification.controller.ts  # Email verification
└── profile.controller.ts             # Profile updates

Each file should be < 200 lines

  1. Validate refactoring
# Ensure everything still compiles
cd backend && npm run build

# Run existing tests
npm test

# Start the server and test manually
npm run dev

Checkpoint: ✅ No files > 300 lines, all modules properly separated


2.2 Establish Coding Standards

Status: 🔴 Not Started

Steps:

  1. Install Prettier and ESLint plugins
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
cd backend && npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
  1. Create .prettierrc in project root
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "printWidth": 100,
  "trailingComma": "es5",
  "arrowParens": "always",
  "endOfLine": "lf"
}
  1. Update .eslintrc.cjs to use Prettier
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react-hooks/recommended',
    'prettier', // Must be last
  ],
  plugins: ['prettier'],
  rules: {
    'prettier/prettier': 'error',
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/explicit-function-return-type': 'warn',
    'no-console': ['warn', { allow: ['warn', 'error'] }],
  },
};
  1. Create CONTRIBUTING.md
cat > CONTRIBUTING.md << 'EOF'
# Contributing Guidelines

## Code Standards

### File Organization
- **Maximum file size**: 300 lines
- **Maximum function length**: 50 lines
- **Maximum function parameters**: 4 (use objects for more)

### TypeScript
- **Strict mode**: Always enabled
- **No `any` types**: Use proper types or `unknown`
- **Explicit return types**: Required for all functions
- **Interface over type**: Prefer interfaces for objects

### Naming Conventions
- **Files**: kebab-case (e.g., `user-service.ts`)
- **Classes**: PascalCase (e.g., `UserService`)
- **Functions**: camelCase (e.g., `getUserById`)
- **Constants**: UPPER_SNAKE_CASE (e.g., `MAX_RETRY_COUNT`)
- **Interfaces**: PascalCase with optional `I` prefix (e.g., `IUser` or `User`)

### Testing
- **Coverage requirement**: 80% minimum
- **Test file naming**: `*.test.ts` or `*.spec.ts`
- **Test structure**: Arrange-Act-Assert
- **Test descriptions**: Should read like sentences

### Git Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/):
- `feat:` New feature
- `fix:` Bug fix
- `docs:` Documentation changes
- `style:` Code style changes (formatting)
- `refactor:` Code refactoring
- `test:` Adding or updating tests
- `chore:` Maintenance tasks

Example:

feat(auth): add two-factor authentication

  • Implement TOTP-based 2FA
  • Add QR code generation
  • Update user model with 2FA fields

### Pull Requests
1. Create feature branch from `develop`
2. Write tests first (TDD preferred)
3. Ensure all tests pass
4. Run linter: `npm run lint`
5. Check formatting: `npm run format:check`
6. Update documentation if needed
7. Request review from at least one team member

### Code Review Checklist
- [ ] Tests cover new functionality
- [ ] No TypeScript errors or warnings
- [ ] Follows naming conventions
- [ ] No hardcoded configuration
- [ ] Error handling implemented
- [ ] Logging added for debugging
- [ ] Documentation updated
- [ ] No console.log statements (use Logger)
- [ ] Security implications considered
EOF
  1. Add format scripts to package.json
{
  "scripts": {
    "format": "prettier --write \"src/**/*.{ts,tsx}\"",
    "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
    "lint": "eslint . --ext .ts,.tsx --report-unused-disable-directives --max-warnings 0",
    "lint:fix": "eslint . --ext .ts,.tsx --fix"
  }
}
  1. Format entire codebase
npm run format
cd backend && npm run format

Checkpoint: ✅ Code formatted consistently, linting errors fixed, guidelines documented


2.3 Database Migrations

Status: 🔴 Not Started

Steps:

  1. Install migration tool
cd backend
npm install --save-dev migrate-mongo
  1. Initialize migrations
npx migrate-mongo init
  1. Configure migrations - Edit migrate-mongo-config.js:
module.exports = {
  mongodb: {
    url: process.env.MONGO_URI || 'mongodb://localhost:27017',
    databaseName: 'sehatynet',
    options: {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
  },
  migrationsDir: 'migrations',
  changelogCollectionName: 'changelog',
  migrationFileExtension: '.js',
};
  1. Create first migration - Document current schema:
npx migrate-mongo create initial-schema

Edit migrations/XXXXXX-initial-schema.js:

module.exports = {
  async up(db) {
    // Create indexes
    await db.collection('users').createIndex({ email: 1, role: 1 }, { unique: true });
    await db.collection('appointments').createIndex({ patientId: 1 });
    await db.collection('appointments').createIndex({ doctorId: 1 });
    // ... all existing indexes
  },

  async down(db) {
    // Rollback logic
    await db.collection('users').dropIndex('email_1_role_1');
    // ... rollback all changes
  },
};
  1. Update package.json
{
  "scripts": {
    "migrate:up": "migrate-mongo up",
    "migrate:down": "migrate-mongo down",
    "migrate:status": "migrate-mongo status",
    "migrate:create": "migrate-mongo create"
  }
}

Checkpoint: ✅ Migration system in place, current schema documented


Phase 3: Testing & Quality Assurance (Week 7-10)

Goal: Achieve 80%+ test coverage and establish quality gates Time: 3-4 weeks Impact: High - Ensures reliability and enables safe refactoring

3.1 Unit Tests - Backend

Status: 🔴 Not Started

Goal: 80% coverage of backend

Priority Test Areas (in order):

  1. Authentication - src/controllers/auth/__tests__/

    • Registration validation
    • Login success/failure
    • JWT token generation
    • Password reset flow
    • Email verification
  2. Authorization - src/middleware/__tests__/

    • Role-based access control
    • Token validation
    • CSRF protection
  3. Models - src/models/__tests__/

    • Schema validation
    • Field encryption/decryption
    • Hooks and middleware
  4. Services - src/services/__tests__/

    • Business logic
    • Data transformations
    • External API calls (mocked)
  5. Controllers - Integration tests

    • API endpoint responses
    • Error handling
    • Data validation

Example Test Template:

// src/services/__tests__/user.service.test.ts
import { UserService } from '../user.service';
import User from '../../models/user.model';

jest.mock('../../models/user.model');

describe('UserService', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('getUserById', () => {
    it('should return user when found', async () => {
      const mockUser = { _id: '123', email: 'test@example.com' };
      (User.findById as jest.Mock).mockResolvedValue(mockUser);

      const result = await UserService.getUserById('123');

      expect(result).toEqual(mockUser);
      expect(User.findById).toHaveBeenCalledWith('123');
    });

    it('should throw error when user not found', async () => {
      (User.findById as jest.Mock).mockResolvedValue(null);

      await expect(UserService.getUserById('123')).rejects.toThrow('User not found');
    });
  });
});

Run coverage report:

cd backend
npm run test:coverage

Checkpoint: ✅ 80%+ test coverage on backend, all critical paths tested


3.2 Unit Tests - Frontend

Status: 🔴 Not Started

Goal: 70%+ coverage of frontend (slightly lower due to UI complexity)

Priority Test Areas:

  1. Hooks - src/hooks/__tests__/

    • Custom hooks logic
    • State management
  2. Components - src/components/__tests__/

    • Rendering logic
    • User interactions
    • Props handling
  3. Utilities - src/utils/__tests__/ or src/lib/__tests__/

    • Helper functions
    • Formatters
    • Validators

Example Component Test:

// src/components/__tests__/LoginForm.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import LoginForm from '../LoginForm';

describe('LoginForm', () => {
  it('should display validation errors for empty fields', async () => {
    render(<LoginForm />);

    const submitButton = screen.getByRole('button', { name: /login/i });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(screen.getByText(/email is required/i)).toBeInTheDocument();
      expect(screen.getByText(/password is required/i)).toBeInTheDocument();
    });
  });

  it('should call onSubmit with form data when valid', async () => {
    const mockOnSubmit = vi.fn();
    render(<LoginForm onSubmit={mockOnSubmit} />);

    fireEvent.change(screen.getByLabelText(/email/i), {
      target: { value: 'test@example.com' }
    });
    fireEvent.change(screen.getByLabelText(/password/i), {
      target: { value: 'SecurePass123!' }
    });

    fireEvent.click(screen.getByRole('button', { name: /login/i }));

    await waitFor(() => {
      expect(mockOnSubmit).toHaveBeenCalledWith({
        email: 'test@example.com',
        password: 'SecurePass123!'
      });
    });
  });
});

Checkpoint: ✅ 70%+ test coverage on frontend, critical components tested


3.3 End-to-End Tests

Status: 🔴 Not Started

Goal: Cover critical user journeys

Install Playwright:

npm install --save-dev @playwright/test
npx playwright install

Create E2E test structure:

tests/
├── e2e/
│   ├── auth/
│   │   ├── login.spec.ts
│   │   ├── register.spec.ts
│   │   └── password-reset.spec.ts
│   ├── appointments/
│   │   ├── book-appointment.spec.ts
│   │   └── cancel-appointment.spec.ts
│   └── prescriptions/
│       └── create-prescription.spec.ts
└── playwright.config.ts

Example E2E Test:

// tests/e2e/auth/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('User Login', () => {
  test('should successfully login with valid credentials', async ({ page }) => {
    await page.goto('https://localhost:5173');

    await page.click('text=Login');
    await page.fill('input[name="email"]', 'doctor@example.com');
    await page.fill('input[name="password"]', 'SecurePass123!');
    await page.click('button[type="submit"]');

    await expect(page).toHaveURL(/.*dashboard/);
    await expect(page.locator('text=Welcome')).toBeVisible();
  });

  test('should display error with invalid credentials', async ({ page }) => {
    await page.goto('https://localhost:5173');

    await page.click('text=Login');
    await page.fill('input[name="email"]', 'wrong@example.com');
    await page.fill('input[name="password"]', 'wrongpass');
    await page.click('button[type="submit"]');

    await expect(page.locator('text=Invalid credentials')).toBeVisible();
  });
});

Critical Flows to Test:

  1. Patient registration and login
  2. Doctor login and dashboard access
  3. Appointment booking (full flow)
  4. Prescription creation
  5. Medical record viewing
  6. Live consultation joining

Checkpoint: ✅ All critical user journeys have E2E tests


3.4 CI/CD Quality Gates

Status: 🔴 Not Started

Update .github/workflows/ci.yml:

name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  test-backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: |
          cd backend
          npm ci

      - name: Run TypeScript compiler
        run: |
          cd backend
          npm run build

      - name: Run tests
        run: |
          cd backend
          npm test

      - name: Check test coverage
        run: |
          cd backend
          npm run test:coverage -- --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}'

      - name: Lint
        run: |
          cd backend
          npm run lint

  test-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Run TypeScript compiler
        run: npm run build

      - name: Run tests
        run: npm test

      - name: Check test coverage
        run: npm run test:coverage -- --coverage.threshold.lines=70

      - name: Lint
        run: npm run lint

  security-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run npm audit
        run: |
          npm audit --audit-level=moderate
          cd backend && npm audit --audit-level=moderate

      - name: Check for vulnerabilities
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  e2e-tests:
    runs-on: ubuntu-latest
    needs: [test-backend, test-frontend]
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Run E2E tests
        run: npm run test:e2e

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: playwright-report
          path: playwright-report/

Checkpoint: ✅ CI/CD pipeline blocks merges if tests fail or coverage drops


Phase 4: API & Documentation (Week 11-12)

Goal: Add comprehensive API documentation and developer guides Time: 1-2 weeks Impact: Medium - Improves maintainability and onboarding

4.1 API Documentation with Swagger

Status: 🔴 Not Started

Install dependencies:

cd backend
npm install --save swagger-jsdoc swagger-ui-express
npm install --save-dev @types/swagger-jsdoc @types/swagger-ui-express

Create Swagger configuration - backend/src/config/swagger.config.ts:

import swaggerJsdoc from 'swagger-jsdoc';

const options: swaggerJsdoc.Options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'SehatyNet API',
      version: '1.0.0',
      description: 'Telehealth platform API documentation',
      contact: {
        name: 'SehatyNet Team',
        email: 'support@sehatynet.com',
      },
    },
    servers: [
      {
        url: 'http://localhost:5000/api/v1',
        description: 'Development server',
      },
      {
        url: 'https://sehatynet.com/api/v1',
        description: 'Production server',
      },
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
        },
      },
    },
    security: [
      {
        bearerAuth: [],
      },
    ],
  },
  apis: ['./src/routes/*.ts', './src/controllers/**/*.ts'],
};

export const swaggerSpec = swaggerJsdoc(options);

Add to server - in backend/src/server/app.ts:

import swaggerUi from 'swagger-ui-express';
import { swaggerSpec } from '../config/swagger.config';

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

Document endpoints - Example in backend/src/routes/auth.routes.ts:

/**
 * @swagger
 * /auth/register:
 *   post:
 *     summary: Register a new user
 *     tags: [Authentication]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - email
 *               - password
 *               - firstName
 *               - lastName
 *               - role
 *             properties:
 *               email:
 *                 type: string
 *                 format: email
 *               password:
 *                 type: string
 *                 format: password
 *                 minLength: 8
 *               firstName:
 *                 type: string
 *               lastName:
 *                 type: string
 *               role:
 *                 type: string
 *                 enum: [patient, doctor, pharmacy, lab, radiologist]
 *     responses:
 *       201:
 *         description: User created successfully
 *       400:
 *         description: Invalid input
 *       409:
 *         description: Email already exists
 */
router.post('/register', authController.register);

Checkpoint: ✅ All API endpoints documented, accessible at /api-docs


4.2 Consolidate Documentation

Status: 🔴 Not Started

Organize documentation:

docs/
├── README.md                    # Overview
├── getting-started/
│   ├── installation.md
│   ├── local-development.md
│   └── deployment.md
├── architecture/
│   ├── overview.md
│   ├── database-schema.md
│   ├── authentication.md
│   └── file-storage.md
├── api/
│   └── README.md               # Link to Swagger docs
├── user-guides/
│   ├── patient.md
│   ├── doctor.md
│   ├── pharmacy.md
│   └── admin.md
├── compliance/
│   ├── hipaa.md
│   ├── gdpr.md
│   └── security-audit.md
└── contributing/
    ├── code-standards.md       # Link to CONTRIBUTING.md
    ├── testing-guide.md
    └── release-process.md

Migrate existing 138 MD files into this structure

Update root README.md with professional structure:

# SehatyNet - Telehealth Platform

[![CI](https://github.com/user/repo/workflows/CI/badge.svg)]()
[![Coverage](https://img.shields.io/badge/coverage-85%25-green)]()
[![License](https://img.shields.io/badge/license-MIT-blue)]()

## Quick Start

```bash
npm install
npm run dev
```

Documentation

Features

  • 🏥 Multi-role support (Patient, Doctor, Pharmacy, Lab, etc.)
  • 📹 Live video consultations
  • 📋 Digital prescriptions
  • 🔒 HIPAA & GDPR compliant
  • 🌍 Multi-language support
  • 📱 Mobile responsive

Technology Stack

  • Frontend: React 19, TypeScript, Tailwind CSS
  • Backend: Node.js, Express, TypeScript
  • Database: MongoDB with Mongoose
  • Real-time: WebSockets, WebRTC
  • Infrastructure: Docker, Cloud Run, Nginx

License

MIT © SehatyNet Team


**Checkpoint**: ✅ Documentation consolidated, discoverable, and up-to-date

---

## Phase 5: Performance & Polish (Week 13-16)

**Goal**: Optimize performance and add production-grade features
**Time**: 3-4 weeks
**Impact**: Medium-High - Production readiness

### 5.1 Add Caching Layer

**Status**: 🔴 Not Started

**Install Redis**:
```bash
cd backend
npm install redis ioredis
npm install --save-dev @types/redis

Create cache service - backend/src/services/cache.service.ts:

import Redis from 'ioredis';
import { Logger } from '../utils/logger.utils';

class CacheService {
  private client: Redis;

  constructor() {
    this.client = new Redis({
      host: process.env.REDIS_HOST || 'localhost',
      port: parseInt(process.env.REDIS_PORT || '6379'),
      password: process.env.REDIS_PASSWORD,
      retryStrategy: (times) => {
        const delay = Math.min(times * 50, 2000);
        return delay;
      },
    });

    this.client.on('error', (err) => {
      Logger.error('Redis connection error', err);
    });

    this.client.on('connect', () => {
      Logger.info('Redis connected successfully');
    });
  }

  async get<T>(key: string): Promise<T | null> {
    try {
      const value = await this.client.get(key);
      return value ? JSON.parse(value) : null;
    } catch (error) {
      Logger.error(`Cache get error for key ${key}`, error as Error);
      return null;
    }
  }

  async set(key: string, value: any, ttlSeconds: number = 3600): Promise<void> {
    try {
      await this.client.setex(key, ttlSeconds, JSON.stringify(value));
    } catch (error) {
      Logger.error(`Cache set error for key ${key}`, error as Error);
    }
  }

  async del(key: string): Promise<void> {
    try {
      await this.client.del(key);
    } catch (error) {
      Logger.error(`Cache delete error for key ${key}`, error as Error);
    }
  }

  async flush(): Promise<void> {
    try {
      await this.client.flushall();
    } catch (error) {
      Logger.error('Cache flush error', error as Error);
    }
  }
}

export default new CacheService();

Use in controllers:

import CacheService from '../services/cache.service';

// Example: Cache user profile
export const getProfile = async (req: Request, res: Response): Promise<void> => {
  const userId = req.user!._id;
  const cacheKey = `user:${userId}`;

  // Try cache first
  const cachedUser = await CacheService.get(cacheKey);
  if (cachedUser) {
    return res.json(cachedUser);
  }

  // Fetch from database
  const user = await User.findById(userId);

  // Cache for 1 hour
  await CacheService.set(cacheKey, user, 3600);

  res.json(user);
};

Add Redis to docker-compose.yml:

services:
  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'
    volumes:
      - redis-data:/data

volumes:
  redis-data:

Checkpoint: ✅ Redis caching implemented for frequently accessed data


5.2 Database Query Optimization

Status: 🔴 Not Started

Steps:

  1. Add query profiling
// Enable profiling in development
if (process.env.NODE_ENV === 'development') {
  mongoose.set('debug', true);
}
  1. Add indexes for common queries
// In models
userSchema.index({ email: 1 });
userSchema.index({ role: 1, active: 1 });

appointmentSchema.index({ patientId: 1, date: -1 });
appointmentSchema.index({ doctorId: 1, status: 1 });
appointmentSchema.index({ date: 1, status: 1 });

medicalRecordSchema.index({ patientId: 1, createdAt: -1 });
  1. Implement pagination middleware:
// backend/src/middleware/pagination.middleware.ts
export const paginate = (defaultLimit: number = 20, maxLimit: number = 100) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      maxLimit,
      Math.max(1, parseInt(req.query.limit as string) || defaultLimit)
    );
    const skip = (page - 1) * limit;

    req.pagination = { page, limit, skip };
    next();
  };
};
  1. Use lean() for read-only queries:
// Instead of:
const users = await User.find({ role: 'patient' });

// Use:
const users = await User.find({ role: 'patient' }).lean();
  1. Optimize population:
// Instead of eager loading everything:
const appointments = await Appointment.find().populate('patientId').populate('doctorId');

// Select only needed fields:
const appointments = await Appointment.find()
  .populate('patientId', 'firstName lastName email')
  .populate('doctorId', 'firstName lastName specialty');

Checkpoint: ✅ Common queries optimized, pagination implemented, indexes added


5.3 Error Tracking & Monitoring

Status: 🔴 Not Started

Install Sentry:

npm install @sentry/node @sentry/react
cd backend && npm install @sentry/node

Configure Sentry - Backend:

// backend/src/config/sentry.config.ts
import * as Sentry from '@sentry/node';

export const initSentry = () => {
  if (process.env.SENTRY_DSN) {
    Sentry.init({
      dsn: process.env.SENTRY_DSN,
      environment: process.env.NODE_ENV || 'development',
      tracesSampleRate: 0.1,
      beforeSend(event, hint) {
        // Don't send development errors
        if (process.env.NODE_ENV === 'development') {
          return null;
        }
        return event;
      },
    });
  }
};

Add to server startup:

import { initSentry } from './config/sentry.config';
initSentry();

Configure Sentry - Frontend:

// src/config/sentry.config.ts
import * as Sentry from '@sentry/react';

export const initSentry = () => {
  if (import.meta.env.VITE_SENTRY_DSN) {
    Sentry.init({
      dsn: import.meta.env.VITE_SENTRY_DSN,
      environment: import.meta.env.MODE,
      integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
      tracesSampleRate: 0.1,
      replaysSessionSampleRate: 0.1,
      replaysOnErrorSampleRate: 1.0,
    });
  }
};

Checkpoint: ✅ Error tracking configured, production errors monitored


Validation & Metrics

After completing all phases, validate your progress:

Code Quality Metrics

Run these commands to verify improvements:

# Backend
cd backend

# Type safety
npm run build  # Should complete without errors

# Test coverage
npm run test:coverage  # Should show 80%+ coverage

# Code quality
npm run lint  # Should have zero errors

# Frontend
cd ..

# Type safety
npm run build  # Should complete without errors

# Test coverage
npm run test:coverage  # Should show 70%+ coverage

# Code quality
npm run lint  # Should have zero errors

Professional Checklist

  • Testing: 80%+ coverage, all critical paths tested
  • Type Safety: Strict TypeScript, no any types
  • Code Organization: No files > 300 lines
  • Configuration: No hardcoded values
  • Documentation: API docs, architecture docs, user guides
  • Security: Dependency scanning, secrets management
  • Performance: Caching, query optimization, pagination
  • CI/CD: Quality gates, automated testing
  • Monitoring: Error tracking, logging, metrics
  • Git: Clean history, no sensitive files

Final Score Estimation

Track your score improvement:

CategoryBeforeTargetCurrent
Testing0/109/10___/10
Type Safety3/109/10___/10
Code Organization5/109/10___/10
Documentation6/109/10___/10
Security7/109/10___/10
Performance5/108/10___/10
Overall6.5/109/10___/10

Skill Usage Instructions

Starting a Phase

  1. Read the entire phase description
  2. Update PROGRESS.md with phase start
  3. Create a feature branch for the phase
  4. Work through steps sequentially
  5. Validate at each checkpoint
  6. Create PR when phase complete
  7. Update PROGRESS.md with completion

When to Ask for Help

  • TypeScript errors seem impossible to fix
  • Test coverage stuck below target
  • Performance optimizations not working
  • Breaking changes to API
  • Migration issues

Tracking Progress

Create PROGRESS.md in project root:

# Code Professionalization Progress

## Phase 1: Critical Fixes

- [x] 1.1 Enable TypeScript Strict Mode
- [x] 1.2 Add Testing Infrastructure
- [ ] 1.3 Extract Configuration
- [ ] 1.4 Fix Git Hygiene

**Status**: In Progress
**Started**: 2026-01-19
**Estimated Completion**: 2026-02-02

## Phase 2: Code Quality

- [ ] 2.1 Refactor Large Files
- [ ] 2.2 Establish Coding Standards
- [ ] 2.3 Database Migrations

**Status**: Not Started

<!-- etc. -->

Success Criteria

Phase 1 Complete

  • TypeScript compiles in strict mode
  • At least 20 tests passing
  • No hardcoded configuration
  • Clean Git history

Phase 2 Complete

  • No files > 300 lines
  • Code formatted consistently
  • Migration system in place
  • CONTRIBUTING.md created

Phase 3 Complete

  • 80%+ backend coverage
  • 70%+ frontend coverage
  • E2E tests for critical flows
  • CI/CD blocking on test failures

Phase 4 Complete

  • All endpoints documented
  • Documentation consolidated
  • Developer onboarding guide

Phase 5 Complete

  • Caching implemented
  • Queries optimized
  • Error tracking enabled
  • Performance benchmarked

Overall Success 🎯

  • Code score improved from 6.5/10 to 9/10
  • Professional code review would pass
  • Safe to onboard new developers
  • Production-ready for enterprise

Notes

  • Don't skip phases - Each builds on the previous
  • Validate at checkpoints - Don't move forward if checkpoints fail
  • Track progress - Update PROGRESS.md regularly
  • Get code reviews - Have someone review each phase
  • Celebrate wins - Each phase complete is a major achievement

This is a marathon, not a sprint. Professional code quality is built incrementally.

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

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

レビュー

💬

レビュー機能は近日公開予定です