Initial commit

This commit is contained in:
2025-11-19 22:13:05 +01:00
commit df76a89c1b
7 changed files with 887 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
---
name: OpenSpec: Apply
description: Implement an approved OpenSpec change and keep tasks in sync.
category: OpenSpec
tags: [openspec, apply]
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
**Steps**
Track these steps as TODOs and complete them one by one.
1. Read `changes/<id>/proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria.
2. Work through tasks sequentially, keeping edits minimal and focused on the requested change.
3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished.
4. Update the checklist after all work is done so each task is marked `- [x]` and reflects reality.
5. Reference `openspec list` or `openspec show <item>` when additional context is required.
**Reference**
- Use `openspec show <id> --json --deltas-only` if you need additional context from the proposal while implementing.
<!-- OPENSPEC:END -->
+27
View File
@@ -0,0 +1,27 @@
---
name: OpenSpec: Archive
description: Archive a deployed OpenSpec change and update specs.
category: OpenSpec
tags: [openspec, archive]
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
**Steps**
1. Determine the change ID to archive:
- If this prompt already includes a specific change ID (for example inside a `<ChangeId>` block populated by slash-command arguments), use that value after trimming whitespace.
- If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends.
- Otherwise, review the conversation, run `openspec list`, and ask the user which change to archive; wait for a confirmed change ID before proceeding.
- If you still cannot identify a single change ID, stop and tell the user you cannot archive anything yet.
2. Validate the change ID by running `openspec list` (or `openspec show <id>`) and stop if the change is missing, already archived, or otherwise not ready to archive.
3. Run `openspec archive <id> --yes` so the CLI moves the change and applies spec updates without prompts (use `--skip-specs` only for tooling-only work).
4. Review the command output to confirm the target specs were updated and the change landed in `changes/archive/`.
5. Validate with `openspec validate --strict` and inspect with `openspec show <id>` if anything looks off.
**Reference**
- Use `openspec list` to confirm change IDs before archiving.
- Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off.
<!-- OPENSPEC:END -->
+27
View File
@@ -0,0 +1,27 @@
---
name: OpenSpec: Proposal
description: Scaffold a new OpenSpec change and validate strictly.
category: OpenSpec
tags: [openspec, change]
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
- Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
**Steps**
1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`.
3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
4. Capture architectural reasoning in `design.md` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
5. Draft spec deltas in `changes/<id>/specs/<capability>/spec.md` (one folder per capability) using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement and cross-reference related capabilities when relevant.
6. Draft `tasks.md` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
7. Validate with `openspec validate <id> --strict` and resolve every issue before sharing the proposal.
**Reference**
- Use `openspec show <id> --json --deltas-only` or `openspec show <spec> --type spec` to inspect details when validation fails.
- Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones.
- Explore the codebase with `rg <keyword>`, `ls`, or direct file reads so proposals align with current implementation realities.
<!-- OPENSPEC:END -->
+18
View File
@@ -0,0 +1,18 @@
<!-- OPENSPEC:START -->
# OpenSpec Instructions
These instructions are for AI assistants working in this project.
Always open `@/openspec/AGENTS.md` when the request:
- Mentions planning or proposals (words like proposal, spec, change, plan)
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
- Sounds ambiguous and you need the authoritative spec before coding
Use `@/openspec/AGENTS.md` to learn:
- How to create and apply change proposals
- Spec format and conventions
- Project structure and guidelines
Keep this managed block so 'openspec update' can refresh the instructions.
<!-- OPENSPEC:END -->
+18
View File
@@ -0,0 +1,18 @@
<!-- OPENSPEC:START -->
# OpenSpec Instructions
These instructions are for AI assistants working in this project.
Always open `@/openspec/AGENTS.md` when the request:
- Mentions planning or proposals (words like proposal, spec, change, plan)
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
- Sounds ambiguous and you need the authoritative spec before coding
Use `@/openspec/AGENTS.md` to learn:
- How to create and apply change proposals
- Spec format and conventions
- Project structure and guidelines
Keep this managed block so 'openspec update' can refresh the instructions.
<!-- OPENSPEC:END -->
+454
View File
@@ -0,0 +1,454 @@
# OpenSpec Instructions
Instructions for AI coding assistants using OpenSpec for spec-driven development.
## TL;DR Quick Checklist
- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)
- Decide scope: new capability vs modify existing capability
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
- Validate: `openspec validate [change-id] --strict` and fix issues
- Request approval: Do not start implementation until proposal is approved
## Three-Stage Workflow
### Stage 1: Creating Changes
Create proposal when you need to:
- Add features or functionality
- Make breaking changes (API, schema)
- Change architecture or patterns
- Optimize performance (changes behavior)
- Update security patterns
Triggers (examples):
- "Help me create a change proposal"
- "Help me plan a change"
- "Help me create a proposal"
- "I want to create a spec proposal"
- "I want to create a spec"
Loose matching guidance:
- Contains one of: `proposal`, `change`, `spec`
- With one of: `create`, `plan`, `make`, `start`, `help`
Skip proposal for:
- Bug fixes (restore intended behavior)
- Typos, formatting, comments
- Dependency updates (non-breaking)
- Configuration changes
- Tests for existing behavior
**Workflow**
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
4. Run `openspec validate <id> --strict` and resolve any issues before sharing the proposal.
### Stage 2: Implementing Changes
Track these steps as TODOs and complete them one by one.
1. **Read proposal.md** - Understand what's being built
2. **Read design.md** (if exists) - Review technical decisions
3. **Read tasks.md** - Get implementation checklist
4. **Implement tasks sequentially** - Complete in order
5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses
6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality
7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved
### Stage 3: Archiving Changes
After deployment, create separate PR to:
- Move `changes/[name]/``changes/archive/YYYY-MM-DD-[name]/`
- Update `specs/` if capabilities changed
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
- Run `openspec validate --strict` to confirm the archived change passes checks
## Before Any Task
**Context Checklist:**
- [ ] Read relevant specs in `specs/[capability]/spec.md`
- [ ] Check pending changes in `changes/` for conflicts
- [ ] Read `openspec/project.md` for conventions
- [ ] Run `openspec list` to see active changes
- [ ] Run `openspec list --specs` to see existing capabilities
**Before Creating Specs:**
- Always check if capability already exists
- Prefer modifying existing specs over creating duplicates
- Use `openspec show [spec]` to review current state
- If request is ambiguous, ask 12 clarifying questions before scaffolding
### Search Guidance
- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)
- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)
- Show details:
- Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)
- Change: `openspec show <change-id> --json --deltas-only`
- Full-text search (use ripgrep): `rg -n "Requirement:|Scenario:" openspec/specs`
## Quick Start
### CLI Commands
```bash
# Essential commands
openspec list # List active changes
openspec list --specs # List specifications
openspec show [item] # Display change or spec
openspec validate [item] # Validate changes or specs
openspec archive <change-id> [--yes|-y] # Archive after deployment (add --yes for non-interactive runs)
# Project management
openspec init [path] # Initialize OpenSpec
openspec update [path] # Update instruction files
# Interactive mode
openspec show # Prompts for selection
openspec validate # Bulk validation mode
# Debugging
openspec show [change] --json --deltas-only
openspec validate [change] --strict
```
### Command Flags
- `--json` - Machine-readable output
- `--type change|spec` - Disambiguate items
- `--strict` - Comprehensive validation
- `--no-interactive` - Disable prompts
- `--skip-specs` - Archive without spec updates
- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)
## Directory Structure
```
openspec/
├── project.md # Project conventions
├── specs/ # Current truth - what IS built
│ └── [capability]/ # Single focused capability
│ ├── spec.md # Requirements and scenarios
│ └── design.md # Technical patterns
├── changes/ # Proposals - what SHOULD change
│ ├── [change-name]/
│ │ ├── proposal.md # Why, what, impact
│ │ ├── tasks.md # Implementation checklist
│ │ ├── design.md # Technical decisions (optional; see criteria)
│ │ └── specs/ # Delta changes
│ │ └── [capability]/
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
│ └── archive/ # Completed changes
```
## Creating Change Proposals
### Decision Tree
```
New request?
├─ Bug fix restoring spec behavior? → Fix directly
├─ Typo/format/comment? → Fix directly
├─ New feature/capability? → Create proposal
├─ Breaking change? → Create proposal
├─ Architecture change? → Create proposal
└─ Unclear? → Create proposal (safer)
```
### Proposal Structure
1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)
2. **Write proposal.md:**
```markdown
## Why
[1-2 sentences on problem/opportunity]
## What Changes
- [Bullet list of changes]
- [Mark breaking changes with **BREAKING**]
## Impact
- Affected specs: [list capabilities]
- Affected code: [key files/systems]
```
3. **Create spec deltas:** `specs/[capability]/spec.md`
```markdown
## ADDED Requirements
### Requirement: New Feature
The system SHALL provide...
#### Scenario: Success case
- **WHEN** user performs action
- **THEN** expected result
## MODIFIED Requirements
### Requirement: Existing Feature
[Complete modified requirement]
## REMOVED Requirements
### Requirement: Old Feature
**Reason**: [Why removing]
**Migration**: [How to handle]
```
If multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.
4. **Create tasks.md:**
```markdown
## 1. Implementation
- [ ] 1.1 Create database schema
- [ ] 1.2 Implement API endpoint
- [ ] 1.3 Add frontend component
- [ ] 1.4 Write tests
```
5. **Create design.md when needed:**
Create `design.md` if any of the following apply; otherwise omit it:
- Cross-cutting change (multiple services/modules) or a new architectural pattern
- New external dependency or significant data model changes
- Security, performance, or migration complexity
- Ambiguity that benefits from technical decisions before coding
Minimal `design.md` skeleton:
```markdown
## Context
[Background, constraints, stakeholders]
## Goals / Non-Goals
- Goals: [...]
- Non-Goals: [...]
## Decisions
- Decision: [What and why]
- Alternatives considered: [Options + rationale]
## Risks / Trade-offs
- [Risk] → Mitigation
## Migration Plan
[Steps, rollback]
## Open Questions
- [...]
```
## Spec File Format
### Critical: Scenario Formatting
**CORRECT** (use #### headers):
```markdown
#### Scenario: User login success
- **WHEN** valid credentials provided
- **THEN** return JWT token
```
**WRONG** (don't use bullets or bold):
```markdown
- **Scenario: User login** ❌
**Scenario**: User login ❌
### Scenario: User login ❌
```
Every requirement MUST have at least one scenario.
### Requirement Wording
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
### Delta Operations
- `## ADDED Requirements` - New capabilities
- `## MODIFIED Requirements` - Changed behavior
- `## REMOVED Requirements` - Deprecated features
- `## RENAMED Requirements` - Name changes
Headers matched with `trim(header)` - whitespace ignored.
#### When to use ADDED vs MODIFIED
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you arent explicitly changing the existing requirement, add a new requirement under ADDED instead.
Authoring a MODIFIED requirement correctly:
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
Example for RENAMED:
```markdown
## RENAMED Requirements
- FROM: `### Requirement: Login`
- TO: `### Requirement: User Authentication`
```
## Troubleshooting
### Common Errors
**"Change must have at least one delta"**
- Check `changes/[name]/specs/` exists with .md files
- Verify files have operation prefixes (## ADDED Requirements)
**"Requirement must have at least one scenario"**
- Check scenarios use `#### Scenario:` format (4 hashtags)
- Don't use bullet points or bold for scenario headers
**Silent scenario parsing failures**
- Exact format required: `#### Scenario: Name`
- Debug with: `openspec show [change] --json --deltas-only`
### Validation Tips
```bash
# Always use strict mode for comprehensive checks
openspec validate [change] --strict
# Debug delta parsing
openspec show [change] --json | jq '.deltas'
# Check specific requirement
openspec show [spec] --json -r 1
```
## Happy Path Script
```bash
# 1) Explore current state
openspec spec list --long
openspec list
# Optional full-text search:
# rg -n "Requirement:|Scenario:" openspec/specs
# rg -n "^#|Requirement:" openspec/changes
# 2) Choose change id and scaffold
CHANGE=add-two-factor-auth
mkdir -p openspec/changes/$CHANGE/{specs/auth}
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md
# 3) Add deltas (example)
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
## ADDED Requirements
### Requirement: Two-Factor Authentication
Users MUST provide a second factor during login.
#### Scenario: OTP required
- **WHEN** valid credentials are provided
- **THEN** an OTP challenge is required
EOF
# 4) Validate
openspec validate $CHANGE --strict
```
## Multi-Capability Example
```
openspec/changes/add-2fa-notify/
├── proposal.md
├── tasks.md
└── specs/
├── auth/
│ └── spec.md # ADDED: Two-Factor Authentication
└── notifications/
└── spec.md # ADDED: OTP email notification
```
auth/spec.md
```markdown
## ADDED Requirements
### Requirement: Two-Factor Authentication
...
```
notifications/spec.md
```markdown
## ADDED Requirements
### Requirement: OTP Email Notification
...
```
## Best Practices
### Simplicity First
- Default to <100 lines of new code
- Single-file implementations until proven insufficient
- Avoid frameworks without clear justification
- Choose boring, proven patterns
### Complexity Triggers
Only add complexity with:
- Performance data showing current solution too slow
- Concrete scale requirements (>1000 users, >100MB data)
- Multiple proven use cases requiring abstraction
### Clear References
- Use `file.ts:42` format for code locations
- Reference specs as `specs/auth/spec.md`
- Link related changes and PRs
### Capability Naming
- Use verb-noun: `user-auth`, `payment-capture`
- Single purpose per capability
- 10-minute understandability rule
- Split if description needs "AND"
### Change ID Naming
- Use kebab-case, short and descriptive: `add-two-factor-auth`
- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`
- Ensure uniqueness; if taken, append `-2`, `-3`, etc.
## Tool Selection Guide
| Task | Tool | Why |
|------|------|-----|
| Find files by pattern | Glob | Fast pattern matching |
| Search code content | Grep | Optimized regex search |
| Read specific files | Read | Direct file access |
| Explore unknown scope | Task | Multi-step investigation |
## Error Recovery
### Change Conflicts
1. Run `openspec list` to see active changes
2. Check for overlapping specs
3. Coordinate with change owners
4. Consider combining proposals
### Validation Failures
1. Run with `--strict` flag
2. Check JSON output for details
3. Verify spec file format
4. Ensure scenarios properly formatted
### Missing Context
1. Read project.md first
2. Check related specs
3. Review recent archives
4. Ask for clarification
## Quick Reference
### Stage Indicators
- `changes/` - Proposed, not yet built
- `specs/` - Built and deployed
- `archive/` - Completed changes
### File Purposes
- `proposal.md` - Why and what
- `tasks.md` - Implementation steps
- `design.md` - Technical decisions
- `spec.md` - Requirements and behavior
### CLI Essentials
```bash
openspec list # What's in progress?
openspec show [item] # View details
openspec validate --strict # Is it correct?
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
```
Remember: Specs are truth. Changes are proposals. Keep them in sync.
+320
View File
@@ -0,0 +1,320 @@
# Project Context
## Purpose
This project provides a toolset for managing members of a non-profit society. It consists of a graphql api. A simple MCP server that connects to the graphql api provides the tools for AI agents to manage the society administration.
## Tech Stack
### Core Framework
- **Python 3.11+** - Primary language
- **uv** - Fast Python package and project manager
- **FastAPI** - Async web framework and HTTP layer
- **Strawberry GraphQL** - Schema-first GraphQL with Python type hints
### Data Layer
- **SQLAlchemy 2.0** - ORM with modern async support
- **Alembic** - Database migration management
- **SQLite** - Development and testing database
- **PostgreSQL** - Production database (future)
### Integration Layer
- **MCP Server (Python)** - AI assistant integration
- **httpx** - HTTP client for GraphQL queries
## Project Conventions
### Code Style
#### Formatting
- **Black** - Code formatting (line length: 88)
- **isort** - Import sorting (Black-compatible profile)
- **ruff** - Fast linting and additional formatting
#### Type Hints
- Use type hints extensively for all function signatures
- Leverage Strawberry's type system for GraphQL schema
- SQLAlchemy models should use Mapped[] type annotations
- Prefer explicit types over Any where possible
#### Naming Conventions
- **Files**: lowercase_with_underscores.py
- **Classes**: PascalCase (e.g., MemberModel, MemberType)
- **Functions/Variables**: snake_case (e.g., get_member, member_id)
- **Constants**: UPPER_SNAKE_CASE (e.g., MAX_MEMBERS)
- **GraphQL Types**: PascalCase matching domain entities
- **GraphQL Fields**: camelCase (Strawberry default)
#### Code Organization
- Keep modules focused and single-purpose
- Prefer flat structure until complexity requires hierarchy
- Group related functionality (models, resolvers, services)
- Avoid circular dependencies through clear layering
#### Dependency Management
- **uv** for all Python package management
- `uv pip install <package>` - Install packages
- `uv pip compile requirements.in -o requirements.txt` - Lock dependencies
- `uv venv` - Create virtual environments
- `uv run` - Run commands in virtual environment
- **pyproject.toml** - Project metadata and dependencies
- **requirements.txt** or **uv.lock** - Locked dependency versions
- Pin major versions, allow minor/patch updates
- Regular dependency updates for security patches
- Separate dev dependencies from production dependencies
#### Documentation
- **README.md** - Primary project documentation
- Project overview and purpose
- Quick start guide
- Installation instructions (uv setup)
- Basic usage examples
- Links to OpenSpec documentation
- Contributing guidelines
- License information
- Keep README.md up-to-date with major changes
- README is the entry point for new developers and AI assistants
- For detailed specs, refer to `openspec/` directory
### Architecture Patterns
#### Layered Architecture
```
API Layer (FastAPI + Strawberry)
Service Layer (Business Logic)
Data Layer (SQLAlchemy Models)
Database (SQLite/PostgreSQL)
```
#### GraphQL Schema Design
- **Type hints as schema**: Use Python types to define GraphQL schema
- **Simple, consistent filters**: Prefer explicit arguments over complex nested filters
- Good: `members(status: MemberStatus, joinedAfter: Date)`
- Avoid: `members(where: {and: [{status: {eq: ACTIVE}}]})`
- **Introspection-friendly**: Design schema for AI consumption via introspection
- **Field descriptions**: Document all fields for self-describing API
#### Database Patterns
- **Database-agnostic code**: Write portable SQLAlchemy code for SQLite/PostgreSQL
- **Connection string switching**: Same code works with different databases
- **Alembic migrations**: All schema changes via migrations
- **Async operations**: Use async SQLAlchemy patterns where beneficial
#### Authentication
- **JWT tokens** at HTTP layer (FastAPI middleware)
- **Service account** for MCP server (admin privileges)
- GraphQL resolvers assume authenticated context
- Future: User-specific MCP instances
#### Simplicity Principles
- Default to single-file implementations (<100 lines)
- Avoid frameworks/abstractions without clear justification
- Choose boring, proven patterns
- Add complexity only with:
- Performance data showing need
- Concrete scale requirements
- Multiple proven use cases
### Testing Strategy
#### Testing Pyramid
- **Unit Tests**: Core business logic and utilities
- **Integration Tests**: Database operations and GraphQL resolvers
- **E2E Tests**: Complete GraphQL query/mutation flows
- **MCP Tests**: Tool definitions and API integration
#### Framework & Tools
- **pytest** - Test runner with async support
- **pytest-asyncio** - Async test support
- **httpx** - Test client for FastAPI/GraphQL
- **SQLAlchemy test fixtures** - In-memory SQLite for fast tests
#### Test Organization
```
tests/
├── unit/ # Pure logic tests
├── integration/ # Database + resolver tests
├── e2e/ # Full API tests
└── mcp/ # MCP server tests
```
#### Coverage Goals
- Aim for >80% coverage on business logic
- 100% coverage on critical paths (payments, memberships)
- Focus on behavior, not implementation details
- Test error cases and edge conditions
#### Testing Conventions
- One test file per module: `test_<module>.py`
- Descriptive test names: `test_member_creation_with_valid_data`
- Use fixtures for common setup (db session, test data)
- Clean database state between tests
- Mock external services (future: email, payment providers)
### Git Workflow
#### Branching Strategy with Worktrees
- **main** - Production-ready code (primary worktree)
- **Feature branches** - `feature/<description>` or `<change-id>` from OpenSpec
- **Hotfix branches** - `hotfix/<issue>`
- Use **git worktrees** for parallel development:
- Each branch gets its own directory
- Work on multiple features simultaneously
- No need to stash or switch contexts
- Example: `git worktree add ../clubber-feature-payments feature/payments`
- Keep branches short-lived (1-3 days max)
- Remove worktree and delete branch after merge
#### Commit Conventions
- Use conventional commits format:
- `feat:` - New features
- `fix:` - Bug fixes
- `refactor:` - Code refactoring
- `docs:` - Documentation changes
- `test:` - Test additions/changes
- `chore:` - Build, config, dependencies
- Examples:
- `feat: add member payment tracking`
- `fix: correct member status calculation`
- `refactor: simplify GraphQL resolver logic`
#### Pull Request Process
1. Create worktree for feature branch from main
2. Implement changes with tests in worktree
3. Run tests and linting locally
4. Create PR with clear description
5. Link to OpenSpec change if applicable
6. Review and address feedback
7. Squash merge to main
8. Remove worktree: `git worktree remove <path>`
#### Pre-commit Checks
- Black formatting
- isort import sorting
- ruff linting
- Type checking (mypy)
- Tests pass
## Domain Context
### Non-Profit Society Management
This system manages members of a registered non-profit society (Verein/club).
#### Core Entities
- **Members**: Individuals who belong to the society
- Active, inactive, honorary members
- Membership start/end dates
- Contact information
- Payment status
- **Memberships**: The relationship between members and the society
- Annual/lifetime memberships
- Membership fees
- Payment tracking
- Status changes over time
- **Payments**: Financial transactions
- Membership fees
- Donations
- Event fees
- Payment methods and tracking
- **Events** (future): Society activities and meetings
- Member participation
- Registration and attendance
#### Business Rules
- Members must have valid contact information
- Membership status changes based on payment history
- Privacy considerations for member data (GDPR compliance)
- Financial records must be auditable
- Society governance (board members, voting rights)
#### Common Operations
- Add new members
- Track membership payments
- Generate membership lists
- Send payment reminders
- Export reports for annual meetings
- Member communication
## Important Constraints
### Technical Constraints
- **Database portability**: Code must work with both SQLite and PostgreSQL
- **Async-first**: Use async patterns for scalability
- **Single-server deployment**: No distributed systems initially
- **Limited resources**: Optimize for small-scale (<1000 members initially)
- **Python-only**: Keep the stack simple with one primary language
### Business Constraints
- **Data privacy**: GDPR compliance for EU member data
- Right to access (export member data)
- Right to deletion (full data removal)
- Consent tracking for communications
- Data minimization principles
- **Audit trail**: Financial transactions must be traceable
- **Offline capability**: Export functionality for offline access to critical data
- **Non-profit requirements**: Transparent financial reporting
### AI Integration Constraints
- **Schema introspection**: GraphQL schema must be AI-readable
- **Simple query patterns**: Avoid complex nested filters
- **Service account authentication**: MCP server uses admin credentials
- **Rate limiting**: Protect against excessive API usage (future)
- **Query complexity limits**: Prevent resource-intensive operations
### Development Constraints
- **Simplicity first**: Avoid premature optimization
- **Incremental delivery**: Start with core features, expand gradually
- **Solo developer**: Optimize for maintainability over cleverness
- **Open source ready**: Clean, documented code for potential future contributors
## External Dependencies
### Current Dependencies
- **Python Package Index (PyPI)**: Package registry (managed via uv)
- strawberry-graphql
- fastapi
- sqlalchemy
- alembic
- httpx
- pytest and testing tools
- **uv**: Fast package installer and resolver
### Future/Planned Dependencies
- **Email Service** (future): Transactional emails
- Payment reminders
- Membership notifications
- Board communications
- Consider: SMTP, SendGrid, or similar
- **Payment Processing** (future): Online payment collection
- Bank transfers (EU SEPA)
- Credit card processing
- Payment reconciliation
- Consider: Stripe, PayPal, or EU-specific providers
- **Document Storage** (future): Member documents and files
- Meeting minutes
- Member applications
- Financial reports
- Consider: Local filesystem, S3-compatible storage
- **Backup Service** (future): Automated backups
- Database backups
- Document backups
- Disaster recovery
### MCP Integration
- **Claude AI API**: For AI assistant features via MCP
- **MCP Protocol**: Standard protocol for AI tool integration
- **GraphQL Introspection**: Self-documenting API for AI consumption
### Development Tools
- **Git**: Version control
- **GitHub** (optional): Code hosting and collaboration
- **Docker** (optional): Containerization for deployment
- **CI/CD** (future): Automated testing and deployment