# Clubber A toolset for managing members of non-profit societies (Vereine) with AI-powered administration. ## Overview Clubber provides a GraphQL API for member management combined with an MCP (Model Context Protocol) server that enables AI assistants to help with society administration tasks. **Current Status**: Early development - OpenSpec documentation and project structure in place. ## Architecture The system consists of two main components: 1. **GraphQL API** - Core backend for member data management - Built with FastAPI and Strawberry GraphQL - Database-agnostic design (SQLite for development, PostgreSQL for production) - SQLAlchemy 2.0 ORM with async support 2. **MCP Server** - AI assistant integration layer - Connects to the GraphQL API - Provides tools for AI agents to manage society operations - Service account authentication ## Tech Stack - **Python 3.11+** - Primary language - **uv** - Fast package and project manager - **FastAPI** - Async web framework - **Strawberry GraphQL** - Type-safe GraphQL with Python type hints - **SQLAlchemy 2.0** - Database ORM - **Alembic** - Database migrations ## Project Structure ``` clubber/ ├── openspec/ # Specification-driven development │ ├── project.md # Project conventions and context │ ├── specs/ # Current specifications │ └── changes/ # Change proposals ├── CLAUDE.md # AI assistant instructions └── README.md # This file ``` ## Getting Started ### Prerequisites - Python 3.11 or higher - [uv](https://github.com/astral-sh/uv) package manager ### Setup ```bash # Clone the repository git clone ssh://git@codeberg.org/gurix/clubber.git cd clubber # Install uv if not already installed curl -LsSf https://astral.sh/uv/install.sh | sh # Install dependencies uv sync # Run database migrations uv run alembic upgrade head # (Optional) Seed the database with sample data PYTHONPATH=. uv run python scripts/seed.py ``` ### Running the Server Start the development server: ```bash uv run uvicorn src.main:app --host 127.0.0.1 --port 8000 --reload ``` The `--reload` flag enables auto-restart when code changes are detected. Access the API: - **GraphQL Playground**: http://127.0.0.1:8000/graphql - **API Documentation**: http://127.0.0.1:8000/docs - **Root Endpoint**: http://127.0.0.1:8000/ ## API Usage Examples ### Member Data Model Members have the following fields: - `firstName` (required) - Member's first name - `lastName` (optional) - Member's last name - `street` (optional) - Street address - `apartmentNumber` (optional) - Apartment or unit number - `zip` (optional) - Postal code - `city` (optional) - City - `country` (optional) - Country - `email` (optional) - Email address (validated when provided) - `phone` (optional) - Phone number in E.164 format (validated when provided) **Key Feature**: Only `firstName` is required. All other fields are optional and can be populated later. Email and phone are validated only when provided (not when null/empty). ### GraphQL Queries List all members: ```graphql { members { id firstName lastName email phone city } } ``` Get a single member: ```graphql { member(id: 1) { id firstName lastName email street city country } } ``` ### GraphQL Mutations Create a member (minimal - only firstName): ```graphql mutation { createMember(input: { firstName: "Alice" }) { id firstName email } } ``` Create a member with all fields: ```graphql mutation { createMember(input: { firstName: "Bob" lastName: "Johnson" street: "123 Main St" apartmentNumber: "4B" zip: "12345" city: "Springfield" country: "USA" email: "bob.johnson@example.com" phone: "+14155551234" }) { id firstName lastName email phone } } ``` Update a member: ```graphql mutation { updateMember(input: { id: 1 email: "updated@example.com" phone: "+14155559999" }) { id firstName email phone } } ``` Delete a member: ```graphql mutation { deleteMember(id: 2) } ``` ### Using curl Query members: ```bash curl -X POST http://127.0.0.1:8000/graphql \ -H "Content-Type: application/json" \ -d '{"query": "{ members { id firstName lastName email } }"}' ``` Create a member: ```bash curl -X POST http://127.0.0.1:8000/graphql \ -H "Content-Type: application/json" \ -d '{"query": "mutation { createMember(input: { firstName: \"Charlie\" }) { id firstName } }"}' ``` ## Development Workflow This project uses [OpenSpec](https://openspec.dev) for specification-driven development: 1. **Review existing specs** in `openspec/specs/` 2. **Create change proposals** in `openspec/changes/` before implementing features 3. **Validate proposals** with `openspec validate --strict` 4. **Implement changes** following the proposal 5. **Archive completed changes** after deployment See `openspec/AGENTS.md` for detailed workflow instructions. ### Working with Git Worktrees We use git worktrees for parallel development: ```bash # Create a worktree for a feature branch git worktree add ../clubber-feature-name feature/feature-name # Work in the worktree cd ../clubber-feature-name # Remove worktree after merge git worktree remove ../clubber-feature-name ``` ## Contributing 1. Read `openspec/project.md` for project conventions 2. For new features, create an OpenSpec proposal first 3. Follow the coding style (Black, isort, ruff) 4. Write tests for new functionality 5. Use conventional commits (`feat:`, `fix:`, `docs:`, etc.) ## License The MIT License ## Contact Markus Graf - [info@markusgraf.ch](mailto:info@markusgraf.ch) ## Acknowledgments Built with support from: - [Strawberry GraphQL](https://strawberry.rocks) - [FastAPI](https://fastapi.tiangolo.com) - [OpenSpec](https://openspec.dev)