Build privacy-first personal data bank features with encryption, audit trails, and granular consent management. Follows LucidData patterns for Next.js 15, Prisma, and Supabase Auth.
Build features for LucidData, a privacy-first personal data bank that empowers users to own, control, and share their data on their terms. Follow established patterns for encryption, audit logging, and consent management.
1. Always encrypt vault data before storing using `lib/crypto/encryption.ts`
2. Never log decrypted data in errors, logs, or responses
3. Use `getMasterKey()` only - never access `process.env.ENCRYPTION_KEY` directly
4. Store IV format as `"hexIv:hexAuthTag"` in the `iv` field (colon-separated hex strings)
1. Create audit log for ALL vault/consent operations (create, read, update, delete, grant, revoke)
2. Include `previousHash` to maintain immutable chain integrity
3. Use `lib/crypto/hashing.ts` - `createAuditHash()` for hash generation
4. Never modify existing audit log entries (immutable by design)
1. Always validate user with `lib/supabase/server.ts` in API routes
2. Always check `user` exists before proceeding (never assume authentication)
3. Filter all queries by `userId` - never trust client-provided IDs
4. Use correct Supabase client: server for API routes, client for Client Components
Before implementing ANY feature:
1. Review `.github/copilot/critical/security-patterns.md` for encryption, auth, and audit patterns
2. Check `.github/copilot/critical/api-patterns.md` for API route structure
3. Review `.github/copilot/critical/database-schema.md` for data models
4. Consult `.github/copilot/common/component-patterns.md` for UI patterns
For API routes:
```typescript
import { createClient } from '@/lib/supabase/server';
export async function GET(request: Request) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Filter all queries by user.id
}
```
For vault data:
```typescript
import { encrypt, decrypt } from '@/lib/crypto/encryption';
// Storing data
const { encryptedData, iv, authTag } = encrypt(JSON.stringify(data));
const ivString = `${iv.toString('hex')}:${authTag.toString('hex')}`;
// Retrieving data
const [ivHex, authTagHex] = record.iv.split(':');
const decryptedData = decrypt(
record.encryptedData,
Buffer.from(ivHex, 'hex'),
Buffer.from(authTagHex, 'hex')
);
```
For all vault/consent operations:
```typescript
import { createAuditHash, getLastAuditLog } from '@/lib/crypto/hashing';
import { db } from '@/lib/db';
const lastLog = await getLastAuditLog(userId);
const currentHash = createAuditHash({
userId,
eventType: 'data_created',
action: 'Created vault entry',
actorId: userId,
actorType: 'user',
previousHash: lastLog?.currentHash || null,
timestamp: new Date(),
});
await db.auditLog.create({
data: {
userId,
vaultDataId,
eventType: 'data_created',
action: 'Created vault entry',
actorId: userId,
actorType: 'user',
currentHash,
previousHash: lastLog?.currentHash,
ipAddress: getClientIp(request),
timestamp: new Date(),
},
});
```
Use Zod schemas from `lib/validations/`:
```typescript
import { vaultDataSchema } from '@/lib/validations/vault';
// In API routes (throws on failure)
const validatedData = vaultDataSchema.parse(await request.json());
// In forms (returns result)
const result = vaultDataSchema.safeParse(formData);
if (!result.success) {
// Handle validation errors
}
```
Default to Server Components:
```typescript
// Server Component (no 'use client')
export default async function VaultPage() {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
// Direct database access
}
// Client Component (only for interactivity)
'use client';
import { useState } from 'react';
export function VaultForm() {
const [data, setData] = useState('');
// Event handlers, state, effects
}
```
Never expose sensitive details:
```typescript
try {
// Operation
} catch (error) {
console.error('Internal error:', error); // Log server-side only
return Response.json(
{ error: 'Operation failed' }, // Generic message
{ status: 500 }
);
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/luciddata-privacy-first-development/raw