- Move CONTEXT.md to root as AI entry point, symlink .cursorrules

- Rename specs/ to spec/ (singular)
- Consolidate templates into single _TEMPLATE.md files with examples
- Add "When to Create a Feature Spec" and work lifecycle to QUALITY_BAR.md
- Document package manager as FEAT-001 (first behavioral contract)
- Remove old _template/ directories
This commit is contained in:
franzap
2026-01-19 22:13:40 -03:00
parent 09e1822d9c
commit 79648234f5
14 changed files with 397 additions and 257 deletions
-20
View File
@@ -1,20 +0,0 @@
# Zapstore — Cursor Rules
Source of truth:
- specs/guidelines/CONTEXT.md (orientation only)
- specs/guidelines/VISION.md
- specs/guidelines/ARCHITECTURE.md
- specs/guidelines/INVARIANTS.md
- specs/guidelines/QUALITY_BAR.md
Hard constraints:
- Do NOT edit files under specs/guidelines unless explicitly instructed by a human.
- If specs are unclear or contradictory, STOP and report a "Spec Issue". Do not guess.
Working 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.
- Do not use polling or artificial Future.delayed; await Futures/Streams correctly.
- Keep lib/widgets/common generic and reusable.
- Assume Android as default target unless instructed otherwise.
+1
View File
@@ -0,0 +1 @@
CONTEXT.md
+70
View File
@@ -0,0 +1,70 @@
# Zapstore — Project Context
This document is the entry point for AI assistants.
All behavioral authority lives in the project spec, not here.
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.
## 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."
## 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 |
| `CONTEXT.md` | Human | No |
## Key Dependencies
- **models** / **purplebase**: Nostr SDK (local-first storage, relay sync, domain models).
See package README in pub cache. Basic usage patterns in `spec/guidelines/ARCHITECTURE.md`.
- **amber_signer**: NIP-55 Android signer integration.
- **background_downloader**: Download management with pause/resume.
## Working 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.
- Do not use polling or artificial `Future.delayed`; await Futures/Streams correctly.
- Keep `lib/widgets/common` generic and reusable.
- Assume Android as default target unless instructed otherwise.
+122
View File
@@ -0,0 +1,122 @@
# FEAT-001 — Package Manager
## Goal
Single source of truth for installed packages and active install operations.
Manages the complete lifecycle: download → verify → install, with pause/resume/cancel support.
## Non-Goals
- Managing non-APK file types
- Auto-updating without user awareness
- Installing from sources other than Nostr-published releases
## User-Visible Behavior
### Download Phase
- User taps "Install" → download begins, progress shown
- User can pause/resume/cancel active downloads
- Multiple downloads queue automatically (max 3 concurrent)
- "Update All" queues all updates immediately with visual feedback
### Verification Phase
- After download completes, hash verification runs
- Verification state is visible (not hidden)
- Hash mismatch blocks install with clear error
### Permission Phase
- If "Install unknown apps" permission not granted, user is prompted
- Permission state is explicit in UI
- Once granted, all waiting installs advance automatically
### Install Phase
- Native Android install dialog shown
- One install dialog at a time (serialized)
- If user dismisses dialog, install shows "Tap to retry" state
- Success updates installed list immediately (no stale UI)
### Failure States
- Download failed → clear error, can retry
- Hash mismatch → error, cannot proceed
- Certificate mismatch → offer "Uninstall and reinstall" option
- Permission denied → guidance to enable in Settings
## State Machine
Operations follow this sealed class hierarchy (`install_operation.dart`):
```
DownloadQueued → Downloading ↔ DownloadPaused
↓
Verifying
↓
AwaitingPermission (if needed)
↓
ReadyToInstall
↓
Installing → AwaitingUserAction (if dismissed)
↓
[cleared] or OperationFailed
```
State transitions are unidirectional except Downloading ↔ DownloadPaused.
## Edge Cases
- Network drops mid-download → download pauses or fails gracefully, can retry
- App backgrounded during install → install completes, UI updates on return
- 404 from origin server → automatic CDN fallback before failing
- Stale operations (>7 days) → garbage collected on app restart
- Android package DB race condition → state updated from target metadata, not sync
## Invariants
These are non-negotiable. Violations mean the implementation is broken.
1. **UI never blocks** — `install()` returns immediately; events drive state via EventChannel
2. **One install dialog at a time** — Android PackageInstaller limitation, enforced by serialization
3. **Hash verification before install** — Native side verifies before install session opens
4. **Permission flow is explicit** — `AwaitingPermission` state exists for UI feedback
5. **Downloaded files are cleaned up** — Deleted after success or dismissal
6. **No polling** — All state changes via callbacks/events, never periodic checks
## Integration Boundaries
```
┌─────────────────────────────────────────────────────────────┐
│ PackageManager (Dart) │
│ - State machine owner │
│ - Download management (background_downloader) │
│ - Orchestrates flow │
└─────────────────────────┬───────────────────────────────────┘
│ MethodChannel / EventChannel
┌─────────────────────────▼───────────────────────────────────┐
│ AndroidPackageManagerPlugin (Kotlin) │
│ - Hash verification │
│ - PackageInstaller session │
│ - Permission checks │
│ - Emits: verifying/started/success/failed/cancelled │
└─────────────────────────────────────────────────────────────┘
```
## Acceptance Criteria
- [ ] User can download, pause, resume, cancel downloads
- [ ] User can install apps with proper verification
- [ ] Multiple downloads queue correctly (max 3 concurrent)
- [ ] Install failures show actionable error messages
- [ ] Certificate mismatch offers force-update option
- [ ] UI remains responsive throughout all operations
- [ ] No operations block the UI thread
## Files
- `lib/services/package_manager/package_manager.dart` — Base class, state machine
- `lib/services/package_manager/install_operation.dart` — State definitions
- `lib/services/package_manager/android_package_manager.dart` — Android implementation
- `android/.../AndroidPackageManagerPlugin.kt` — Native side
+75
View File
@@ -0,0 +1,75 @@
# FEAT-XXX — Short Name
## Goal
1–2 sentences describing what this feature/bugfix achieves for the user.
## Non-Goals
- Explicitly list what is out of scope
- Prevents scope creep and AI drift
## User-Visible Behavior
- What the user sees or can do
- States: loading, success, error, empty (where relevant)
- Offline behavior
## Edge Cases
- Degraded or no network
- Cancellation / retry
- Invalid or partial data
- Permission denied
- Other relevant risks
## Acceptance Criteria
- [ ] Observable outcome 1
- [ ] Observable outcome 2
- [ ] Observable outcome 3
## Notes (optional)
- Anything that needs human decision
- Open questions
---
# Example: FEAT-002 — NWC Zaps
## Goal
Allow users to zap app developers directly from the app detail screen using Nostr Wallet Connect.
## Non-Goals
- In-app wallet management (just NWC connection)
- Zapping comments or reviews (only developers)
- Recurring zaps or subscriptions
## User-Visible Behavior
- Zap button visible on app detail screen when NWC connected
- Tapping opens amount selection dialog (21, 100, 500, 1000 sats, custom)
- Success: toast confirmation with amount
- Failure: error dialog with reason
- Button disabled with tooltip when developer has no lightning address
## Edge Cases
- Developer has no lightning address → button hidden or disabled with explanation
- NWC connection drops mid-zap → graceful error, suggest reconnect
- Insufficient wallet balance → clear error from wallet
- App backgrounded during zap → completes, toast on return
## Acceptance Criteria
- [ ] User can connect NWC from profile settings
- [ ] User can zap developer from app detail screen
- [ ] Zap fails gracefully with clear error message
- [ ] Zap button correctly disabled when NWC not connected
## Notes
- Consider whether to show cumulative zaps received by developer
@@ -6,6 +6,33 @@
- Happy-path-only implementations are insufficient.
- Failures must be explicit and observable.
## When to Create a Feature Spec
Create a spec if the work:
- Touches async/lifecycle code (risk of UI blocking or resource leaks)
- Modifies security-sensitive flows (verification, permissions, signing, secrets)
- Changes state machine behavior (package manager, auth, subscriptions)
- Affects multiple screens or services
- Could regress existing UX
**Skip the spec** if:
- Pure UI cosmetics (colors, spacing, copy changes)
- Adding a field to an existing model with no behavioral change
- Bug fix with obvious cause and obvious solution
- Dependency update with no API changes
When in doubt, create a spec. The overhead is low.
## Work Packet Lifecycle
1. Create `WORK-XXX-*.md` when starting non-trivial work
2. Update tasks and decisions as you work
3. **Delete after PR merges** — the feature spec remains as the contract
If multiple phases: `WORK-005-a.md`, `WORK-005-b.md` (same feature number).
## Layer Expectations
### models
@@ -46,54 +73,39 @@
- Artificial delays or polling
- Large refactors unrelated to the task
## Working With AI (Human Guidelines)
## Working With AI
This project uses a spec-first workflow to collaborate safely with AI.
### Documentation Discipline
- Markdown files must remain small, focused, and human-readable.
- Prefer extending or refining existing documents over creating new ones.
- New markdown files should be introduced only when unavoidable.
- Prefer extending existing documents over creating new ones.
- The goal is to do more with less, not to document everything.
### What Humans Own
- Foundation specs under `specs/guidelines/`
- Feature specs under `specs/features/`
- Guidelines under `spec/guidelines/` (never AI-modified)
- Feature specs under `spec/features/`
- Decisions to change behavior or architecture
### What AI Owns
- Execution plans under `work/**/task_plan.md`
- Decision logs and test matrices under `work/**/`
### When a Work Packet Is Required
- New features
- UX changes
- Async, lifecycle, or background work
- Security or verification changes
- Any non-trivial or risky change
- Work packets under `work/`
- Refinement of task plans during implementation
### Spec-First Rule
- Behavior changes require updating the spec first.
- Behavior changes require a feature spec first.
- During implementation, specs are read-only.
- If a spec is unclear or incorrect, AI must stop and report a "Spec Issue".
### Task Plan Usage
- Humans create the initial task_plan with a rough checklist.
- AI refines the plan, executes tasks, and marks progress.
- Every code change must map to an item in the task_plan.
### Task Completeness
For non-trivial work, changes are not considered complete unless:
For non-trivial work, changes are not complete unless:
- task_plan.md reflects the actual work performed
- test_matrix.md demonstrates behavioral coverage
- no significant code exists outside the task plan
- Work packet reflects the actual work performed
- No significant code exists outside the task plan
- Edge cases and failure modes are addressed
This workflow exists to prevent AI drift, accidental refactors, and UX regressions.
-31
View File
@@ -1,31 +0,0 @@
# FEAT-XXX — <short name>
## Goal
<1–2 sentences describing what this feature/bugfix achieves for the user>
## Non-goals
- <explicitly list what is out of scope>
## User-visible Behavior
- <what the user sees / can do>
- <states: loading / success / error where relevant>
## Edge Cases
- <degraded network>
- <cancellation / retry>
- <invalid / partial data>
- <other relevant risks>
## Acceptance Criteria
- [ ] <observable outcome 1>
- [ ] <observable outcome 2>
- [ ] <observable outcome 3>
## Notes / Open Questions (optional)
- <anything that needs human decision>
-85
View File
@@ -1,85 +0,0 @@
# Zapstore — Project Context
This document provides **orientation only**.
It does **not** define rules, behavior, or constraints.
If anything in this file conflicts with files under `specs/guidelines/`,
this file is wrong.
---
## What This Repository Is
Zapstore is a Flutter-based, local-first application store built on top of
the Nostr protocol and Bitcoin Lightning payments.
It allows users to:
- discover apps published via Nostr,
- verify and install applications safely,
- and directly support developers through zaps.
Zapstore prioritizes trust, verification, and user sovereignty over scale,
growth, or engagement metrics.
---
## Core Stack (High Level)
- **Frontend**: Flutter (Android-first)
- **Protocols**: Nostr, Lightning Network
- **Payments**: Zaps, NWC (NIP-47)
- **Data Model**: Nostr event kinds (apps, releases, files, zaps)
- **Storage**: Local-first (SQLite), relay-backed sync
- **Execution Model**: Async + isolates (non-blocking UI)
---
## Repository Structure (Conceptual)
This repository is organized into three main packages:
- **zapstore**
- Flutter UI and application orchestration
- Navigation, presentation, and user interaction
- **purplebase**
- Local-first storage, indexing, and relay synchronization
- Background work and isolate execution
- **models**
- Pure domain models and utilities
- Nostr kinds, parsing, signing, encryption, verification
Details and dependency rules are defined in `ARCHITECTURE.md`.
---
## How to Read the Specs (Important)
The following files define the actual guardrails of the project:
1. **VISION.md**
- What Zapstore is and is not
2. **ARCHITECTURE.md**
- Package responsibilities and dependency boundaries
3. **INVARIANTS.md**
- Non-negotiable behavioral guarantees
4. **QUALITY_BAR.md**
- Definition of acceptable work and anti-patterns
These files are human-owned and change slowly.
---
## What This File Is Not
- This file does **not** define invariants or rules
- This file does **not** describe UI flows or behavior
- This file does **not** override any foundation spec
- This file should remain small and stable
Its sole purpose is to provide initial context for humans and AI agents
before reading the foundation specifications.
+91
View File
@@ -0,0 +1,91 @@
# WORK-XXX — Short Name
**Feature:** FEAT-XXX-short-name.md
**Status:** In Progress | Complete
## Tasks
- [ ] 1. Task description
- Files: `lib/path/to/file.dart`
- Notes: any relevant context
- [ ] 2. Task description
- [ ] 3. Handle edge cases per spec
- [ ] 4. Self-review against INVARIANTS.md
## Test Coverage
| Scenario | Expected | Status |
|----------|----------|--------|
| Happy path | Describe expected behavior | [ ] |
| Edge case: network failure | Graceful degradation | [ ] |
| Edge case: cancellation | Clean cleanup | [ ] |
## Decisions
### YYYY-MM-DD — Decision title
**Context:** Why this decision came up.
**Options:** A, B, C considered.
**Decision:** Chosen option.
**Rationale:** Why.
## Spec Issues
Report blockers here instead of guessing. Format:
- **Issue:** Description of unclear/incorrect spec
- **Question:** What clarification is needed
## Progress Notes
Brief updates as work proceeds.
---
# Example: WORK-002 — NWC Zaps
**Feature:** FEAT-002-nwc-zaps.md
**Status:** In Progress
## Tasks
- [x] 1. Add nwc_wallet package dependency
- [x] 2. Create NwcService in lib/services/
- Files: `lib/services/nwc_service.dart`
- Stores connection string in SecureStorageService
- [x] 3. Add NWC settings UI in profile screen
- Files: `lib/screens/profile_screen.dart`, `lib/widgets/nwc_widgets.dart`
- [ ] 4. Create ZapButton widget
- Files: `lib/widgets/zap_button.dart`
- [ ] 5. Create ZapDialog for amount selection
- [ ] 6. Integrate into AppDetailScreen
- [ ] 7. Implement zap request flow (kind 9734)
- [ ] 8. Self-review against INVARIANTS.md
## Test Coverage
| Scenario | Expected | Status |
|----------|----------|--------|
| Connect valid NWC | Connection saved, status updated | [x] |
| Connect invalid NWC | Error shown, nothing saved | [x] |
| Zap with sufficient balance | Success toast | [ ] |
| Zap with insufficient balance | Wallet error shown | [ ] |
| Developer has no LN address | Button disabled with tooltip | [ ] |
## Decisions
### 2026-01-15 — NWC string storage
**Context:** Need to persist NWC connection string securely.
**Options:** New encrypted file, SecureStorageService, Nostr event.
**Decision:** SecureStorageService.
**Rationale:** Already used for nsec, platform-native secure storage.
## Spec Issues
_None_
## Progress Notes
**2026-01-15:** Completed NWC connection flow. Reused SecureStorageService.
**2026-01-17:** ZapButton done. Added edge case for missing LN address to test matrix.
-33
View File
@@ -1,33 +0,0 @@
# Decisions
This file records **non-obvious decisions** made during implementation.
Only write here when:
- a tradeoff was made
- multiple options existed
- a decision affects future work
Do not log:
- routine steps
- mechanical changes
- obvious refactors
---
## Decision Log
### YYYY-MM-DD — Short title
**Context**
Brief description of the situation.
**Decision**
What was chosen.
**Rationale**
Why this option was selected.
**Consequences**
Expected impact or follow-up considerations.
-27
View File
@@ -1,27 +0,0 @@
# Task Plan — FEAT-XXX <short name>
This file is the working memory for this change.
Rules:
- Every code change must map to a task below.
- Tasks must be checked when completed.
- If the spec is unclear or incorrect, stop and report a Spec Issue.
## Goal
<One sentence: what this task accomplishes>
## Constraints
- Follow the feature spec
- Do not modify foundation specs
- Respect invariants and quality bar
## Tasks
- [ ] Understand current behavior
- [ ] Implement required changes
- [ ] Handle failure and edge cases
- [ ] Update tests
- [ ] Validate against test matrix
-35
View File
@@ -1,35 +0,0 @@
# Test Matrix
This file describes **how behavior is validated** for this change.
Focus on:
- observable behavior
- edge cases
- failure modes
Do not list:
- trivial happy paths only
- tests that merely mirror the implementation
---
## Scope
Briefly describe what behavior this change introduces or modifies.
---
## Behavioral Coverage
| Scenario | Expected Behavior | Test Type | Location |
| -------- | ----------------- | --------- | -------- |
| | | | |
---
## Notes
- Prefer fewer, high-signal tests over broad but shallow coverage.
- If a scenario is intentionally untested, state why.