Technical reference for AI assistants working on Folk Care - open source home healthcare software with EVV, scheduling, care plans, and billing. Covers architecture, development workflow, database patterns, and multi-agent coordination.
Technical reference for AI assistants working on Folk Care - open source home healthcare software for community-owned agencies.
**Repository:** https://github.com/neighborhood-lab/folk-care
**License:** AGPL-3.0
**Stack:** TypeScript, Node.js, Express, React, React Native, PostgreSQL, Turborepo
This skill provides comprehensive guidance for AI assistants working on the Folk Care codebase, including:
When starting work on Folk Care:
```bash
git clone https://github.com/neighborhood-lab/folkcare.git
cd folkcare
nvm use # Requires Node.js 22.x
npm install
docker compose up -d
cp .env.example .env
npm run db:migrate
npm run db:seed
npm run dev
```
**Technology Stack:**
**Core Principles:**
1. **ESM Everywhere** - All imports use `.js` extensions, `type: "module"` in package.json
2. **Service-Repository Pattern** - Business logic separated from data access
3. **Permission-Based Access** - Fine-grained control via `PermissionService`
4. **Audit Trail** - Immutable revision history for compliance
5. **Monorepo Structure** - Turborepo manages packages and verticals
```
folkcare/
├── packages/
│ ├── core/ # Shared domain logic, database, permissions
│ ├── app/ # Express REST API
│ ├── web/ # React frontend
│ ├── mobile/ # React Native mobile app
│ └── shared-components/ # Shared UI components
├── verticals/ # Business domain modules
│ ├── client-demographics/
│ ├── caregiver-staff/
│ ├── scheduling-visits/
│ ├── time-tracking-evv/
│ ├── care-plans-tasks/
│ └── billing-invoicing/
├── showcase/ # Static demo (GitHub Pages)
├── api/ # Vercel serverless functions
└── scripts/ # Repository utilities
```
**Each vertical follows this pattern:**
```
verticals/vertical-name/
├── src/
│ ├── service.ts # Business logic layer
│ ├── repository.ts # Database access layer
│ ├── types.ts # TypeScript types
│ ├── routes.ts # Express route handlers
│ └── validation.ts # Zod schemas
└── tests/
├── service.test.ts # Service unit tests
└── routes.test.ts # API integration tests
```
**Service-Repository Pattern:**
```typescript
// Repository (Data Access)
export class ClientRepository {
constructor(private db: Knex) {}
async findById(id: string): Promise<Client | null> {
const row = await this.db('clients')
.where({ id, is_deleted: false })
.first();
return row ? this.mapToClient(row) : null;
}
}
// Service (Business Logic)
export class ClientService {
constructor(
private repository: ClientRepository,
private auditService: AuditService,
private permissionService: PermissionService
) {}
async getClient(id: string, userId: string): Promise<Client> {
// Check permissions
await this.permissionService.requirePermission(userId, 'clients', 'read');
const client = await this.repository.findById(id);
if (!client) throw new NotFoundError('Client not found');
// Log audit trail
await this.auditService.log({
userId, action: 'read', resource: 'client', resourceId: id
});
return client;
}
}
```
**ESM Import Rules (CRITICAL):**
```typescript
// ✅ CORRECT - Always use .js extension
import { ClientService } from './service.js';
import { getDatabase } from '@folkcare/core/db.js';
// ❌ WRONG - No extension
import { ClientService } from './service';
// ❌ WRONG - CommonJS
const { getDatabase } = require('./db');
```
**Zod Validation:**
```typescript
import { z } from 'zod';
export const createClientSchema = z.object({
firstName: z.string().min(1).max(100),
lastName: z.string().min(1).max(100),
dateOfBirth: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
organizationId: z.string().uuid()
});
// In route handler
app.post('/api/clients', async (req, res) => {
const data = createClientSchema.parse(req.body);
const client = await clientService.createClient(data, req.user.id);
res.json(client);
});
```
```bash
npm run dev # Start all packages in watch mode
npm run build # Build all packages for production
npm run lint # Lint all packages
npm run typecheck # Type check all packages
npm run test # Run all tests
./scripts/check.sh # Full CI suite (lint + typecheck + test + build)
npm run db:migrate # Run migrations
npm run db:seed # Seed demo data
npm run db:reset # Reset database (migrate + seed)
/quick-check # Fast validation (lint + typecheck)
/full-check # Complete CI suite
/db-reset-local # Reset local database
/capture-showcase # Screenshot local showcase
/capture-production # Screenshot production showcase
```
**Service Unit Tests:**
```typescript
import { describe, it, expect, beforeEach } from 'vitest';
import { ClientService } from '../src/service.js';
describe('ClientService', () => {
let service: ClientService;
beforeEach(() => {
service = new ClientService(mockRepo, mockAudit, mockPermissions);
});
it('should get client by id', async () => {
const client = await service.getClient('123', 'user-1');
expect(client.id).toBe('123');
});
});
```
**API Integration Tests:**
```typescript
import request from 'supertest';
import { app } from '../src/server.js';
describe('POST /api/clients', () => {
it('should create client', async () => {
const response = await request(app)
.post('/api/clients')
.set('Authorization', `Bearer ${token}`)
.send({ firstName: 'John', lastName: 'Doe' });
expect(response.status).toBe(201);
expect(response.body.firstName).toBe('John');
});
});
```
Multiple Claude Code instances can work in parallel:
**Per-Instance Configuration:**
1. **Separate checkout directory** - Each agent in own clone
2. **Unique port numbers** - Avoid conflicts
- Primary: Backend 3000, Web 5173, Mobile 8081
- Secondary: Backend 3001, Web 5174, Mobile 8082
3. **Separate database** - Different DB name per agent
```bash
# Primary: folk-care-0 (default)
# Secondary: folk-care-0-tove
docker exec -it folk-care-0-db psql -U postgres -c 'CREATE DATABASE "folk-care-0-tove"'
```
4. **Own .secrets.txt** - Instance-specific credentials
**Coordination Guidelines:**
**CRITICAL: MCP Servers are PERMANENTLY DISABLED**
DO NOT enable MCP servers. They are a security risk and redundant:
**Verify MCP is disabled:**
```bash
claude mcp list
```
**Permission Checking:**
```typescript
// Always check permissions before data access
await permissionService.requirePermission(userId, 'clients', 'read');
// Check multiple permissions
await permissionService.requireAnyPermission(userId, [
['clients', 'read'],
['clients', 'write']
]);
```
**Audit Logging:**
```typescript
// Log all significant actions
await auditService.log({
userId,
action: 'update',
resource: 'client',
resourceId: clientId,
changes: { firstName: 'New Name' }
});
```
Screenshots are the primary verification technique after UI changes:
1. Make changes locally
2. Run `/capture-showcase` - captures local screenshots
3. Review screenshots in `ui-screenshots-personas/showcase/`
4. Deploy to develop branch
5. Run `/capture-production` - captures production screenshots
6. Compare screenshots to verify deployment success
When modifying schema:
```bash
npm run db:migration:create -- migration_name
npm run db:migrate
npm run db:migration:rollback
```
**Migration pattern:**
```typescript
export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable('table_name', (table) => {
table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()'));
table.string('name', 255).notNullable();
table.timestamp('created_at').defaultTo(knex.fn.now());
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTable('table_name');
}
```
1. **Always use .js extensions in imports** - ESM requirement
2. **Never enable MCP servers** - Security risk
3. **Check permissions before data access** - Use PermissionService
4. **Log audit trail for compliance** - Use AuditService
5. **Follow service-repository pattern** - Keep business logic separate from data access
6. **Use Zod for validation** - Runtime type safety
7. **Screenshot verification for UI changes** - Primary verification technique
8. **Multi-agent coordination** - Use separate branches and databases
**Creating a new vertical:**
```bash
mkdir -p verticals/new-vertical/src
mkdir -p verticals/new-vertical/tests
npm run db:migration:create -- add_new_vertical_tables
npm run dev
npm run test
./scripts/check.sh
```
**Making a pull request:**
```bash
git checkout -b feature/description
git add .
git commit -m "feat: description"
git push origin feature/description
gh pr create --repo neighborhood-lab/folk-care --title "Title" --body "Description"
/capture-showcase
/capture-production
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/folk-care-development-guide/raw