cfsa-antigravity 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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mobile-offline-sync
|
|
3
|
+
description: Offline-first data synchronization for mobile apps covering conflict resolution, optimistic UI, local databases, background sync, and network-aware degradation. Use when building mobile features that must work without connectivity.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Mobile Offline Sync
|
|
8
|
+
|
|
9
|
+
Build mobile applications that work reliably without network connectivity and synchronize seamlessly when reconnected.
|
|
10
|
+
|
|
11
|
+
## Conflict Resolution Strategies
|
|
12
|
+
|
|
13
|
+
When multiple clients modify the same record offline, conflicts are inevitable. Choose a strategy based on data semantics.
|
|
14
|
+
|
|
15
|
+
| Strategy | How It Works | Best For | Risk |
|
|
16
|
+
|----------|-------------|----------|------|
|
|
17
|
+
| Last-Write-Wins (LWW) | Highest timestamp wins | User preferences, non-critical data | Silent data loss |
|
|
18
|
+
| Field-Level Merge | Merge non-conflicting field changes | Profile data, settings | Complex implementation |
|
|
19
|
+
| CRDTs | Mathematically guaranteed convergence | Counters, sets, collaborative text | Large metadata overhead |
|
|
20
|
+
| Manual Merge | Present both versions to user | Documents, critical business data | Requires UI for resolution |
|
|
21
|
+
| Server-Wins | Server version always wins | Read-heavy data, admin-managed content | Client changes lost |
|
|
22
|
+
| Client-Wins | Client version always wins | Draft content, user-local data | Server changes lost |
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Field-level merge implementation
|
|
26
|
+
interface SyncRecord {
|
|
27
|
+
id: string;
|
|
28
|
+
fields: Record<string, unknown>;
|
|
29
|
+
fieldTimestamps: Record<string, number>; // Per-field last-modified
|
|
30
|
+
version: number;
|
|
31
|
+
deletedAt?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function fieldLevelMerge(
|
|
35
|
+
local: SyncRecord,
|
|
36
|
+
remote: SyncRecord
|
|
37
|
+
): SyncRecord {
|
|
38
|
+
const merged: SyncRecord = {
|
|
39
|
+
id: local.id,
|
|
40
|
+
fields: {},
|
|
41
|
+
fieldTimestamps: {},
|
|
42
|
+
version: Math.max(local.version, remote.version) + 1,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const allFields = new Set([
|
|
46
|
+
...Object.keys(local.fields),
|
|
47
|
+
...Object.keys(remote.fields),
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
for (const field of allFields) {
|
|
51
|
+
const localTs = local.fieldTimestamps[field] ?? 0;
|
|
52
|
+
const remoteTs = remote.fieldTimestamps[field] ?? 0;
|
|
53
|
+
|
|
54
|
+
if (localTs >= remoteTs) {
|
|
55
|
+
merged.fields[field] = local.fields[field];
|
|
56
|
+
merged.fieldTimestamps[field] = localTs;
|
|
57
|
+
} else {
|
|
58
|
+
merged.fields[field] = remote.fields[field];
|
|
59
|
+
merged.fieldTimestamps[field] = remoteTs;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return merged;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Anti-pattern**: Using wall-clock timestamps for LWW without clock synchronization. Use hybrid logical clocks (HLC) or server-assigned timestamps instead.
|
|
68
|
+
|
|
69
|
+
## Optimistic UI Updates
|
|
70
|
+
|
|
71
|
+
Apply changes to the local UI immediately. If the server rejects the change, roll back.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Optimistic mutation with rollback
|
|
75
|
+
interface OptimisticMutation<T> {
|
|
76
|
+
id: string;
|
|
77
|
+
type: 'create' | 'update' | 'delete';
|
|
78
|
+
table: string;
|
|
79
|
+
payload: T;
|
|
80
|
+
previousState?: T;
|
|
81
|
+
timestamp: number;
|
|
82
|
+
retryCount: number;
|
|
83
|
+
maxRetries: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class OptimisticStore<T extends { id: string }> {
|
|
87
|
+
private pendingMutations = new Map<string, OptimisticMutation<T>>();
|
|
88
|
+
private confirmedState = new Map<string, T>();
|
|
89
|
+
|
|
90
|
+
apply(mutation: OptimisticMutation<T>): void {
|
|
91
|
+
// Save rollback state
|
|
92
|
+
mutation.previousState = this.confirmedState.get(mutation.payload.id);
|
|
93
|
+
this.pendingMutations.set(mutation.id, mutation);
|
|
94
|
+
|
|
95
|
+
// Apply optimistically to local state
|
|
96
|
+
if (mutation.type === 'delete') {
|
|
97
|
+
this.confirmedState.delete(mutation.payload.id);
|
|
98
|
+
} else {
|
|
99
|
+
this.confirmedState.set(mutation.payload.id, mutation.payload);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
confirm(mutationId: string): void {
|
|
104
|
+
this.pendingMutations.delete(mutationId);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
rollback(mutationId: string): void {
|
|
108
|
+
const mutation = this.pendingMutations.get(mutationId);
|
|
109
|
+
if (!mutation) return;
|
|
110
|
+
|
|
111
|
+
if (mutation.previousState) {
|
|
112
|
+
this.confirmedState.set(mutation.payload.id, mutation.previousState);
|
|
113
|
+
} else {
|
|
114
|
+
this.confirmedState.delete(mutation.payload.id);
|
|
115
|
+
}
|
|
116
|
+
this.pendingMutations.delete(mutationId);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// React hook for optimistic mutations
|
|
123
|
+
function useOptimisticMutation<T>(
|
|
124
|
+
mutationFn: (data: T) => Promise<T>,
|
|
125
|
+
options: {
|
|
126
|
+
onOptimistic: (data: T) => void;
|
|
127
|
+
onConfirm: (data: T) => void;
|
|
128
|
+
onRollback: (data: T, error: Error) => void;
|
|
129
|
+
}
|
|
130
|
+
) {
|
|
131
|
+
const mutate = useCallback(async (data: T) => {
|
|
132
|
+
options.onOptimistic(data);
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const result = await mutationFn(data);
|
|
136
|
+
options.onConfirm(result);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
options.onRollback(data, error as Error);
|
|
139
|
+
}
|
|
140
|
+
}, [mutationFn, options]);
|
|
141
|
+
|
|
142
|
+
return { mutate };
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Rule**: Always store the previous state before applying an optimistic update so rollback is possible.
|
|
147
|
+
**Rule**: Show a subtle indicator (sync icon, muted timestamp) for unconfirmed optimistic changes.
|
|
148
|
+
|
|
149
|
+
## Local Database Options
|
|
150
|
+
|
|
151
|
+
| Database | Platform | Strengths | Weaknesses |
|
|
152
|
+
|----------|----------|-----------|------------|
|
|
153
|
+
| SQLite (via expo-sqlite, react-native-sqlite-storage) | iOS, Android | Mature, SQL, large datasets | No reactive queries by default |
|
|
154
|
+
| WatermelonDB | iOS, Android | Reactive, lazy loading, fast sync | Complex setup, learning curve |
|
|
155
|
+
| Realm (MongoDB) | iOS, Android | Object-oriented, reactive, sync built-in | Vendor lock-in with Atlas |
|
|
156
|
+
| MMKV | iOS, Android | Fastest key-value store | Not a relational database |
|
|
157
|
+
| OPFS + SQLite (wa-sqlite) | Web | SQL in browser, persistent | Browser support varies |
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// WatermelonDB - Model with sync support
|
|
161
|
+
import { Model } from '@nozbe/watermelondb';
|
|
162
|
+
import { field, date, readonly } from '@nozbe/watermelondb/decorators';
|
|
163
|
+
|
|
164
|
+
class Task extends Model {
|
|
165
|
+
static table = 'tasks';
|
|
166
|
+
|
|
167
|
+
@field('title') title!: string;
|
|
168
|
+
@field('is_completed') isCompleted!: boolean;
|
|
169
|
+
@field('server_id') serverId?: string;
|
|
170
|
+
@readonly @date('created_at') createdAt!: Date;
|
|
171
|
+
@date('updated_at') updatedAt!: Date;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Schema definition
|
|
175
|
+
const schema = appSchema({
|
|
176
|
+
version: 1,
|
|
177
|
+
tables: [
|
|
178
|
+
tableSchema({
|
|
179
|
+
name: 'tasks',
|
|
180
|
+
columns: [
|
|
181
|
+
{ name: 'title', type: 'string' },
|
|
182
|
+
{ name: 'is_completed', type: 'boolean' },
|
|
183
|
+
{ name: 'server_id', type: 'string', isOptional: true },
|
|
184
|
+
{ name: 'created_at', type: 'number' },
|
|
185
|
+
{ name: 'updated_at', type: 'number' },
|
|
186
|
+
],
|
|
187
|
+
}),
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Background Sync Scheduling
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// React Native - Background fetch for sync
|
|
196
|
+
import BackgroundFetch from 'react-native-background-fetch';
|
|
197
|
+
|
|
198
|
+
function configureBackgroundSync() {
|
|
199
|
+
BackgroundFetch.configure(
|
|
200
|
+
{
|
|
201
|
+
minimumFetchInterval: 15, // minutes (OS may defer)
|
|
202
|
+
stopOnTerminate: false,
|
|
203
|
+
startOnBoot: true,
|
|
204
|
+
enableHeadless: true,
|
|
205
|
+
requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY,
|
|
206
|
+
},
|
|
207
|
+
async (taskId) => {
|
|
208
|
+
console.log('[BackgroundFetch] Task:', taskId);
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
await syncPendingMutations();
|
|
212
|
+
await pullRemoteChanges();
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error('[BackgroundFetch] Sync failed:', error);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
BackgroundFetch.finish(taskId);
|
|
218
|
+
},
|
|
219
|
+
(taskId) => {
|
|
220
|
+
// Task timeout - OS is forcing termination
|
|
221
|
+
console.warn('[BackgroundFetch] Timeout:', taskId);
|
|
222
|
+
BackgroundFetch.finish(taskId);
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Rule**: Background sync is best-effort. The OS controls scheduling. Never assume a specific interval.
|
|
229
|
+
**Rule**: Background tasks on iOS have ~30 seconds. Keep sync operations fast and incremental.
|
|
230
|
+
|
|
231
|
+
## Queue Management for Pending Mutations
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
interface MutationQueue {
|
|
235
|
+
id: string;
|
|
236
|
+
operation: 'CREATE' | 'UPDATE' | 'DELETE';
|
|
237
|
+
table: string;
|
|
238
|
+
recordId: string;
|
|
239
|
+
payload: Record<string, unknown>;
|
|
240
|
+
createdAt: number;
|
|
241
|
+
retryCount: number;
|
|
242
|
+
lastError?: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
class SyncQueue {
|
|
246
|
+
private db: SQLiteDatabase;
|
|
247
|
+
private maxRetries = 5;
|
|
248
|
+
|
|
249
|
+
async enqueue(mutation: Omit<MutationQueue, 'id' | 'createdAt' | 'retryCount'>): Promise<void> {
|
|
250
|
+
await this.db.execute(
|
|
251
|
+
`INSERT INTO sync_queue (id, operation, table_name, record_id, payload, created_at, retry_count)
|
|
252
|
+
VALUES (?, ?, ?, ?, ?, ?, 0)`,
|
|
253
|
+
[generateId(), mutation.operation, mutation.table, mutation.recordId,
|
|
254
|
+
JSON.stringify(mutation.payload), Date.now()]
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async processQueue(): Promise<SyncResult> {
|
|
259
|
+
const pending = await this.db.query<MutationQueue>(
|
|
260
|
+
`SELECT * FROM sync_queue WHERE retry_count < ? ORDER BY created_at ASC`,
|
|
261
|
+
[this.maxRetries]
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const results: SyncResult = { succeeded: 0, failed: 0, skipped: 0 };
|
|
265
|
+
|
|
266
|
+
for (const mutation of pending) {
|
|
267
|
+
try {
|
|
268
|
+
await this.sendToServer(mutation);
|
|
269
|
+
await this.dequeue(mutation.id);
|
|
270
|
+
results.succeeded++;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (isRetryable(error)) {
|
|
273
|
+
await this.incrementRetry(mutation.id, (error as Error).message);
|
|
274
|
+
results.failed++;
|
|
275
|
+
} else {
|
|
276
|
+
// Non-retryable: move to dead letter queue
|
|
277
|
+
await this.moveToDeadLetter(mutation, error);
|
|
278
|
+
results.skipped++;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return results;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async getPendingCount(): Promise<number> {
|
|
287
|
+
const result = await this.db.query<{ count: number }>(
|
|
288
|
+
'SELECT COUNT(*) as count FROM sync_queue WHERE retry_count < ?',
|
|
289
|
+
[this.maxRetries]
|
|
290
|
+
);
|
|
291
|
+
return result[0].count;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Anti-pattern**: Unbounded retry without backoff. Use exponential backoff: `delay = min(baseDelay * 2^retryCount, maxDelay)`.
|
|
297
|
+
**Anti-pattern**: Losing mutations on app crash. Persist the queue to SQLite, not in-memory.
|
|
298
|
+
|
|
299
|
+
## Network Status Detection
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import NetInfo, { NetInfoState } from '@react-native-community/netinfo';
|
|
303
|
+
|
|
304
|
+
class NetworkMonitor {
|
|
305
|
+
private listeners = new Set<(online: boolean) => void>();
|
|
306
|
+
private currentState: NetInfoState | null = null;
|
|
307
|
+
|
|
308
|
+
start(): () => void {
|
|
309
|
+
const unsubscribe = NetInfo.addEventListener((state) => {
|
|
310
|
+
const wasOnline = this.isOnline();
|
|
311
|
+
this.currentState = state;
|
|
312
|
+
const nowOnline = this.isOnline();
|
|
313
|
+
|
|
314
|
+
if (!wasOnline && nowOnline) {
|
|
315
|
+
// Came back online -- trigger sync
|
|
316
|
+
this.notifyListeners(true);
|
|
317
|
+
} else if (wasOnline && !nowOnline) {
|
|
318
|
+
this.notifyListeners(false);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return unsubscribe;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
isOnline(): boolean {
|
|
326
|
+
if (!this.currentState) return true; // Assume online until proven otherwise
|
|
327
|
+
return this.currentState.isConnected === true &&
|
|
328
|
+
this.currentState.isInternetReachable !== false;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
onStatusChange(listener: (online: boolean) => void): () => void {
|
|
332
|
+
this.listeners.add(listener);
|
|
333
|
+
return () => this.listeners.delete(listener);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private notifyListeners(online: boolean): void {
|
|
337
|
+
this.listeners.forEach((listener) => listener(online));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Rule**: `isConnected` can be `true` while `isInternetReachable` is `false` (e.g., captive portal). Check both.
|
|
343
|
+
|
|
344
|
+
## Graceful Degradation Patterns
|
|
345
|
+
|
|
346
|
+
| Feature | Online Behavior | Offline Behavior |
|
|
347
|
+
|---------|----------------|-----------------|
|
|
348
|
+
| Data display | Fetch from server, cache locally | Show cached data with "offline" banner |
|
|
349
|
+
| Create/edit | Send to server immediately | Save locally, queue for sync |
|
|
350
|
+
| Search | Server-side search | Local full-text search on cached data |
|
|
351
|
+
| Images | Load from CDN | Show cached images, placeholder for uncached |
|
|
352
|
+
| Auth | Validate token with server | Accept cached token if not expired |
|
|
353
|
+
| Real-time features | WebSocket connection | Disabled with "reconnecting" indicator |
|
|
354
|
+
|
|
355
|
+
## Sync Status UI Indicators
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
function SyncStatusBadge() {
|
|
359
|
+
const { isOnline, pendingCount, lastSyncAt, syncState } = useSyncStatus();
|
|
360
|
+
|
|
361
|
+
if (syncState === 'syncing') {
|
|
362
|
+
return (
|
|
363
|
+
<View style={styles.badge}>
|
|
364
|
+
<ActivityIndicator size="small" />
|
|
365
|
+
<Text>Syncing {pendingCount} changes...</Text>
|
|
366
|
+
</View>
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (!isOnline) {
|
|
371
|
+
return (
|
|
372
|
+
<View style={[styles.badge, styles.offline]}>
|
|
373
|
+
<OfflineIcon />
|
|
374
|
+
<Text>Offline - {pendingCount} changes pending</Text>
|
|
375
|
+
</View>
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (pendingCount > 0) {
|
|
380
|
+
return (
|
|
381
|
+
<View style={[styles.badge, styles.pending]}>
|
|
382
|
+
<Text>{pendingCount} unsynced</Text>
|
|
383
|
+
</View>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return null; // No badge when fully synced and online
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Rule**: Never show "all synced" permanently. Only show sync status when there is something to communicate.
|
|
392
|
+
|
|
393
|
+
## Data Versioning
|
|
394
|
+
|
|
395
|
+
Track schema versions to handle migrations when the app updates and the local database schema changes.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
const MIGRATIONS: Migration[] = [
|
|
399
|
+
{
|
|
400
|
+
fromVersion: 1,
|
|
401
|
+
toVersion: 2,
|
|
402
|
+
sql: [
|
|
403
|
+
'ALTER TABLE tasks ADD COLUMN priority INTEGER DEFAULT 0',
|
|
404
|
+
'CREATE INDEX idx_tasks_priority ON tasks(priority)',
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
fromVersion: 2,
|
|
409
|
+
toVersion: 3,
|
|
410
|
+
sql: [
|
|
411
|
+
'ALTER TABLE tasks ADD COLUMN assigned_to TEXT',
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
];
|
|
415
|
+
|
|
416
|
+
async function runMigrations(db: SQLiteDatabase, currentVersion: number, targetVersion: number) {
|
|
417
|
+
const applicable = MIGRATIONS.filter(
|
|
418
|
+
(m) => m.fromVersion >= currentVersion && m.toVersion <= targetVersion
|
|
419
|
+
).sort((a, b) => a.fromVersion - b.fromVersion);
|
|
420
|
+
|
|
421
|
+
for (const migration of applicable) {
|
|
422
|
+
await db.transaction(async (tx) => {
|
|
423
|
+
for (const sql of migration.sql) {
|
|
424
|
+
await tx.execute(sql);
|
|
425
|
+
}
|
|
426
|
+
await tx.execute('PRAGMA user_version = ?', [migration.toVersion]);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Output Checklist
|
|
433
|
+
|
|
434
|
+
- [ ] Conflict resolution strategy chosen and documented
|
|
435
|
+
- [ ] Optimistic UI with rollback on server rejection
|
|
436
|
+
- [ ] Local database persists data across app restarts
|
|
437
|
+
- [ ] Background sync configured with OS-appropriate scheduling
|
|
438
|
+
- [ ] Mutation queue persisted to disk (survives crashes)
|
|
439
|
+
- [ ] Network status monitored with reconnection-triggered sync
|
|
440
|
+
- [ ] UI indicates offline state and pending change count
|
|
441
|
+
- [ ] Retry with exponential backoff and max retry limit
|
|
442
|
+
- [ ] Dead letter queue for permanently failed mutations
|
|
443
|
+
- [ ] Database migrations handle schema version changes
|