- Kotlin 42.3%
- Go 33.2%
- TypeScript 20.7%
- CSS 2.9%
- Makefile 0.3%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
check / commits (pull_request) Successful in 20s
check / go (pull_request) Successful in 2m54s
check / report (pull_request) Successful in 4s
android / build (pull_request) Successful in 7m59s
android / report (pull_request) Successful in 5s
check / web (pull_request) Successful in 4m30s
check / commits (push) Successful in 32s
check / go (push) Successful in 3m0s
check / report (push) Has been skipped
check / web (push) Successful in 6m54s
android / build (push) Successful in 7m29s
android / report (push) Has been skipped
tag / tag (push) Successful in 5m8s
release / docs (push) Successful in 1m19s
release / binaries (push) Successful in 1m59s
release / android (push) Successful in 4m59s
release / image (push) Successful in 3m57s
release / module (push) Successful in 28s
release / manifests (push) Successful in 29s
release / release (push) Successful in 15s
Three celebration defects on the phone (issue #283). A sub-job ticked inside the job sheet handed the moment to its board, and the board drew the confetti on its own canvas — under the sheet, which Material hosts in a separate window. The calendar page opened the job sheet with no celebrate hook at all, so a points tick from a calendar row's sheet never burst. And the wide calendar (week, month, the day sheet) set its confetti origin but only the phone branch composed the overlay, so those bursts never drew either. ConfettiOverlay now composes into a transparent, touch-through window of its own (a Compose Dialog with the dim, focus and touch flags cleared), so it sits above whichever sheet or dialog fired it — the web's fixed-position canvas, which the DOM stacks over the sheet for free. Origins move to screen coordinates so a burst fired from a sheet's window lands where the tap was. The calendar page wires onCelebrate like the Jobs and Today boards, and hosts one overlay for every view. Verified on the emulator against the e2e server: ticking a points sub-job inside the job sheet raises a third app window on top with NOT_FOCUSABLE NOT_TOUCHABLE and no dim, above the sheet's window, and it retires when the burst ends. Two emulator gotchas met on the way: the seed's admin has reduce_motion on, and an AVD with animator_duration_scale 0 reads as system reduce-motion — both skip the confetti by design. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
| .dagger | ||
| .gitea/workflows | ||
| .github | ||
| android | ||
| cmd | ||
| conformance | ||
| deploy | ||
| design | ||
| docs | ||
| docsite | ||
| gen | ||
| internal | ||
| pkg | ||
| proto/api/core/v1 | ||
| scripts | ||
| tools | ||
| web | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| buf.gen.android.yaml | ||
| buf.gen.ts.yaml | ||
| buf.gen.yaml | ||
| buf.yaml | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| cosign.pub | ||
| dagger.json | ||
| devbox.json | ||
| devbox.lock | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| LOCAL_DEVELOPMENT.md | ||
| Makefile | ||
| README.md | ||
Eagraí Clainne
Family Organization System - A gRPC-based application for organizing family activities, events, items, and rewards.
Overview
Eagraí Clainne is a Go-based backend service that provides APIs for managing family organization tasks including:
- User Management: Create and manage family member accounts with authentication
- Events: Schedule and coordinate family events with participant tracking
- Items: Track family items and assign them to users with deadlines
- Rewards: Create reward systems and allow users to claim rewards
It serves a bundled web frontend and a native Android client, and also speaks the Model Context Protocol for assistant clients.
The service is built using:
- Connect RPC (gRPC-compatible protocol)
- Protocol Buffers for API definitions
- SQLite by default, PostgreSQL optional for data persistence, selected
by
EAG_DB_DRIVER(see ADR-0021) - JWT authentication with role-based access control (RBAC)
Client Library
A Go client library is available in pkg/client/ for building CLI tools and applications:
import "eagraiclainne.ie/pkg/client"
c, _ := client.New("http://localhost:8080", nil)
loginResp, _ := c.Users.Login(ctx, "user@example.com", "password")
c.SetAuthToken(loginResp.Token)
event, _ := c.Events.Create(ctx, &client.CreateEventParams{...})
See pkg/client/README.md for full documentation and examples.
Architecture
The project follows a clean architecture with clear separation of concerns:
cmd/server/ - Server entry point and configuration
internal/
auth/ - Authentication, JWT handling, RBAC, and interceptors
database/ - Database abstraction layer with generic table operations
services/ - Business logic for each domain (user, event, item, reward)
proto/api/core/v1/ - Protocol Buffer API definitions
gen/go/api/core/v1/ - Generated Go code from Protocol Buffers
Development Setup
📖 For detailed local development instructions, see LOCAL_DEVELOPMENT.md
Quick Start
Local development runs on a kind cluster (see deploy/README.md):
# One-time: bootstrap the kind cluster + local registry
make cluster-up
# Build the image and deploy database, observability and app
make deploy
# Fresh database only: seed a family to log in with
make seed-family
The app is then available at http://localhost:8080.
Before committing, run:
make check # fmt, vet, lint, test, and web/android i18n checks
Alternative: Using Devbox
This project also supports devbox for reproducible development environments:
# Install devbox
curl -fsSL https://get.jetpack.io/devbox | bash
# Enter devbox shell
devbox shell
# Follow the Quick Start steps above
Development Commands
Building
go build ./... # Build all packages
go build -o ./bin/server ./cmd/server # Build server executable
Testing
go test ./... # Run all tests
go test -v ./internal/database/ -run TestName # Run specific test
Code Quality
go fmt ./... # Format code
go vet ./... # Vet code for errors
golangci-lint run # Run linter
Protocol Buffers
buf generate # Generate Go code from .proto files
buf lint # Lint protocol buffer definitions
Environment Variables
Configuration is read via viper with the EAG_ prefix, so a db-driver
flag maps to the EAG_DB_DRIVER environment variable. The database ones:
| Variable | Default | Description |
|---|---|---|
| EAG_DB_DRIVER | sqlite | Storage engine (sqlite or postgres) |
| EAG_DB_PATH | eagraiclainne.db | SQLite database file (driver sqlite) |
| EAG_DB_HOST | localhost | Database host (driver postgres) |
| EAG_DB_PORT | 5432 | Database port (driver postgres) |
| EAG_DB_USER | postgres | Database user (driver postgres) |
| EAG_DB_PASSWORD | (empty) | Database password (driver postgres) |
| EAG_DB_NAME | eagraiclainne | Database name (driver postgres) |
| EAG_DB_SSLMODE | disable | SSL mode (driver postgres) |
API Services
The following Connect RPC services are available:
- UserService: User registration, login, profile management
- EventService: Event creation, updates, user participation
- ItemService: Item tracking, user assignment, deadline management
- ItemListService: Grouping of items into lists
- RewardService: Reward creation, claiming, user reward tracking
- MealService / MealRotaService: Meal planning and the cooking rota
- ApiKeyService: Admin-managed machine credentials (API keys)
- SystemService: Data export, import and restore
- WebhookService: Outbound signed event deliveries
MCP Endpoint
The server speaks the Model Context Protocol at /mcp (streamable HTTP), so
Claude and other MCP clients can work the family data with the tools
list_items, add_item, complete_item, list_events and add_event.
Authenticate with an API key (mint one in the web Admin → Keys panel, or with
eagraiclainne apikey create):
claude mcp add eagraiclainne --transport http http://localhost:8080/mcp \
--header "Authorization: Bearer <api-key-token>"
A personal key acts as one member. A standalone key (for a shared device such
as Home Assistant) names who actually acted per call via acting_user,
honoured only against its admin-set allowlist. See
ADR-0016.
Authentication & Authorization
The service implements JWT-based authentication with RBAC:
- Users authenticate via the
LoginRPC - JWT tokens are required for most operations (via Authorization header)
- Roles determine access permissions (Admin, Member, Child, Guest)
- Admin-managed API keys serve machine clients; the key record is the authority (per-key revocation, acting-user allowlists) — see ADR-0016
- See ADR-0007, ADR-0008, and ADR-0009 for details
ADR Process
For significant changes, we record Architecture Decision Records (ADRs). ADRs document design decisions and their rationale for:
- New authentication/authorization systems
- Database schema changes
- New API services or significant endpoint additions
- Major refactoring affecting multiple packages
- Changes to core architecture or design patterns
ADRs are stored in docs/adr/<nnnn>-<topic>.md and should include sections for context, decision,
consequences, and alternatives considered. Existing ADRs are in docs/adr/.
Database Schema
The database schema is defined in internal/database/schema.sql (PostgreSQL)
and internal/database/schema_sqlite.sql (SQLite), applied on boot, and
includes tables for:
- Users and authentication
- Events and event participants
- Items and item assignments
- Rewards and reward claims
The database layer provides generic, type-safe operations using Go generics.
Contributing
See CONTRIBUTING.md for how to get access, build, commit,
and submit a change. In short: follow the project conventions, write tests for
new functionality, record an ADR for significant architectural changes, and
make sure make check passes before submitting.
License
See LICENSE file for details.