Files
fete/specs/019-instance-limit/spec.md
nitrix 6aeb4b8bca 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>
2026-03-06 20:19:41 +01:00

6.3 KiB

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.