Development guidelines for Safarnak, an offline-first travel app built with Expo React Native, Cloudflare Workers, GraphQL, and Drizzle ORM in a single-root monorepo architecture.
Guidelines for developing Safarnak, a full-stack offline-first travel application built as a single-root monorepo.
Safarnak is a unified monorepo where client and server code coexist:
```
worker/ # Server resolvers & entry (index.ts)
graphql/ # Shared schema + operations
api/ # Client GraphQL types & hooks (generated)
database/ # Shared schema with separate adapters
├── schema.ts # Unified schema (server + client tables)
├── server.ts # D1 adapter (getServerDB)
├── client.ts # SQLite adapter (getLocalDB)
migrations/ # Server-only migrations (D1)
store/ # Redux store, slices, middleware
app/ # Expo Router pages
components/ # UI components & contexts
```
**NEVER use relative imports. Always use path aliases:**
```typescript
"@/*" → "./*"
"@ui/*" → "./ui/*"
"@graphql/*" → "./graphql/*"
"@database/*" → "./database/*"
"@worker/*" → "./worker/*"
"@api" → "./api"
"@api/*" → "./api/*"
"@state" → "./ui/state"
"@state/*" → "./ui/state/*"
"@hooks" → "./ui/hooks"
"@hooks/*" → "./ui/hooks/*"
"@constants" → "./constants"
"@constants/*" → "./constants/*"
```
1. **NEVER add `"type": "module"` to package.json**
2. **Keep `eslint.config.mjs`** - do not convert ESLint config type
3. **Strict code separation**:
- `graphql/` - shared between client and worker
- `api/` - client-only, generated (never edit manually)
- `worker/` - server-only resolvers
- `database/schema.ts` - single source of truth for both server and client
4. **Always run `yarn codegen` after changing GraphQL schema or operations**
5. **Never manually edit** `api/types.ts` or `api/hooks.ts` (auto-generated)
6. **Use path aliases exclusively** - avoid all relative imports
7. **Prefer NativeWind Tailwind classes** via `className` over inline styles
8. **Run `yarn db:migrate`** before testing APIs locally
9. **Worker entry is `worker/index.ts`** - defined in `wrangler.toml`
```typescript
// In worker resolvers
import { getServerDB } from '@database/server';
const db = getServerDB(env.DB);
// In client components
import { getLocalDB } from '@database/client';
const db = getLocalDB();
```
1. Edit `graphql/schema.graphql`
2. Add/modify operations in `graphql/queries/*.graphql`
3. Run `yarn codegen` to regenerate `api/types.ts` and `api/hooks.ts`
4. Implement resolvers in `worker/queries`, `worker/mutations`, or `worker/subscriptions`
```typescript
import { useGetTripsQuery, useCreateTripMutation } from '@api';
```
- `EXPO_PUBLIC_GRAPHQL_URL_DEV` or `EXPO_PUBLIC_GRAPHQL_URL`
- `GRAPHQL_URL_DEV` or `GRAPHQL_URL`
```bash
yarn dev # Start worker (8787) + Expo dev server
yarn start # Expo dev server only
yarn worker:dev # Worker only
```
```bash
yarn codegen # Generate types & hooks
yarn codegen:watch # Watch mode
```
```bash
yarn db:generate # Generate migration from schema
yarn db:migrate # Apply migrations to local D1
yarn db:studio # Drizzle Studio
```
```bash
yarn android # Run on Android
yarn build:debug # EAS debug build (Android)
yarn build:release # EAS release build (Android)
```
```bash
yarn lint # Run ESLint
yarn lint:fix # Fix ESLint issues
yarn clean # Clean cache
```
1. Validate all resolver inputs; fail fast on invalid data
2. Drizzle ORM prevents SQL injection
3. Keep tokens and secrets out of client code
4. Use PBKDF2 for password hashing (100k iterations)
5. Implement proper authorization checks in resolvers
1. Use `React.memo`, `useCallback`, `useMemo` judiciously
2. Keep Redux state lean
3. Leverage Apollo cache appropriately
4. Use NativeWind classes for styling efficiency
5. Implement offline-first patterns with Redux middleware
When making changes to Safarnak:
1. **GraphQL First**: Update `graphql/schema.graphql` and operations, then run `yarn codegen`
2. **Implement Resolvers**: Add/modify resolvers in `worker/` only
3. **Use Path Aliases**: Never use relative imports
4. **Database Changes**:
- Modify `database/schema.ts` (unified schema)
- Use `@database/server` in worker resolvers
- Use `@database/client` in client components
- Run `yarn db:generate` and `yarn db:migrate`
5. **Never Edit Generated Files**: Don't touch `api/hooks.ts` or `api/types.ts`
6. **Follow Patterns**: Maintain existing directory ownership and conventions
7. **Style with NativeWind**: Prefer `className` over inline styles
- `feat:` → minor bump
- `fix:` → patch bump
- others → build only
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/safarnak-travel-app-development/raw