Migrate project artifacts to spec-kit format

- Move cross-cutting docs (personas, design system, implementation phases,
  Ideen.md) to .specify/memory/
- Move cross-cutting research and plans to .specify/memory/research/ and
  .specify/memory/plans/
- Extract 5 setup tasks from spec/setup-tasks.md into individual
  specs/001-005/spec.md files with spec-kit template format
- Extract 20 user stories from spec/userstories.md into individual
  specs/006-026/spec.md files with spec-kit template format
- Relocate feature-specific research and plan docs into specs/[feature]/
- Add spec-kit constitution, templates, scripts, and slash commands
- Slim down CLAUDE.md to Claude-Code-specific config, delegate principles
  to .specify/memory/constitution.md
- Update ralph.sh with stream-json output and per-iteration logging
- Delete old spec/ and docs/agents/ directories
- Gitignore Ralph iteration JSONL logs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 20:19:41 +01:00
parent 0b2b84dafc
commit 6aeb4b8bca
83 changed files with 6486 additions and 660 deletions

View File

@@ -0,0 +1,88 @@
# Feature Specification: Limit Active Events Per Instance
**Feature**: `019-instance-limit`
**Created**: 2026-03-06
**Status**: Draft
**Source**: Migrated from spec/userstories.md (US-13)
## User Scenarios & Testing
### User Story 1 - Enforce Configured Event Cap on Creation (Priority: P1)
As a self-hoster, I want to configure a maximum number of simultaneously active events via a server environment variable, so that I can prevent storage exhaustion and limit potential abuse on my instance without modifying code.
**Why this priority**: The event cap is the primary deliverable of this story — without it, there is no feature. All other scenarios are edge cases of this core enforcement behavior.
**Independent Test**: Can be fully tested by configuring `MAX_ACTIVE_EVENTS=1`, creating one event, then attempting to create a second — the second creation should be rejected with a clear error.
**Acceptance Scenarios**:
1. **Given** the server is configured with `MAX_ACTIVE_EVENTS=3` and 3 non-expired events exist, **When** a user submits the event creation form, **Then** the server rejects the request with a clear error indicating the instance is at capacity, and the frontend surfaces this error on the creation form — not as a silent failure.
2. **Given** the server is configured with `MAX_ACTIVE_EVENTS=3` and 2 non-expired events exist, **When** a user submits the event creation form, **Then** the request succeeds and the new event is created normally.
3. **Given** the server is configured with `MAX_ACTIVE_EVENTS=3` and 3 non-expired events exist, but 1 is past its expiry date (awaiting cleanup), **When** a user submits the event creation form, **Then** the request succeeds — expired events do not count toward the limit.
---
### User Story 2 - No Limit When Variable Is Unset (Priority: P2)
As a self-hoster running a personal or trusted-group instance, I want no event limit applied by default, so that I do not need to configure anything to run the app normally.
**Why this priority**: The default behavior (unlimited) must be safe and require no configuration. Self-hosters who do not need a cap should not have to think about this setting.
**Independent Test**: Can be fully tested by starting the server without `MAX_ACTIVE_EVENTS` set and verifying that multiple events can be created without rejection.
**Acceptance Scenarios**:
1. **Given** the server has no `MAX_ACTIVE_EVENTS` environment variable set, **When** any number of events are created, **Then** no capacity error is returned — event creation is unlimited.
2. **Given** the server has `MAX_ACTIVE_EVENTS` set to an empty string, **When** events are created, **Then** no capacity error is returned — an empty value is treated the same as unset.
---
### User Story 3 - Cap Is Enforced Server-Side Only (Priority: P2)
As a self-hoster, I want the event cap to be enforced exclusively on the server, so that it cannot be bypassed by a modified or malicious client.
**Why this priority**: Client-side enforcement alone would be trivially bypassable. The server is the authoritative enforcement point.
**Independent Test**: Can be fully tested by sending a direct HTTP POST to the event creation endpoint (bypassing the frontend entirely) when the cap is reached — the server must reject it.
**Acceptance Scenarios**:
1. **Given** the configured cap is reached, **When** a direct HTTP POST is made to the event creation endpoint (bypassing the frontend), **Then** the server returns an error response indicating the instance is at capacity.
2. **Given** the configured cap is reached, **When** no personal data is included in the rejection response or logs, **Then** the server returns only the rejection status — no PII is logged.
---
### Edge Cases
- What happens when `MAX_ACTIVE_EVENTS=0`? [NEEDS EXPANSION — treat as "no limit" or "reject all"? Clarify during implementation.]
- What happens when `MAX_ACTIVE_EVENTS` is set to a non-integer value? The server should fail fast at startup with a clear configuration error.
- Race condition: two concurrent creation requests when the cap is at N-1. The server must handle this atomically — one request succeeds, the other is rejected.
- Expired events that have not yet been cleaned up must not count toward the limit. The check must query only non-expired events.
## Requirements
### Functional Requirements
- **FR-001**: The server MUST read a `MAX_ACTIVE_EVENTS` environment variable at startup to determine the event creation cap.
- **FR-002**: If `MAX_ACTIVE_EVENTS` is set to a positive integer and the number of non-expired events equals or exceeds that value, the server MUST reject new event creation requests with a clear error response.
- **FR-003**: The frontend MUST surface the capacity error on the event creation form — not as a silent failure or generic error.
- **FR-004**: If `MAX_ACTIVE_EVENTS` is unset or empty, the server MUST apply no limit — event creation is unlimited.
- **FR-005**: Only non-expired events MUST count toward the limit; expired events awaiting cleanup are excluded from the count.
- **FR-006**: The limit MUST be enforced server-side; client-side state or input cannot bypass it.
- **FR-007**: No personal data or PII MUST be logged when a creation request is rejected due to the cap.
- **FR-008**: The `MAX_ACTIVE_EVENTS` environment variable MUST be documented in the README's self-hosting section (configuration table).
### Key Entities
- **Event (active count)**: The count of events whose `expiry_date` is in the future. This is the value checked against `MAX_ACTIVE_EVENTS` at event creation time.
## Success Criteria
### Measurable Outcomes
- **SC-001**: When the cap is reached, a POST to the event creation endpoint returns an appropriate HTTP error status with a machine-readable error body.
- **SC-002**: The capacity error is displayed to the user on the creation form with a message that does not expose internal state or configuration values.
- **SC-003**: Creating events up to but not exceeding the cap succeeds without any change in behavior compared to uncapped instances.
- **SC-004**: The `MAX_ACTIVE_EVENTS` variable appears in the README configuration table with its type, default, and description documented.
- **SC-005**: Expired events (past `expiry_date`) are never counted toward the cap, verifiable by inspecting the query or checking behavior after expiry.