mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
Improve AI guidelines
This commit is contained in:
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../spec/guidelines/ARCHITECTURE.md
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
description: Flutter/Dart conventions for Zapstore projects
|
||||
globs: ["**/*.dart", "**/pubspec.yaml"]
|
||||
---
|
||||
|
||||
# Flutter/Dart Conventions
|
||||
|
||||
## State Management
|
||||
|
||||
- Use Flutter Hooks (`HookWidget`, `HookConsumerWidget`) for local widget state — not `StatefulWidget`.
|
||||
- Use `useState`, `useAnimationController`, `useEffect` over manual `State` classes.
|
||||
- Use Riverpod providers for shared/global state. Keep providers focused and composable.
|
||||
- Prefer `ref.watch` for reactive UI, `ref.read` in callbacks only.
|
||||
|
||||
## Data & Async
|
||||
|
||||
- All async work must be cancellable. Pass `CancellationToken` or use `ref.onDispose`.
|
||||
- Never `await` inside `build()`. Move async work to providers or `useEffect`.
|
||||
- Use `switch` on sealed classes / union types for exhaustive state handling:
|
||||
```dart
|
||||
return switch (state) {
|
||||
StorageLoading() => const CircularProgressIndicator(),
|
||||
StorageError(:final exception) => Text('Error: $exception'),
|
||||
StorageData(:final models) => MyWidget(models),
|
||||
};
|
||||
```
|
||||
- All async operations must have explicit loading, success, and error states in the UI.
|
||||
|
||||
## Widget Structure
|
||||
|
||||
- One widget per file. File name matches widget name in snake_case.
|
||||
- Keep `build()` methods short — extract sub-widgets or use helper methods.
|
||||
- Widgets must not manage relay connections, storage, or background jobs.
|
||||
- Use `const` constructors wherever possible.
|
||||
|
||||
## Naming
|
||||
|
||||
- Files: `snake_case.dart`. Classes: `PascalCase`. Variables/methods: `camelCase`.
|
||||
- Providers: `<noun>Provider` or `<noun>NotifierProvider`.
|
||||
- Services: `<Noun>Service`. Notifiers: `<Noun>Notifier`.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Never swallow exceptions silently. Surface errors to the UI or log them.
|
||||
- Use typed exceptions where the caller needs to distinguish error types.
|
||||
- `try/catch` at the boundary (provider/service), not deep in domain logic.
|
||||
|
||||
## Testing
|
||||
|
||||
- Test providers and services, not widget internals.
|
||||
- Use `ProviderContainer` for unit-testing Riverpod providers.
|
||||
- Mock external dependencies (storage, network) — no real I/O in unit tests.
|
||||
- Widget tests for critical UI states: loading, error, empty, success.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Run `fvm flutter pub get` after any `pubspec.yaml` change.
|
||||
- Pin Flutter SDK version via FVM (`fvm use <version>`).
|
||||
- Prefer packages already in use over adding new ones.
|
||||
|
||||
## Build
|
||||
|
||||
- Assume Android as default target unless instructed otherwise.
|
||||
- Release builds must be reproducible (see INVARIANTS.md).
|
||||
- Run `flutter analyze` — fix all issues before committing.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../spec/guidelines/INVARIANTS.md
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../spec/guidelines/QUALITY_BAR.md
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../spec/guidelines/VISION.md
|
||||
@@ -1 +0,0 @@
|
||||
CONTEXT.md
|
||||
@@ -1,17 +1,8 @@
|
||||
# AI Agents
|
||||
# Zapstore — Agent Instructions
|
||||
|
||||
This document is the entry point for AI assistants.
|
||||
All behavioral authority lives in the project spec, not here.
|
||||
Local-first, Nostr-native app store for Android.
|
||||
|
||||
If anything in this file conflicts with files under `spec/guidelines/`,
|
||||
this file is wrong.
|
||||
|
||||
## What This Repository Is
|
||||
|
||||
Zapstore is a local-first, Nostr-native app store for Android.
|
||||
It discovers, downloads, verifies, and installs APKs signed by developers the user trusts.
|
||||
|
||||
Users can support developers directly via Lightning zaps.
|
||||
All behavioral authority lives in `spec/guidelines/`. If this file conflicts, guidelines win.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
@@ -22,51 +13,29 @@ Users can support developers directly via Lightning zaps.
|
||||
| Quality standards | `spec/guidelines/QUALITY_BAR.md` |
|
||||
| Product vision | `spec/guidelines/VISION.md` |
|
||||
| Feature specs | `spec/features/` |
|
||||
| Active work | `work/` |
|
||||
| Active work | `spec/work/` |
|
||||
| Decisions & learnings | `spec/knowledge/` |
|
||||
|
||||
## Project Spec Structure
|
||||
|
||||
spec/
|
||||
guidelines/ # Permanent rules (human-owned, never AI-modified)
|
||||
ARCHITECTURE.md # Package boundaries, dependencies, key patterns
|
||||
INVARIANTS.md # Non-negotiable behavioral guarantees
|
||||
QUALITY_BAR.md # Standards, when to create specs
|
||||
VISION.md # Product goals and non-goals
|
||||
|
||||
features/ # Feature specs (behavioral contracts)
|
||||
_TEMPLATE.md # Template with example
|
||||
FEAT-001-*.md # Actual feature specs
|
||||
|
||||
work/ # Active work packets (temporary, delete after merge)
|
||||
_TEMPLATE.md # Template with example
|
||||
WORK-001-*.md # Actual work packets
|
||||
|
||||
## How to Work
|
||||
|
||||
1. Before implementing, check `spec/features/` for a relevant feature spec
|
||||
2. For non-trivial work, create a work packet in `work/`
|
||||
3. Every code change must trace to a task in the work packet
|
||||
4. If a spec is unclear or incorrect, report a Spec Issue—do not guess
|
||||
|
||||
See `spec/guidelines/QUALITY_BAR.md` for what qualifies as "non-trivial."
|
||||
Guidelines are symlinked into `.cursor/rules/` and auto-load.
|
||||
|
||||
## File Ownership
|
||||
|
||||
**Never modify** files in `spec/guidelines/`.
|
||||
If a guideline seems wrong or incomplete, report it as a Spec Issue.
|
||||
|
||||
| Path | Owner | AI May Modify |
|
||||
|------|-------|---------------|
|
||||
| `spec/guidelines/*` | Human | No |
|
||||
| `spec/features/*` | Human | No (unless explicitly asked) |
|
||||
| `work/*.md` | AI | Yes |
|
||||
| `lib/**` | Shared | Yes |
|
||||
| `test/**` | Shared | Yes |
|
||||
| `AGENTS.md` | Human | No |
|
||||
| `spec/features/*` | Human | No (unless asked) |
|
||||
| `spec/work/*.md` | AI | Yes |
|
||||
| `spec/knowledge/*.md` | AI | Yes |
|
||||
| `lib/**`, `test/**` | Shared | Yes |
|
||||
|
||||
## Working Rules
|
||||
## Key Commands
|
||||
|
||||
```bash
|
||||
fvm flutter pub get # Dependencies
|
||||
fvm flutter analyze # Lint
|
||||
fvm flutter test # Tests
|
||||
```
|
||||
|
||||
## Project Rules
|
||||
|
||||
- Prefer small, localized changes. Avoid unrelated refactors.
|
||||
- After dependency changes, run: `fvm flutter pub get`
|
||||
- Fix any analyze/lint errors introduced by your changes.
|
||||
- Assume Android as default target unless instructed otherwise.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
description: Architecture — layers, dependency rules, ownership, common Dart/Flutter patterns
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Zapstore — Architecture
|
||||
|
||||
## Core Principle
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
description: Non-negotiable invariants — UI safety, async discipline, local-first, security, lifecycle
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Zapstore — Invariants
|
||||
|
||||
The following guarantees are non-negotiable.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
description: Quality expectations — when to spec, layer standards, testing, anti-patterns, AI workflow
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Zapstore — Quality Bar
|
||||
|
||||
## General Expectations
|
||||
@@ -66,6 +71,20 @@ If multiple phases: `WORK-005-a.md`, `WORK-005-b.md` (same feature number).
|
||||
- Failure, cancellation, and degraded-network paths must be covered.
|
||||
- Tests that only assert the happy path are insufficient.
|
||||
|
||||
### Test layers
|
||||
|
||||
- **Widget tests** (`flutter test`): preferred for UI state machines, all states
|
||||
(loading, empty, error, retry). Fully headless, no device needed.
|
||||
- **Integration tests** (`flutter test integration_test/`): used for flows that
|
||||
cross platform boundaries — downloads, installs, storage, notifications.
|
||||
Run against a connected Android emulator or device via ADB.
|
||||
- **Patrol** is the integration test framework. Use `patrolTest` and `$.native`
|
||||
for interacting with Android system UI (e.g. PackageInstaller dialogs).
|
||||
Do not use `testWidgets` for integration tests.
|
||||
- Pre-grant `REQUEST_INSTALL_PACKAGES` via
|
||||
`adb shell appops set <package> REQUEST_INSTALL_PACKAGES allow`
|
||||
before running install tests, to avoid a permissions setup screen.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Silent failures
|
||||
@@ -91,7 +110,7 @@ This project uses a spec-first workflow to collaborate safely with AI.
|
||||
|
||||
### What AI Owns
|
||||
|
||||
- Work packets under `work/`
|
||||
- Work packets under `spec/work/`
|
||||
- Refinement of task plans during implementation
|
||||
|
||||
### Spec-First Rule
|
||||
@@ -109,3 +128,7 @@ For non-trivial work, changes are not complete unless:
|
||||
- Edge cases and failure modes are addressed
|
||||
|
||||
This workflow exists to prevent AI drift, accidental refactors, and UX regressions.
|
||||
|
||||
## Knowledge Entries
|
||||
|
||||
After a work packet merges, promote non-obvious decisions to `spec/knowledge/DEC-XXX-*.md`. See `spec/knowledge/_TEMPLATE.md` for format and criteria.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
description: Product vision — what Zapstore is, who it serves, what success means
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Zapstore — Vision
|
||||
|
||||
## What Zapstore Is
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
date: YYYY-MM-DD
|
||||
tags: [tag1, tag2, tag3]
|
||||
problem: One-line description of the problem encountered
|
||||
---
|
||||
|
||||
# DEC-XXX — Short Title
|
||||
|
||||
## Problem
|
||||
|
||||
What went wrong, or what was unclear. Concrete and specific.
|
||||
|
||||
## Context
|
||||
|
||||
Why this came up. What was being built. What made it non-obvious.
|
||||
|
||||
## Decision
|
||||
|
||||
What was chosen. One clear statement.
|
||||
|
||||
## Options Considered
|
||||
|
||||
- **Option A** — description, why rejected
|
||||
- **Option B** — description, why rejected
|
||||
- **Option C (chosen)** — description, why selected
|
||||
|
||||
## Rationale
|
||||
|
||||
Why this option fits this codebase, this team, this context.
|
||||
|
||||
## How to Avoid This Problem Next Time
|
||||
|
||||
Concrete rule or pattern an agent can follow automatically:
|
||||
- Do X instead of Y
|
||||
- When you see Z, always do W
|
||||
- Reference: `path/to/example.go` shows the correct pattern
|
||||
|
||||
---
|
||||
|
||||
# Example: DEC-001 — Separate polling from local watching
|
||||
|
||||
---
|
||||
date: 2026-02-04
|
||||
tags: [state-management, providers, riverpod, skeleton]
|
||||
problem: Mixed local/remote data in one provider caused skeleton showing during refreshes
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
The updates screen showed a skeleton loading state during every pull-to-refresh, even when data was already loaded locally.
|
||||
|
||||
## Context
|
||||
|
||||
Building the updates screen. A single `CategorizedUpdatesNotifier` was both watching local DB and performing remote fetches. Timer-based invalidation triggered network requests on every rebuild.
|
||||
|
||||
## Decision
|
||||
|
||||
Split into two providers: one owns remote polling, one watches local data only.
|
||||
|
||||
## Options Considered
|
||||
|
||||
- **Single provider** — simpler, but mixing concerns caused skeleton/loading state confusion
|
||||
- **Split providers (chosen)** — `UpdatePollerNotifier` (remote) + `CategorizedUpdatesNotifier` (local only)
|
||||
|
||||
## Rationale
|
||||
|
||||
Local provider is purely reactive — it never triggers network. Remote provider handles network + throttling. Clear separation means skeleton logic is simple: show only when no local data matches.
|
||||
|
||||
## How to Avoid This Problem Next Time
|
||||
|
||||
- Never mix `RemoteSource` and `LocalSource` queries in the same provider
|
||||
- If a provider needs both local reactivity and remote fetching, split it
|
||||
- Skeleton rule: `showSkeleton = installedIds.isNotEmpty && !hasAnyMatch` — once any match exists, never show skeleton again
|
||||
- See `lib/services/updates_service.dart` for the correct pattern
|
||||
@@ -40,6 +40,10 @@ Report blockers here instead of guessing. Format:
|
||||
|
||||
Brief updates as work proceeds.
|
||||
|
||||
## On Merge
|
||||
|
||||
Delete this work packet. If any decision here is non-obvious and worth remembering, promote it to `spec/knowledge/DEC-XXX-short-title.md` first.
|
||||
|
||||
---
|
||||
|
||||
# Example: WORK-002 — NWC Zaps
|
||||
Reference in New Issue
Block a user