skillstore-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/data/bundles/devflow-complete.json +19 -0
- package/data/free-skills/devflow-agile/manifest.json +19 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/retro.md +23 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/review.md +21 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/sprint.md +30 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/standup.md +20 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile.md +35 -0
- package/data/free-skills/devflow-agile/plugin/commands/devflow.md +42 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/SKILL.md +93 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/assets/sample-output.md +182 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/clean-architecture.md +361 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/clean-code-guide.md +207 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/debugging-methodology.md +191 -0
- package/data/free-skills/devflow-agile/template/agents/agile-coach.md +76 -0
- package/data/free-skills/devflow-agile/template/workflows/agile-sprint-workflow.md +81 -0
- package/data/free-skills/devflow-bootstrap/manifest.json +8 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/bootstrap/auto.md +31 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/bootstrap.md +38 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/devflow.md +20 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/SKILL.md +56 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/assets/sample-output.md +216 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/references/architecture-decisions.md +254 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/references/stack-templates.md +400 -0
- package/data/free-skills/devflow-bootstrap/template/agents/bootstrap-specialist.md +56 -0
- package/data/free-skills/devflow-bootstrap/template/workflows/bootstrap-workflow.md +70 -0
- package/data/free-skills/devflow-docs/manifest.json +8 -0
- package/data/free-skills/devflow-docs/plugin/commands/devflow.md +20 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs/generate.md +17 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs/parse.md +19 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs.md +26 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/SKILL.md +59 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/assets/sample-output.md +114 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/references/extraction-techniques.md +115 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/references/ocr-strategies.md +167 -0
- package/data/free-skills/devflow-docs/template/agents/docs-specialist.md +35 -0
- package/data/free-skills/devflow-docs/template/workflows/docs-workflow.md +70 -0
- package/data/free-skills/devflow-postproject/manifest.json +13 -0
- package/data/free-skills/devflow-postproject/plugin/commands/devflow.md +34 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/handover.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/retro.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/support.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject.md +32 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/SKILL.md +70 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/assets/sample-output.md +79 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/facilitation-techniques.md +178 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/lessons-learned-template.md +118 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/retro-techniques.md +100 -0
- package/data/free-skills/devflow-postproject/template/agents/transition-manager.md +71 -0
- package/data/free-skills/devflow-postproject/template/workflows/transition-workflow.md +72 -0
- package/data/free-skills/devflow-presale/manifest.json +15 -0
- package/data/free-skills/devflow-presale/plugin/commands/devflow.md +47 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/analyze.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/estimate.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/price.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/propose.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale.md +42 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/SKILL.md +63 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/assets/sample-output.md +129 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/references/extraction-framework.md +140 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/references/output-template.md +132 -0
- package/data/free-skills/devflow-presale/template/agents/presale-lead.md +83 -0
- package/data/free-skills/devflow-presale/template/agents/proposal-reviewer.md +63 -0
- package/data/free-skills/devflow-presale/template/workflows/presale-workflow.md +70 -0
- package/data/registry/categories.json +7 -0
- package/data/registry/packages.json +184 -0
- package/data/shared/framework/agents/brainstormer.md +74 -0
- package/data/shared/framework/agents/code-reviewer.md +87 -0
- package/data/shared/framework/agents/debugger.md +84 -0
- package/data/shared/framework/agents/docs-manager.md +55 -0
- package/data/shared/framework/agents/git-manager.md +59 -0
- package/data/shared/framework/agents/planner.md +68 -0
- package/data/shared/framework/agents/researcher.md +66 -0
- package/data/shared/framework/agents/tester.md +65 -0
- package/data/shared/framework/commands/cook/auto.md +27 -0
- package/data/shared/framework/commands/cook.md +45 -0
- package/data/shared/framework/commands/fix/ci.md +21 -0
- package/data/shared/framework/commands/fix/test.md +26 -0
- package/data/shared/framework/commands/fix/types.md +29 -0
- package/data/shared/framework/commands/fix.md +26 -0
- package/data/shared/framework/commands/git/cm.md +37 -0
- package/data/shared/framework/commands/git/pr.md +40 -0
- package/data/shared/framework/config/CLAUDE.md.template +26 -0
- package/data/shared/framework/config/settings.json +41 -0
- package/data/shared/framework/config/skillstore.config.json +29 -0
- package/data/shared/framework/hooks/discord-notify.sh +85 -0
- package/data/shared/framework/hooks/docs-sync.sh +53 -0
- package/data/shared/framework/hooks/modularization-hook.js +103 -0
- package/data/shared/framework/hooks/notification.js +94 -0
- package/data/shared/framework/hooks/quality-gate.js +109 -0
- package/data/shared/framework/hooks/scout-block.js +77 -0
- package/data/shared/framework/hooks/telegram-notify.sh +77 -0
- package/data/shared/framework/protocols/error-recovery.md +80 -0
- package/data/shared/framework/protocols/orchestration-protocol.md +112 -0
- package/data/shared/framework/quality/review-protocol.md +76 -0
- package/data/shared/framework/quality/verification-protocol.md +66 -0
- package/data/shared/framework/rules/development-rules.md +75 -0
- package/data/shared/framework/skills/backend-development/SKILL.md +77 -0
- package/data/shared/framework/skills/backend-development/assets/sample-output.md +175 -0
- package/data/shared/framework/skills/backend-development/references/advanced-patterns.md +180 -0
- package/data/shared/framework/skills/backend-development/references/api-design-guide.md +160 -0
- package/data/shared/framework/skills/backend-development/references/architecture-patterns.md +183 -0
- package/data/shared/framework/skills/backend-development/references/observability-resilience.md +155 -0
- package/data/shared/framework/skills/backend-development/references/troubleshooting.md +199 -0
- package/data/shared/framework/skills/codebase-analysis/SKILL.md +72 -0
- package/data/shared/framework/skills/codebase-analysis/assets/sample-output.md +263 -0
- package/data/shared/framework/skills/codebase-analysis/references/analysis-techniques.md +241 -0
- package/data/shared/framework/skills/codebase-analysis/references/dependency-mapping.md +280 -0
- package/data/shared/framework/skills/codebase-analysis/references/tech-debt-assessment.md +208 -0
- package/data/shared/framework/skills/databases/SKILL.md +72 -0
- package/data/shared/framework/skills/databases/assets/sample-output.md +212 -0
- package/data/shared/framework/skills/databases/references/advanced-data-patterns.md +259 -0
- package/data/shared/framework/skills/databases/references/query-optimization.md +214 -0
- package/data/shared/framework/skills/databases/references/schema-design.md +159 -0
- package/data/shared/framework/skills/databases/references/troubleshooting.md +214 -0
- package/data/shared/framework/skills/debugging-investigation/SKILL.md +84 -0
- package/data/shared/framework/skills/debugging-investigation/assets/sample-output.md +314 -0
- package/data/shared/framework/skills/debugging-investigation/references/systematic-debugging.md +197 -0
- package/data/shared/framework/skills/debugging-investigation/references/tool-specific-guides.md +202 -0
- package/data/shared/framework/skills/debugging-investigation/references/troubleshooting-patterns.md +196 -0
- package/data/shared/framework/skills/frontend-development/SKILL.md +67 -0
- package/data/shared/framework/skills/frontend-development/assets/sample-output.md +110 -0
- package/data/shared/framework/skills/frontend-development/references/component-patterns.md +112 -0
- package/data/shared/framework/skills/frontend-development/references/performance-guide.md +169 -0
- package/data/shared/framework/skills/frontend-development/references/routing-forms-realtime.md +374 -0
- package/data/shared/framework/skills/frontend-development/references/ssr-rsc-patterns.md +284 -0
- package/data/shared/framework/skills/frontend-development/references/troubleshooting.md +154 -0
- package/data/shared/framework/skills/mobile-development/SKILL.md +67 -0
- package/data/shared/framework/skills/mobile-development/assets/sample-output.md +382 -0
- package/data/shared/framework/skills/mobile-development/references/mobile-patterns.md +681 -0
- package/data/shared/framework/skills/mobile-development/references/mobile-performance.md +524 -0
- package/data/shared/framework/skills/mobile-development/references/troubleshooting.md +158 -0
- package/data/shared/framework/skills/security-audit/SKILL.md +83 -0
- package/data/shared/framework/skills/security-audit/assets/sample-output.md +451 -0
- package/data/shared/framework/skills/security-audit/references/owasp-checklist.md +580 -0
- package/data/shared/framework/skills/security-audit/references/secure-coding-patterns.md +433 -0
- package/data/shared/framework/skills/security-audit/references/vulnerability-remediation.md +331 -0
- package/data/shared/framework/skills/ui-generation/SKILL.md +70 -0
- package/data/shared/framework/skills/ui-generation/assets/sample-output.md +139 -0
- package/data/shared/framework/skills/ui-generation/references/accessibility-responsive.md +127 -0
- package/data/shared/framework/skills/ui-generation/references/compound-components.md +252 -0
- package/data/shared/framework/skills/ui-generation/references/generation-patterns.md +110 -0
- package/data/shared/framework/skills/ui-generation/references/storybook-design-system.md +278 -0
- package/data/shared/framework/skills/ui-generation/references/troubleshooting.md +198 -0
- package/data/shared/framework/workflows/documentation-management.md +58 -0
- package/data/shared/framework/workflows/primary-workflow.md +88 -0
- package/dist/commands/activate.d.ts +3 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +34 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/bundle.d.ts +3 -0
- package/dist/commands/bundle.d.ts.map +1 -0
- package/dist/commands/bundle.js +64 -0
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +99 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +37 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +30 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +35 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +68 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/download/cache.d.ts +3 -0
- package/dist/download/cache.d.ts.map +1 -0
- package/dist/download/cache.js +18 -0
- package/dist/download/cache.js.map +1 -0
- package/dist/download/client.d.ts +2 -0
- package/dist/download/client.d.ts.map +1 -0
- package/dist/download/client.js +58 -0
- package/dist/download/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/installer/file-copier.d.ts +6 -0
- package/dist/installer/file-copier.d.ts.map +1 -0
- package/dist/installer/file-copier.js +32 -0
- package/dist/installer/file-copier.js.map +1 -0
- package/dist/installer/plugin-installer.d.ts +12 -0
- package/dist/installer/plugin-installer.d.ts.map +1 -0
- package/dist/installer/plugin-installer.js +33 -0
- package/dist/installer/plugin-installer.js.map +1 -0
- package/dist/installer/template-installer.d.ts +12 -0
- package/dist/installer/template-installer.d.ts.map +1 -0
- package/dist/installer/template-installer.js +45 -0
- package/dist/installer/template-installer.js.map +1 -0
- package/dist/license/crypto.d.ts +16 -0
- package/dist/license/crypto.d.ts.map +1 -0
- package/dist/license/crypto.js +50 -0
- package/dist/license/crypto.js.map +1 -0
- package/dist/license/license-store.d.ts +19 -0
- package/dist/license/license-store.d.ts.map +1 -0
- package/dist/license/license-store.js +99 -0
- package/dist/license/license-store.js.map +1 -0
- package/dist/license/validator.d.ts +32 -0
- package/dist/license/validator.d.ts.map +1 -0
- package/dist/license/validator.js +81 -0
- package/dist/license/validator.js.map +1 -0
- package/dist/registry/loader.d.ts +30 -0
- package/dist/registry/loader.d.ts.map +1 -0
- package/dist/registry/loader.js +22 -0
- package/dist/registry/loader.js.map +1 -0
- package/dist/registry/search-engine.d.ts +9 -0
- package/dist/registry/search-engine.d.ts.map +1 -0
- package/dist/registry/search-engine.js +30 -0
- package/dist/registry/search-engine.js.map +1 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +28 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +20 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +79 -0
- package/dist/utils/paths.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Frontend Troubleshooting Guide
|
|
2
|
+
|
|
3
|
+
## Hydration Mismatch Errors (SSR/SSG)
|
|
4
|
+
|
|
5
|
+
**Symptoms:** Console warning "Text content does not match server-rendered HTML", UI flickers on load.
|
|
6
|
+
|
|
7
|
+
**Common causes and fixes:**
|
|
8
|
+
1. **Browser-only APIs used during render** — `window`, `localStorage`, `navigator` accessed unconditionally.
|
|
9
|
+
- Fix: Guard with `useEffect` or `typeof window !== 'undefined'` checks.
|
|
10
|
+
2. **Date/time formatting** — Server and client produce different locale strings.
|
|
11
|
+
- Fix: Use UTC formatting or suppress hydration for that element with `suppressHydrationWarning`.
|
|
12
|
+
3. **Browser extensions injecting DOM nodes** — Extensions add elements between server HTML and hydration.
|
|
13
|
+
- Fix: Test in incognito. Not a code bug, but wrap dynamic sections in a client boundary.
|
|
14
|
+
4. **Conditional rendering based on auth/state** — Server has no session, client does.
|
|
15
|
+
- Fix: Render skeleton on server, populate on client via `useEffect`.
|
|
16
|
+
|
|
17
|
+
**Debug command:** Open DevTools Console, filter for "hydration". React 18+ logs the exact DOM diff.
|
|
18
|
+
|
|
19
|
+
## "Cannot read property of undefined" State Bugs
|
|
20
|
+
|
|
21
|
+
**Diagnosis workflow:**
|
|
22
|
+
1. Check the stack trace — identify which property access fails.
|
|
23
|
+
2. Trace the data flow backward: component props → parent state → API response → backend.
|
|
24
|
+
3. Common root causes:
|
|
25
|
+
- API response shape changed (missing nested object).
|
|
26
|
+
- Race condition: component renders before async data arrives.
|
|
27
|
+
- Optional chaining missing on deeply nested access.
|
|
28
|
+
|
|
29
|
+
**Fix patterns:**
|
|
30
|
+
- Add optional chaining: `user?.profile?.name` instead of `user.profile.name`.
|
|
31
|
+
- Set default values in destructuring: `const { items = [] } = data || {}`.
|
|
32
|
+
- Add loading/error states that prevent rendering until data is valid.
|
|
33
|
+
- Use TypeScript strict null checks to catch these at compile time.
|
|
34
|
+
|
|
35
|
+
## CSS Specificity Wars Diagnosis
|
|
36
|
+
|
|
37
|
+
**Symptoms:** Styles not applying, `!important` scattered everywhere, styles work in isolation but break in context.
|
|
38
|
+
|
|
39
|
+
**Debug workflow:**
|
|
40
|
+
1. Open DevTools → Elements → Computed tab → find the property → see which rule wins.
|
|
41
|
+
2. Check the specificity: inline (1000) > #id (100) > .class (10) > element (1).
|
|
42
|
+
3. Look for third-party CSS loaded after your styles that overrides them.
|
|
43
|
+
|
|
44
|
+
**Fix patterns:**
|
|
45
|
+
- Use CSS Modules or CSS-in-JS to scope styles and avoid collisions.
|
|
46
|
+
- Increase specificity with a parent selector rather than `!important`.
|
|
47
|
+
- Use `:where()` (zero specificity) for resets, `:is()` to group selectors.
|
|
48
|
+
- Audit with: `document.querySelectorAll('[style]')` to find rogue inline styles.
|
|
49
|
+
|
|
50
|
+
## Bundle Size Sudden Increase Investigation
|
|
51
|
+
|
|
52
|
+
**Diagnosis workflow:**
|
|
53
|
+
```bash
|
|
54
|
+
# Install analyzer
|
|
55
|
+
npm install --save-dev webpack-bundle-analyzer
|
|
56
|
+
|
|
57
|
+
# Next.js: add to next.config.js
|
|
58
|
+
# const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' })
|
|
59
|
+
ANALYZE=true npm run build
|
|
60
|
+
|
|
61
|
+
# Vite: use rollup-plugin-visualizer
|
|
62
|
+
npx vite-bundle-visualizer
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Common culprits:**
|
|
66
|
+
1. **Barrel file imports** — `import { Button } from '@/components'` pulls entire directory.
|
|
67
|
+
- Fix: Import directly from the file: `import { Button } from '@/components/Button'`.
|
|
68
|
+
2. **Moment.js or similar heavy library added** — Check for locale bundles.
|
|
69
|
+
- Fix: Switch to `date-fns` or `dayjs` with tree-shaking.
|
|
70
|
+
3. **Source maps included in production** — `devtool: 'source-map'` in prod config.
|
|
71
|
+
4. **Missing dynamic imports** — Large page components loaded eagerly.
|
|
72
|
+
- Fix: `React.lazy()` + `Suspense` or Next.js `dynamic()`.
|
|
73
|
+
|
|
74
|
+
## Memory Leaks in SPA
|
|
75
|
+
|
|
76
|
+
**Symptoms:** Page slows down over time, tab memory in Task Manager grows continuously.
|
|
77
|
+
|
|
78
|
+
**Detection:**
|
|
79
|
+
1. DevTools → Memory → Take Heap Snapshot before and after navigating.
|
|
80
|
+
2. Compare snapshots: filter by "Detached" to find detached DOM trees.
|
|
81
|
+
3. Performance Monitor → JS Heap Size — should stabilize, not grow.
|
|
82
|
+
|
|
83
|
+
**Common causes:**
|
|
84
|
+
1. **Event listeners not cleaned up** — `addEventListener` without `removeEventListener` in cleanup.
|
|
85
|
+
- Fix: Always return cleanup from `useEffect`.
|
|
86
|
+
2. **Intervals/timers not cleared** — `setInterval` persists across navigation.
|
|
87
|
+
- Fix: `clearInterval` in `useEffect` cleanup.
|
|
88
|
+
3. **Closures holding stale references** — Callback captures large objects.
|
|
89
|
+
- Fix: Use `useRef` for mutable values, nullify references in cleanup.
|
|
90
|
+
4. **Third-party libraries not destroyed** — Chart.js, map libraries hold DOM references.
|
|
91
|
+
- Fix: Call `.destroy()` or `.dispose()` in cleanup.
|
|
92
|
+
|
|
93
|
+
## CORS Errors Configuration Checklist
|
|
94
|
+
|
|
95
|
+
**Error:** `Access to fetch has been blocked by CORS policy`.
|
|
96
|
+
|
|
97
|
+
**Diagnosis:**
|
|
98
|
+
1. Open Network tab → find the failed request → check for preflight (OPTIONS) request.
|
|
99
|
+
2. Verify response headers: `Access-Control-Allow-Origin`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`.
|
|
100
|
+
|
|
101
|
+
**Fix checklist:**
|
|
102
|
+
- [ ] Server returns `Access-Control-Allow-Origin` matching the request origin (not `*` if credentials used).
|
|
103
|
+
- [ ] Preflight OPTIONS request returns 200/204 (not 404 or 500).
|
|
104
|
+
- [ ] `Access-Control-Allow-Methods` includes the HTTP method used.
|
|
105
|
+
- [ ] `Access-Control-Allow-Headers` includes custom headers (e.g., `Authorization`, `Content-Type`).
|
|
106
|
+
- [ ] `Access-Control-Allow-Credentials: true` if sending cookies.
|
|
107
|
+
- [ ] Proxy configured in dev server (`vite.config.ts` proxy or Next.js rewrites) to avoid CORS in development.
|
|
108
|
+
|
|
109
|
+
## Performance Regression Debugging (Core Web Vitals)
|
|
110
|
+
|
|
111
|
+
**LCP (Largest Contentful Paint) regression:**
|
|
112
|
+
1. DevTools → Performance → record page load → find LCP marker.
|
|
113
|
+
2. Check: Is the largest element an image? Add `fetchpriority="high"` and `loading="eager"`.
|
|
114
|
+
3. Check: Font blocking render? Use `font-display: swap` and preload critical fonts.
|
|
115
|
+
4. Check: Render-blocking CSS/JS? Defer non-critical resources.
|
|
116
|
+
|
|
117
|
+
**CLS (Cumulative Layout Shift) regression:**
|
|
118
|
+
1. DevTools → Performance → enable "Layout Shift Regions".
|
|
119
|
+
2. Common causes: images without explicit `width`/`height`, dynamic content injected above viewport, web fonts causing reflow.
|
|
120
|
+
3. Fix: Set dimensions on media elements, use `min-height` on dynamic containers.
|
|
121
|
+
|
|
122
|
+
**INP (Interaction to Next Paint) regression:**
|
|
123
|
+
1. DevTools → Performance → interact with the page → check "Total Blocking Time".
|
|
124
|
+
2. Long tasks (>50ms) on main thread block interactions.
|
|
125
|
+
3. Fix: Break work with `requestIdleCallback`, use `startTransition` for non-urgent updates, move computation to Web Workers.
|
|
126
|
+
|
|
127
|
+
## React Re-render Storms
|
|
128
|
+
|
|
129
|
+
**Symptoms:** UI is sluggish, components re-render on every keystroke or unrelated state change.
|
|
130
|
+
|
|
131
|
+
**Diagnosis with React DevTools Profiler:**
|
|
132
|
+
1. Install React DevTools → Profiler tab → enable "Record why each component rendered".
|
|
133
|
+
2. Click record → interact with the UI → stop recording.
|
|
134
|
+
3. Look for components rendering with reason "Parent re-rendered" when their props didn't change.
|
|
135
|
+
|
|
136
|
+
**Common causes and fixes:**
|
|
137
|
+
1. **Inline object/array props** — `<Child style={{ color: 'red' }} />` creates new reference each render.
|
|
138
|
+
- Fix: Hoist to a constant or `useMemo`.
|
|
139
|
+
2. **Context provider value not memoized** — `<Ctx.Provider value={{ user, setUser }}>` re-renders all consumers.
|
|
140
|
+
- Fix: `useMemo` the value object, or split contexts (read vs write).
|
|
141
|
+
3. **State stored too high** — Form input state in a top-level component re-renders the entire tree.
|
|
142
|
+
- Fix: Move state down to the closest component that needs it, or use `React.memo`.
|
|
143
|
+
4. **Missing dependency array** — `useEffect(() => {...})` without deps runs every render.
|
|
144
|
+
- Fix: Add proper dependency array.
|
|
145
|
+
|
|
146
|
+
**Quick audit command:**
|
|
147
|
+
```javascript
|
|
148
|
+
// Paste in console to log all re-renders
|
|
149
|
+
const origRender = React.createElement;
|
|
150
|
+
React.createElement = function(...args) {
|
|
151
|
+
if (typeof args[0] === 'function') console.count(args[0].name);
|
|
152
|
+
return origRender.apply(this, args);
|
|
153
|
+
};
|
|
154
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mobile-development
|
|
3
|
+
description: React Native/Flutter development — component design, navigation, state management, platform-specific concerns, offline-first patterns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mobile Development
|
|
7
|
+
|
|
8
|
+
## Triggers
|
|
9
|
+
|
|
10
|
+
Activate this skill when:
|
|
11
|
+
- Building a mobile app or adding a mobile feature
|
|
12
|
+
- Implementing navigation, gestures, or native interactions
|
|
13
|
+
- Fixing mobile-specific bugs (platform differences, device quirks)
|
|
14
|
+
- Optimizing mobile performance (rendering, memory, startup time)
|
|
15
|
+
- Handling offline scenarios, push notifications, or permissions
|
|
16
|
+
- Setting up CI/CD for mobile builds (Fastlane, EAS, Codemagic)
|
|
17
|
+
|
|
18
|
+
## Process
|
|
19
|
+
|
|
20
|
+
### 1. Platform Assessment
|
|
21
|
+
- Identify target platforms (iOS, Android, or both)
|
|
22
|
+
- Define minimum OS versions and device targets
|
|
23
|
+
- List native capabilities needed (camera, GPS, Bluetooth, payments)
|
|
24
|
+
- Decide framework: React Native (JS ecosystem, hot reload) vs Flutter (Dart, pixel-perfect UI)
|
|
25
|
+
- Check third-party SDK requirements (maps, analytics, crash reporting)
|
|
26
|
+
|
|
27
|
+
### 2. Architecture Design
|
|
28
|
+
Load: `references/mobile-patterns.md`
|
|
29
|
+
|
|
30
|
+
- Define navigation structure (stack, tab, drawer, modal flows)
|
|
31
|
+
- Choose state management: local → context/provider → global store
|
|
32
|
+
- Plan data layer: API client, local database, sync strategy
|
|
33
|
+
- Establish project structure (feature-based folders, shared modules)
|
|
34
|
+
- Define platform-specific boundaries (shared logic vs native code)
|
|
35
|
+
|
|
36
|
+
### 3. Component Implementation
|
|
37
|
+
- Build screens top-down: navigation shell → screen layouts → components
|
|
38
|
+
- Use platform-aware components where UI conventions differ (iOS vs Android)
|
|
39
|
+
- Implement forms with validation and keyboard handling
|
|
40
|
+
- Handle safe areas, notches, dynamic island, and system bars
|
|
41
|
+
- Wire up deep linking and universal links
|
|
42
|
+
|
|
43
|
+
### 4. Testing
|
|
44
|
+
- Unit test business logic and utilities
|
|
45
|
+
- Component/widget tests for interactive elements
|
|
46
|
+
- E2E tests for critical flows (Detox for RN, integration_test for Flutter)
|
|
47
|
+
- Test on real devices for permission flows and native features
|
|
48
|
+
- Test offline scenarios and poor network conditions
|
|
49
|
+
|
|
50
|
+
### 5. Performance Optimization
|
|
51
|
+
Load: `references/mobile-performance.md`
|
|
52
|
+
|
|
53
|
+
- Profile rendering (React DevTools / Flutter DevTools)
|
|
54
|
+
- Optimize list rendering (FlatList/ListView best practices)
|
|
55
|
+
- Reduce app startup time (lazy init, minimal splash work)
|
|
56
|
+
- Minimize memory leaks (clean up listeners, subscriptions, timers)
|
|
57
|
+
- Audit app size and apply asset optimization
|
|
58
|
+
|
|
59
|
+
## References
|
|
60
|
+
|
|
61
|
+
- [Mobile Patterns](references/mobile-patterns.md) — navigation, state, offline-first, push notifications, permissions
|
|
62
|
+
- [Mobile Performance](references/mobile-performance.md) — rendering, memory, network, startup, battery, testing
|
|
63
|
+
- [Troubleshooting](references/troubleshooting.md) — build failures iOS/Android, red screen, startup crashes, push notifications, app store rejections
|
|
64
|
+
|
|
65
|
+
## Assets
|
|
66
|
+
|
|
67
|
+
- [Sample Output](assets/sample-output.md) — architecture plan for a Food Delivery app in React Native
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# Sample Output: Food Delivery App — React Native Architecture Plan
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
**App**: QuickBite — Food delivery platform
|
|
6
|
+
**Framework**: React Native (Expo managed workflow)
|
|
7
|
+
**Target**: iOS 15+, Android 12+
|
|
8
|
+
**Team**: 3 RN developers, 1 QA
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Navigation Structure
|
|
13
|
+
|
|
14
|
+
### Tab Navigator (4 tabs)
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌─────────┬──────────┬──────────┬──────────┐
|
|
18
|
+
│ Home │ Search │ Orders │ Profile │
|
|
19
|
+
└────┬────┴────┬─────┴────┬─────┴────┬─────┘
|
|
20
|
+
│ │ │ │
|
|
21
|
+
▼ ▼ ▼ ▼
|
|
22
|
+
HomeStack SearchStack OrderStack ProfileStack
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Screen Map
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
type RootTabParamList = {
|
|
29
|
+
HomeTab: NavigatorScreenParams<HomeStackParamList>;
|
|
30
|
+
SearchTab: NavigatorScreenParams<SearchStackParamList>;
|
|
31
|
+
OrdersTab: NavigatorScreenParams<OrderStackParamList>;
|
|
32
|
+
ProfileTab: NavigatorScreenParams<ProfileStackParamList>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type HomeStackParamList = {
|
|
36
|
+
Home: undefined;
|
|
37
|
+
RestaurantDetail: { id: string };
|
|
38
|
+
MenuItem: { restaurantId: string; itemId: string };
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type OrderStackParamList = {
|
|
42
|
+
OrderList: undefined;
|
|
43
|
+
OrderDetail: { orderId: string };
|
|
44
|
+
OrderTracking: { orderId: string }; // Real-time map
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type CheckoutParamList = {
|
|
48
|
+
Cart: undefined;
|
|
49
|
+
DeliveryAddress: undefined;
|
|
50
|
+
Payment: undefined;
|
|
51
|
+
OrderConfirmation: { orderId: string };
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Modal Flows (presented over tabs)
|
|
56
|
+
|
|
57
|
+
| Flow | Screens | Trigger |
|
|
58
|
+
|------|---------|---------|
|
|
59
|
+
| Checkout | Cart → Address → Payment → Confirmation | Tap "Checkout" in cart |
|
|
60
|
+
| Add Address | Map Picker → Address Form | Tap "+" in address list |
|
|
61
|
+
| Rating | Star Rating → Comment → Submit | After order delivered |
|
|
62
|
+
|
|
63
|
+
### Deep Linking
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const linking: LinkingOptions<RootTabParamList> = {
|
|
67
|
+
prefixes: ['quickbite://', 'https://quickbite.app'],
|
|
68
|
+
config: {
|
|
69
|
+
screens: {
|
|
70
|
+
HomeTab: {
|
|
71
|
+
screens: {
|
|
72
|
+
RestaurantDetail: 'restaurant/:id',
|
|
73
|
+
MenuItem: 'restaurant/:restaurantId/item/:itemId',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
OrdersTab: {
|
|
77
|
+
screens: {
|
|
78
|
+
OrderTracking: 'orders/:orderId/track',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## State Management
|
|
89
|
+
|
|
90
|
+
### Store Architecture
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
┌─────────────────────────────────────────────────────┐
|
|
94
|
+
│ Server State │
|
|
95
|
+
│ (TanStack Query) │
|
|
96
|
+
│ restaurants, menu items, orders, user profile │
|
|
97
|
+
│ → Caching, background refetch, optimistic updates │
|
|
98
|
+
├─────────────────────────────────────────────────────┤
|
|
99
|
+
│ Client State │
|
|
100
|
+
│ (Zustand) │
|
|
101
|
+
│ cart, delivery address, UI preferences │
|
|
102
|
+
│ → Persisted to MMKV for instant restore │
|
|
103
|
+
├─────────────────────────────────────────────────────┤
|
|
104
|
+
│ Ephemeral State │
|
|
105
|
+
│ (useState / useRef) │
|
|
106
|
+
│ form inputs, scroll position, animation values │
|
|
107
|
+
│ → No persistence needed │
|
|
108
|
+
└─────────────────────────────────────────────────────┘
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Zustand Stores
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// stores/cart.ts — persisted to MMKV
|
|
115
|
+
interface CartStore {
|
|
116
|
+
items: CartItem[];
|
|
117
|
+
deliveryAddress: Address | null;
|
|
118
|
+
promoCode: string | null;
|
|
119
|
+
addItem: (item: MenuItem, qty: number, options: ItemOption[]) => void;
|
|
120
|
+
removeItem: (cartItemId: string) => void;
|
|
121
|
+
updateQuantity: (cartItemId: string, qty: number) => void;
|
|
122
|
+
setAddress: (address: Address) => void;
|
|
123
|
+
applyPromo: (code: string) => void;
|
|
124
|
+
subtotal: () => number;
|
|
125
|
+
deliveryFee: () => number;
|
|
126
|
+
total: () => number;
|
|
127
|
+
clear: () => void;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// stores/auth.ts — persisted, contains tokens
|
|
131
|
+
interface AuthStore {
|
|
132
|
+
token: string | null;
|
|
133
|
+
user: User | null;
|
|
134
|
+
isAuthenticated: boolean;
|
|
135
|
+
login: (credentials: LoginRequest) => Promise<void>;
|
|
136
|
+
logout: () => void;
|
|
137
|
+
refreshToken: () => Promise<void>;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### TanStack Query Keys
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
export const queryKeys = {
|
|
145
|
+
restaurants: {
|
|
146
|
+
all: ['restaurants'] as const,
|
|
147
|
+
nearby: (lat: number, lng: number) => ['restaurants', 'nearby', lat, lng] as const,
|
|
148
|
+
detail: (id: string) => ['restaurants', id] as const,
|
|
149
|
+
menu: (id: string) => ['restaurants', id, 'menu'] as const,
|
|
150
|
+
},
|
|
151
|
+
orders: {
|
|
152
|
+
all: ['orders'] as const,
|
|
153
|
+
active: ['orders', 'active'] as const,
|
|
154
|
+
detail: (id: string) => ['orders', id] as const,
|
|
155
|
+
tracking: (id: string) => ['orders', id, 'tracking'] as const,
|
|
156
|
+
},
|
|
157
|
+
user: {
|
|
158
|
+
profile: ['user', 'profile'] as const,
|
|
159
|
+
addresses: ['user', 'addresses'] as const,
|
|
160
|
+
paymentMethods: ['user', 'payment-methods'] as const,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Offline-First Architecture
|
|
168
|
+
|
|
169
|
+
### Strategy by Data Type
|
|
170
|
+
|
|
171
|
+
| Data | Offline Strategy | Local Storage | Sync Priority |
|
|
172
|
+
|------|-----------------|---------------|---------------|
|
|
173
|
+
| Restaurant list | Cache, stale OK | TanStack Query cache | Low |
|
|
174
|
+
| Menu items | Cache, stale OK | TanStack Query cache | Low |
|
|
175
|
+
| Cart | Full offline support | Zustand + MMKV | High |
|
|
176
|
+
| Active order | Cache + poll on reconnect | WatermelonDB | Critical |
|
|
177
|
+
| User profile | Cache, sync on change | MMKV | Medium |
|
|
178
|
+
| Order history | Cache, paginated | WatermelonDB | Low |
|
|
179
|
+
|
|
180
|
+
### Sync Queue for Mutations
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// When offline: queue mutations
|
|
184
|
+
const pendingMutations: PendingMutation[] = [
|
|
185
|
+
{ id: 'pm_1', type: 'PLACE_ORDER', payload: orderData, createdAt: Date.now() },
|
|
186
|
+
{ id: 'pm_2', type: 'UPDATE_ADDRESS', payload: addressData, createdAt: Date.now() },
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
// On reconnect: process in order
|
|
190
|
+
// PLACE_ORDER → critical, retry 3x
|
|
191
|
+
// UPDATE_ADDRESS → non-critical, retry 1x
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Network State Hook
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
function useNetworkAwareQuery<T>(key: QueryKey, fn: QueryFunction<T>) {
|
|
198
|
+
const isOnline = useNetworkStatus();
|
|
199
|
+
|
|
200
|
+
return useQuery({
|
|
201
|
+
queryKey: key,
|
|
202
|
+
queryFn: fn,
|
|
203
|
+
enabled: isOnline,
|
|
204
|
+
staleTime: isOnline ? 30_000 : Infinity, // Never refetch when offline
|
|
205
|
+
gcTime: 24 * 60 * 60 * 1000, // Keep cache 24h
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Performance Budget
|
|
213
|
+
|
|
214
|
+
| Metric | Target | Measurement |
|
|
215
|
+
|--------|--------|-------------|
|
|
216
|
+
| Cold start | < 1.5s | Flipper startup profiler |
|
|
217
|
+
| TTI (Time to Interactive) | < 2.0s | First meaningful paint + interactive |
|
|
218
|
+
| FlatList scroll | 60 FPS | Flipper FPS monitor |
|
|
219
|
+
| Image load | < 500ms | FastImage cache hit ratio |
|
|
220
|
+
| API response display | < 300ms | Query + render time |
|
|
221
|
+
| App size (iOS) | < 50MB | Xcode archive |
|
|
222
|
+
| App size (Android) | < 30MB | AAB + APK analyzer |
|
|
223
|
+
| JS bundle | < 2MB | Metro bundle size |
|
|
224
|
+
| Memory (steady state) | < 200MB | Xcode Memory Graph |
|
|
225
|
+
|
|
226
|
+
### FlatList Optimization
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
<FlatList
|
|
230
|
+
data={restaurants}
|
|
231
|
+
renderItem={renderRestaurantCard}
|
|
232
|
+
keyExtractor={(item) => item.id}
|
|
233
|
+
getItemLayout={(_, index) => ({
|
|
234
|
+
length: CARD_HEIGHT,
|
|
235
|
+
offset: CARD_HEIGHT * index,
|
|
236
|
+
index,
|
|
237
|
+
})}
|
|
238
|
+
windowSize={5}
|
|
239
|
+
maxToRenderPerBatch={5}
|
|
240
|
+
removeClippedSubviews={true}
|
|
241
|
+
initialNumToRender={10}
|
|
242
|
+
/>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Image Strategy
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Use expo-image (Expo) or FastImage (bare) with preloading
|
|
249
|
+
<Image
|
|
250
|
+
source={{ uri: restaurant.imageUrl }}
|
|
251
|
+
style={styles.image}
|
|
252
|
+
placeholder={blurhash}
|
|
253
|
+
contentFit="cover"
|
|
254
|
+
transition={200}
|
|
255
|
+
cachePolicy="memory-disk"
|
|
256
|
+
/>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## CI/CD Pipeline
|
|
262
|
+
|
|
263
|
+
### EAS Build + EAS Update
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
Feature Branch → PR
|
|
267
|
+
├── Lint + Type Check (GitHub Actions, ~2 min)
|
|
268
|
+
├── Unit Tests (Jest, ~3 min)
|
|
269
|
+
└── E2E Tests (Detox on iOS simulator, ~10 min)
|
|
270
|
+
|
|
271
|
+
Merge to develop
|
|
272
|
+
└── EAS Update (OTA) → Internal testing channel
|
|
273
|
+
|
|
274
|
+
Merge to main
|
|
275
|
+
├── EAS Build (iOS + Android, ~20 min)
|
|
276
|
+
├── TestFlight upload (iOS)
|
|
277
|
+
├── Internal track upload (Android)
|
|
278
|
+
└── Sentry release + source maps
|
|
279
|
+
|
|
280
|
+
Release
|
|
281
|
+
├── App Store submission (manual trigger)
|
|
282
|
+
└── Play Store promotion (internal → production)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Environment Config
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// app.config.ts — Expo config
|
|
289
|
+
export default ({ config }: ConfigContext): ExpoConfig => ({
|
|
290
|
+
...config,
|
|
291
|
+
extra: {
|
|
292
|
+
apiUrl: process.env.API_URL ?? 'https://api.quickbite.app',
|
|
293
|
+
sentryDsn: process.env.SENTRY_DSN,
|
|
294
|
+
mapboxToken: process.env.MAPBOX_TOKEN,
|
|
295
|
+
eas: { projectId: process.env.EAS_PROJECT_ID },
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Testing Strategy
|
|
303
|
+
|
|
304
|
+
### Testing Pyramid
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
┌─────┐
|
|
308
|
+
│ E2E │ 10% — Critical flows only
|
|
309
|
+
│Detox│ (order placement, auth, payment)
|
|
310
|
+
┌┴─────┴┐
|
|
311
|
+
│ Integ │ 30% — Screen-level tests
|
|
312
|
+
│ RNTL │ (render + interaction + navigation)
|
|
313
|
+
┌┴───────┴┐
|
|
314
|
+
│ Unit │ 60% — Business logic, hooks, utils
|
|
315
|
+
│ Jest │ (stores, API transforms, validators)
|
|
316
|
+
└─────────┘
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Unit Test Example
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// __tests__/stores/cart.test.ts
|
|
323
|
+
describe('CartStore', () => {
|
|
324
|
+
beforeEach(() => useCartStore.getState().clear());
|
|
325
|
+
|
|
326
|
+
it('calculates total with delivery fee', () => {
|
|
327
|
+
const { addItem, total, deliveryFee } = useCartStore.getState();
|
|
328
|
+
addItem(mockMenuItem, 2, []); // $12.99 each
|
|
329
|
+
expect(total()).toBe(25.98 + deliveryFee());
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('applies promo code discount', () => {
|
|
333
|
+
const { addItem, applyPromo, total } = useCartStore.getState();
|
|
334
|
+
addItem(mockMenuItem, 1, []);
|
|
335
|
+
applyPromo('SAVE20'); // 20% off
|
|
336
|
+
expect(total()).toBeCloseTo(12.99 * 0.8 + 3.99); // + delivery
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### E2E Critical Flow
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// e2e/orderPlacement.test.ts
|
|
345
|
+
describe('Order Placement', () => {
|
|
346
|
+
beforeAll(async () => { await device.launchApp(); await loginAs('test@user.com'); });
|
|
347
|
+
|
|
348
|
+
it('completes full order flow', async () => {
|
|
349
|
+
// Browse
|
|
350
|
+
await element(by.id('restaurant-card-0')).tap();
|
|
351
|
+
await element(by.id('menu-item-0')).tap();
|
|
352
|
+
await element(by.id('add-to-cart')).tap();
|
|
353
|
+
|
|
354
|
+
// Checkout
|
|
355
|
+
await element(by.id('cart-button')).tap();
|
|
356
|
+
await element(by.id('checkout-button')).tap();
|
|
357
|
+
await element(by.id('address-0')).tap();
|
|
358
|
+
await element(by.id('pay-button')).tap();
|
|
359
|
+
|
|
360
|
+
// Confirmation
|
|
361
|
+
await expect(element(by.text('Order Confirmed'))).toBeVisible();
|
|
362
|
+
await expect(element(by.id('order-tracking-map'))).toBeVisible();
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Key Architecture Decisions
|
|
370
|
+
|
|
371
|
+
| Decision | Choice | Rationale |
|
|
372
|
+
|----------|--------|-----------|
|
|
373
|
+
| Framework | Expo managed | OTA updates, EAS Build, no native config maintenance |
|
|
374
|
+
| Navigation | React Navigation 7 | Most mature, type-safe, deep linking support |
|
|
375
|
+
| Client state | Zustand + MMKV | Minimal boilerplate, fast persistence |
|
|
376
|
+
| Server state | TanStack Query v5 | Caching, background refetch, optimistic updates |
|
|
377
|
+
| Maps | react-native-maps + Mapbox | Real-time driver tracking needs custom tiles |
|
|
378
|
+
| Payments | Stripe React Native SDK | PCI compliance handled by Stripe |
|
|
379
|
+
| Push | Expo Notifications + FCM | Unified API, background handling |
|
|
380
|
+
| Crash reporting | Sentry | Source map support, breadcrumbs, performance monitoring |
|
|
381
|
+
| Analytics | PostHog | Self-hostable, funnel analysis, feature flags |
|
|
382
|
+
| Local DB | WatermelonDB | Lazy loading, offline-first, observable queries |
|