First commit
This commit is contained in:
248
best_practices.md
Normal file
248
best_practices.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# 📘 Project Best Practices
|
||||
|
||||
## 1. Project Purpose
|
||||
LynkedUp is a mobile-first, SDK-driven application suite with enterprise-grade security and offline-first capabilities. It is structured as a PNPM monorepo orchestrated by Nx, providing modular Core SDKs (security, storage, sync, policy, trust) and Feature SDKs (auth, tasks, messaging, etc.) consumed by React Native apps and a Node.js GraphQL BFF.
|
||||
|
||||
## 2. Project Structure
|
||||
- Monorepo
|
||||
- apps/
|
||||
- lynkedup-pro/ and lynkedup-foundation/: React Native apps demonstrating SDK composition.
|
||||
- api-bff/: Node.js Fastify + Apollo GraphQL Backend For Frontend.
|
||||
- sdk-playground/: Development sandbox for SDKs.
|
||||
- packages/
|
||||
- core/: Tier-0 infrastructure SDKs (e.g., security, storage, sync, policy-client, runtime, trust).# 📘 Project Best Practices
|
||||
|
||||
## 1. Project Purpose
|
||||
LynkedUp is a mobile-first, SDK-driven application suite with enterprise-grade security and offline-first capabilities. It is structured as a PNPM monorepo orchestrated by Nx, providing modular Core SDKs (security, storage, sync, policy, trust) and Feature SDKs (auth, tasks, messaging, etc.) consumed by React Native apps and a Node.js GraphQL BFF.
|
||||
|
||||
## 2. Project Structure
|
||||
- Monorepo
|
||||
- apps/
|
||||
- lynkedup-pro/ and lynkedup-foundation/: React Native apps demonstrating SDK composition.
|
||||
- api-bff/: Node.js Fastify + Apollo GraphQL Backend For Frontend.
|
||||
- sdk-playground/: Development sandbox for SDKs.
|
||||
- packages/
|
||||
- core/: Tier-0 infrastructure SDKs (e.g., security, storage, sync, policy-client, runtime, trust).
|
||||
- feature-*/: Tier-1 feature SDKs following clean architecture (domain, data, ui-rn).
|
||||
- shared/: Common types, config, and UI kit.
|
||||
- Tooling & Config: Nx, ESLint, Prettier, Changesets, Commitlint.
|
||||
|
||||
- Separation of concerns (Clean Architecture conventions)
|
||||
- Feature SDKs:
|
||||
- domain/: Pure business logic (use cases, entities, interfaces). No platform or infra dependencies.
|
||||
- data/: Repositories/adapters that implement domain interfaces and talk to core SDKs and BFF.
|
||||
- ui-rn/: React Native components and navigation.
|
||||
- Core SDKs provide foundational services (e.g., SecurityCore, StorageCore) that feature data layers depend on.
|
||||
- Apps initialize and compose SDKs; they own configuration and feature toggles.
|
||||
|
||||
- Entry points & configuration
|
||||
- apps/api-bff/src/main.ts: Fastify server + Apollo schema wiring and middleware registration.
|
||||
- apps/*/App.tsx: SDK initialization sequence (Security → Storage → Sync → Runtime → Trust) and navigation bootstrapping.
|
||||
- packages/*/src/index.ts: Barrel files re-exporting public API for each package.
|
||||
- tsconfig.base.json: Strict TypeScript with path aliases for all packages.
|
||||
|
||||
## 3. Test Strategy
|
||||
- Framework: Jest (Nx managed). Use per-package unit tests with co-located *.spec.ts(x) files.
|
||||
- Suggested organization (based on architecture):
|
||||
- Domain layer: Unit tests for use cases (pure, no I/O). Mock via interfaces.
|
||||
- Data layer: Contract tests for GraphQL and network using MSW; integration tests with core SDKs.
|
||||
- Core SDKs: Unit tests for deterministic logic; integration tests for cross-SDK interactions.
|
||||
- Apps: E2E tests with Detox for key flows.
|
||||
- Mocking guidelines:
|
||||
- Mock via domain interfaces (e.g., IAuthRepository, ITrustRepository) rather than concrete classes.
|
||||
- For GraphQL, prefer MSW to mock network boundaries rather than stubbing internals.
|
||||
- Use dependency injection to pass fakes/mocks into use cases.
|
||||
- Coverage expectations:
|
||||
- Aim high on domain logic (>90%).
|
||||
- Maintain pragmatic coverage for data/adapters; prefer integration and contract tests.
|
||||
- CI:
|
||||
- Use nx affected:test for efficient runs.
|
||||
|
||||
## 4. Code Style
|
||||
- Languages & typing
|
||||
- TypeScript with strict mode enabled. Prefer precise types and interfaces over any.
|
||||
- Public APIs should have explicit return types (ESLint warns on missing types).
|
||||
- Favor async/await over promise chains; avoid top-level side effects.
|
||||
- Naming conventions
|
||||
- Classes: PascalCase (e.g., SecurityCore, LoginUseCase).
|
||||
- Functions/variables: camelCase.
|
||||
- Files: index.ts as package barrels; core classes often use PascalCase file names (e.g., SecurityCore.ts). Keep barrels aligned with actual exports.
|
||||
- Packages follow scopes (@core/*, @feature-*/domain|data|ui-rn, @shared/*).
|
||||
- Formatting
|
||||
- Prettier: singleQuote, semi, printWidth 100, arrowParens avoid, LF line endings.
|
||||
- Enforced via lint-staged on staged files.
|
||||
- Lint rules & boundaries
|
||||
- ESLint: no-unused-vars (ignore args prefixed with _), explicit-function-return-type warn.
|
||||
- Module boundaries via @nx/enforce-module-boundaries with tags:
|
||||
- type:domain → only depend on [type:domain, type:types, scope:shared].
|
||||
- type:data → depend on [type:domain, type:types, scope:core, scope:shared].
|
||||
- type:ui → depend on [type:data, type:domain, type:types, scope:shared].
|
||||
- scope:feature cannot depend on other scope:feature.
|
||||
- scope:core only depends on [scope:core, scope:shared, type:types].
|
||||
- platform:shared cannot depend on platform:rn or platform:node.
|
||||
- Ensure each Nx library is properly tagged to satisfy these constraints.
|
||||
- Documentation & comments
|
||||
- Use concise JSDoc for public APIs and to mark FRD references (e.g., F.SC.004).
|
||||
- Map errors to user-friendly codes/messages at boundaries (see LoginUseCase.handleLoginError).
|
||||
- Error handling
|
||||
- Guard methods with ensureInitialized() where applicable (e.g., SecurityCore, StorageCore).
|
||||
- On server, do not expose internals in production (see BFF formatError).
|
||||
|
||||
## 5. Common Patterns
|
||||
- Clean Architecture layering (UI → Data → Domain → Shared Types) and dependency inversion via interfaces.
|
||||
- SDK initialization order in apps: Security → Storage → Sync → Runtime → Trust → Feature SDKs.
|
||||
- Barrel exports (index.ts) per package for a stable public surface.
|
||||
- GraphQL BFF:
|
||||
- Fastify plugins for security (helmet, cors) and custom plugins (security, rateLimit).
|
||||
- Middleware order: DPoP → Auth → Policy (ABAC) before GraphQL handler.
|
||||
- Dynamic imports for optional dependencies (e.g., Permit.io client).
|
||||
- Security & cryptography
|
||||
- Hardware-backed keys, DPoP proof generation, envelope encryption with organizational DEKs.
|
||||
- Cryptographic erasure and secure wipe via key management.
|
||||
- Offline-first storage
|
||||
- Encrypted local DB, schema registry, selective purge by organization, re-keying (planned).
|
||||
|
||||
## 6. Do's and Don'ts
|
||||
- Do
|
||||
- Initialize core SDKs in the documented order before feature initialization.
|
||||
- Keep domain logic pure and free from platform or network code.
|
||||
- Depend on interfaces in domain; implement in data with adapters to core SDKs/BFF.
|
||||
- Use path aliases from tsconfig.base.json; export public API via index.ts.
|
||||
- Respect ESLint module boundaries and Nx tags; add proper library tags when creating new packages.
|
||||
- Map server errors to safe messages in production; log full details server-side only.
|
||||
- Use MSW for network contract tests; keep unit tests fast and deterministic.
|
||||
- Follow Conventional Commits with configured scopes and the additional `security` type.
|
||||
- Keep barrel files accurate and synchronized with actual implementation files.
|
||||
- Don't
|
||||
- Import across features (no feature-to-feature dependencies).
|
||||
- Make domain depend on data/core/platform code.
|
||||
- Bypass ensureInitialized guards in core SDKs.
|
||||
- Expose stack traces or sensitive details to clients in production.
|
||||
- Hardcode secrets or environment-specific values; use config and env vars.
|
||||
- Introduce Node-specific APIs into React Native code paths.
|
||||
|
||||
## 7. Tools & Dependencies
|
||||
- Tooling
|
||||
- PNPM workspaces + Nx orchestration (caching, affected commands).
|
||||
- ESLint + Prettier + lint-staged; commitlint with conventional commits.
|
||||
- Changesets for versioning and publishing (SDK packages only).
|
||||
- Key libraries
|
||||
- Apps: React Native, React Navigation.
|
||||
- BFF: Fastify, @apollo/server, @graphql-tools/schema, @fastify/cors, @fastify/helmet, optional Permit.io.
|
||||
- Core SDKs: Security (DPoP, key management, encryption), Storage (encrypted DB, schema registry), Sync/Runtime/Trust (per architecture).
|
||||
- Setup
|
||||
- Install: pnpm install; build: pnpm nx run-many -t build.
|
||||
- Dev scripts: dev:playground, dev:pro, dev:foundation.
|
||||
- Tests: pnpm test or pnpm affected:test.
|
||||
- BFF env vars: NODE_ENV, PORT (default 4000), HOST (default 0.0.0.0), PERMIT_PDP_URL, PERMIT_API_KEY.
|
||||
|
||||
- Separation of concerns (Clean Architecture conventions)
|
||||
- Feature SDKs:
|
||||
- domain/: Pure business logic (use cases, entities, interfaces). No platform or infra dependencies.
|
||||
- data/: Repositories/adapters that implement domain interfaces and talk to core SDKs and BFF.
|
||||
- ui-rn/: React Native components and navigation.
|
||||
- Core SDKs provide foundational services (e.g., SecurityCore, StorageCore) that feature data layers depend on.
|
||||
- Apps initialize and compose SDKs; they own configuration and feature toggles.
|
||||
|
||||
- Entry points & configuration
|
||||
- apps/api-bff/src/main.ts: Fastify server + Apollo schema wiring and middleware registration.
|
||||
- apps/*/App.tsx: SDK initialization sequence (Security → Storage → Sync → Runtime → Trust) and navigation bootstrapping.
|
||||
- packages/*/src/index.ts: Barrel files re-exporting public API for each package.
|
||||
- tsconfig.base.json: Strict TypeScript with path aliases for all packages.
|
||||
|
||||
## 3. Test Strategy
|
||||
- Framework: Jest (Nx managed). Use per-package unit tests with co-located *.spec.ts(x) files.
|
||||
- Suggested organization (based on architecture):
|
||||
- Domain layer: Unit tests for use cases (pure, no I/O). Mock via interfaces.
|
||||
- Data layer: Contract tests for GraphQL and network using MSW; integration tests with core SDKs.
|
||||
- Core SDKs: Unit tests for deterministic logic; integration tests for cross-SDK interactions.
|
||||
- Apps: E2E tests with Detox for key flows.
|
||||
- Mocking guidelines:
|
||||
- Mock via domain interfaces (e.g., IAuthRepository, ITrustRepository) rather than concrete classes.
|
||||
- For GraphQL, prefer MSW to mock network boundaries rather than stubbing internals.
|
||||
- Use dependency injection to pass fakes/mocks into use cases.
|
||||
- Coverage expectations:
|
||||
- Aim high on domain logic (>90%).
|
||||
- Maintain pragmatic coverage for data/adapters; prefer integration and contract tests.
|
||||
- CI:
|
||||
- Use nx affected:test for efficient runs.
|
||||
|
||||
## 4. Code Style
|
||||
- Languages & typing
|
||||
- TypeScript with strict mode enabled. Prefer precise types and interfaces over any.
|
||||
- Public APIs should have explicit return types (ESLint warns on missing types).
|
||||
- Favor async/await over promise chains; avoid top-level side effects.
|
||||
- Naming conventions
|
||||
- Classes: PascalCase (e.g., SecurityCore, LoginUseCase).
|
||||
- Functions/variables: camelCase.
|
||||
- Files: index.ts as package barrels; core classes often use PascalCase file names (e.g., SecurityCore.ts). Keep barrels aligned with actual exports.
|
||||
- Packages follow scopes (@core/*, @feature-*/domain|data|ui-rn, @shared/*).
|
||||
- Formatting
|
||||
- Prettier: singleQuote, semi, printWidth 100, arrowParens avoid, LF line endings.
|
||||
- Enforced via lint-staged on staged files.
|
||||
- Lint rules & boundaries
|
||||
- ESLint: no-unused-vars (ignore args prefixed with _), explicit-function-return-type warn.
|
||||
- Module boundaries via @nx/enforce-module-boundaries with tags:
|
||||
- type:domain → only depend on [type:domain, type:types, scope:shared].
|
||||
- type:data → depend on [type:domain, type:types, scope:core, scope:shared].
|
||||
- type:ui → depend on [type:data, type:domain, type:types, scope:shared].
|
||||
- scope:feature cannot depend on other scope:feature.
|
||||
- scope:core only depends on [scope:core, scope:shared, type:types].
|
||||
- platform:shared cannot depend on platform:rn or platform:node.
|
||||
- Ensure each Nx library is properly tagged to satisfy these constraints.
|
||||
- Documentation & comments
|
||||
- Use concise JSDoc for public APIs and to mark FRD references (e.g., F.SC.004).
|
||||
- Map errors to user-friendly codes/messages at boundaries (see LoginUseCase.handleLoginError).
|
||||
- Error handling
|
||||
- Guard methods with ensureInitialized() where applicable (e.g., SecurityCore, StorageCore).
|
||||
- On server, do not expose internals in production (see BFF formatError).
|
||||
|
||||
## 5. Common Patterns
|
||||
- Clean Architecture layering (UI → Data → Domain → Shared Types) and dependency inversion via interfaces.
|
||||
- SDK initialization order in apps: Security → Storage → Sync → Runtime → Trust → Feature SDKs.
|
||||
- Barrel exports (index.ts) per package for a stable public surface.
|
||||
- GraphQL BFF:
|
||||
- Fastify plugins for security (helmet, cors) and custom plugins (security, rateLimit).
|
||||
- Middleware order: DPoP → Auth → Policy (ABAC) before GraphQL handler.
|
||||
- Dynamic imports for optional dependencies (e.g., Permit.io client).
|
||||
- Security & cryptography
|
||||
- Hardware-backed keys, DPoP proof generation, envelope encryption with organizational DEKs.
|
||||
- Cryptographic erasure and secure wipe via key management.
|
||||
- Offline-first storage
|
||||
- Encrypted local DB, schema registry, selective purge by organization, re-keying (planned).
|
||||
|
||||
## 6. Do's and Don'ts
|
||||
- Do
|
||||
- Initialize core SDKs in the documented order before feature initialization.
|
||||
- Keep domain logic pure and free from platform or network code.
|
||||
- Depend on interfaces in domain; implement in data with adapters to core SDKs/BFF.
|
||||
- Use path aliases from tsconfig.base.json; export public API via index.ts.
|
||||
- Respect ESLint module boundaries and Nx tags; add proper library tags when creating new packages.
|
||||
- Map server errors to safe messages in production; log full details server-side only.
|
||||
- Use MSW for network contract tests; keep unit tests fast and deterministic.
|
||||
- Follow Conventional Commits with configured scopes and the additional `security` type.
|
||||
- Keep barrel files accurate and synchronized with actual implementation files.
|
||||
- Don't
|
||||
- Import across features (no feature-to-feature dependencies).
|
||||
- Make domain depend on data/core/platform code.
|
||||
- Bypass ensureInitialized guards in core SDKs.
|
||||
- Expose stack traces or sensitive details to clients in production.
|
||||
- Hardcode secrets or environment-specific values; use config and env vars.
|
||||
- Introduce Node-specific APIs into React Native code paths.
|
||||
|
||||
## 7. Tools & Dependencies
|
||||
- Tooling
|
||||
- PNPM workspaces + Nx orchestration (caching, affected commands).
|
||||
- ESLint + Prettier + lint-staged; commitlint with conventional commits.
|
||||
- Changesets for versioning and publishing (SDK packages only).
|
||||
- Key libraries
|
||||
- Apps: React Native, React Navigation.
|
||||
- BFF: Fastify, @apollo/server, @graphql-tools/schema, @fastify/cors, @fastify/helmet, optional Permit.io.
|
||||
- Core SDKs: Security (DPoP, key management, encryption), Storage (encrypted DB, schema registry), Sync/Runtime/Trust (per architecture).
|
||||
- Setup
|
||||
- Install: pnpm install; build: pnpm nx run-many -t build.
|
||||
- Dev scripts: dev:playground, dev:pro, dev:foundation.
|
||||
- Tests: pnpm test or pnpm affected:test.
|
||||
- BFF env vars: NODE_ENV, PORT (default 4000), HOST (default 0.0.0.0), PERMIT_PDP_URL, PERMIT_API_KEY.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user