# Contributing to Prism

> See also: [README.md](README.md) (project overview) | [CLAUDE.md](CLAUDE.md) (AI agent context) | [dev/dev-docs.md](dev/dev-docs.md) (development docs)
>
> CLI: `uv run prisme --help` (install: `uv add prisme`) | Docs: [docs/](docs/) | [prisme.readthedocs.io](https://prisme.readthedocs.io/)

Thank you for your interest in contributing to Prism! This document provides guidelines and instructions for contributing.

## Development Setup

### Prerequisites

- Python 3.13+
- [uv](https://docs.astral.sh/uv/) (recommended package manager)
- Git
- Docker (optional, for integration tests)

### Installation

```bash
# Clone the repository
git clone https://github.com/Lasse-numerous/prisme.git
cd prisme

# Install dependencies (includes dev dependencies)
uv sync --all-extras

# Install all git hooks (pre-commit, commit-msg, pre-push)
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push
```

### Running Tests

Tests run automatically on `git push` via pre-push hooks. You can also run them manually:

```bash
# Run all tests (recommended before pushing)
uv run pytest

# Quick check - stop on first failure
uv run pytest -x

# Run with coverage
uv run pytest --cov --cov-report=html

# Run specific test file
uv run pytest tests/spec/test_models.py

# Run specific test function
uv run pytest tests/spec/test_models.py::TestModelSpec::test_valid_model

# Pattern matching
uv run pytest -k "model and not slow"

# Run slow tests (excluded by default)
uv run pytest -m slow

# Run end-to-end tests
uv run pytest -m e2e

# Run Docker tests (requires Docker)
uv run pytest -m docker
```

### Code Quality

```bash
# Lint code
uv run ruff check .

# Auto-fix linting issues
uv run ruff check . --fix

# Check formatting
uv run ruff format --check .

# Auto-format code
uv run ruff format .

# Type check
uv run mypy src

# Build documentation
uv run mkdocs build --strict
```

## Architecture at a Glance

Understanding the codebase helps you contribute effectively. Prism follows a pipeline architecture:

```
specs/models.py (StackSpec)
    → validate (validators.py)
    → build GeneratorContext
    → run 31 generators (backend, frontend, testing, infrastructure)
    → apply FileStrategy per file
    → write to disk (with manifest tracking)
```

Key source directories in `src/prisme/`:

| Directory | Purpose |
|-----------|---------|
| `cli.py` | CLI entry point — 67+ Click commands across 16 groups |
| `spec/` | Pydantic models: `StackSpec` → `ModelSpec` → `FieldSpec` |
| `generators/` | 31 generator classes (backend, frontend, testing, infrastructure) |
| `templates/jinja2/` | 282 Jinja2 templates mirroring generator structure |
| `tracking/` | `ManifestManager` — file hash tracking for override detection |
| `utils/` | Spec loading, template rendering, file handling, protected regions |
| `docker/` | Docker Compose generation, Traefik proxy |
| `deploy/` | Hetzner/Terraform deployment |

Each generator inherits from `generators/base.py` and produces `GeneratedFile` objects with a `FileStrategy` that controls how files are written:

| Strategy | Behavior |
|----------|----------|
| `ALWAYS_OVERWRITE` | Regenerated every time (types, schemas) |
| `GENERATE_ONCE` | Created once, never overwritten (user extensions) |
| `GENERATE_BASE` | Base regenerated, user code preserved (services, components) |
| `MERGE` | Smart merge with conflict markers (assembly files) |

For deeper architecture details, see [docs/architecture/](docs/architecture/) and the [develop-prism skill](.claude/skills/develop-prism/SKILL.md).

## Commit Message Format

We use [Conventional Commits](https://www.conventionalcommits.org/) for our commit messages. This enables automatic semantic versioning and changelog generation.

### Format

```
<type>(<scope>): <description>

[optional body]

[optional footer(s)]
```

### Types

| Type | Description | Version Bump |
|------|-------------|--------------|
| `feat` | A new feature | Minor |
| `fix` | A bug fix | Patch |
| `perf` | Performance improvement | Patch |
| `docs` | Documentation only changes | None |
| `style` | Code style changes (formatting, whitespace) | None |
| `refactor` | Code changes that neither fix bugs nor add features | None |
| `test` | Adding or modifying tests | None |
| `build` | Changes to build system or dependencies | None |
| `ci` | Changes to CI configuration | None |
| `chore` | Other changes that don't modify src or test files | None |

### Scopes

Common scopes: `generators`, `spec`, `cli`, `templates`, `docker`, `deploy`, `tests`, `tracking`, `dx`.

### Examples

```bash
# Feature
feat(generators): add support for nested model generation

# Bug fix
fix(cli): resolve path resolution on Windows

# Breaking change (add ! after type)
feat(spec)!: rename FieldType.TEXT to FieldType.STRING

# With scope
fix(backend): handle null values in REST serialization

# Without scope
docs: update installation instructions
```

### Commit Linting

Commit messages are automatically validated by the `commit-msg` hook (installed via pre-commit). If your commit message doesn't follow the conventional commits format, the commit will be rejected. No Node.js required — this uses the Python-based [conventional-pre-commit](https://github.com/compilerla/conventional-pre-commit) hook.

## Git Hooks

All hooks are managed by [pre-commit](https://pre-commit.com/). Install them with:

```bash
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push
```

### Pre-commit (on `git commit`)

Runs automatically on each commit to fix formatting issues:
- **ruff** — Auto-fix linting issues
- **ruff-format** — Auto-format code
- **trailing-whitespace** — Remove trailing whitespace
- **end-of-file-fixer** — Ensure files end with newline
- **check-yaml** — Validate YAML syntax

### Commit-msg (on `git commit`)

Validates commit message format:
- **conventional-pre-commit** — Ensures commit follows [Conventional Commits](https://www.conventionalcommits.org/) format

### Pre-push (on `git push`)

Runs automatically before pushing to catch CI failures early:
- **ruff check** — Lint check (no auto-fix)
- **ruff format --check** — Format check
- **mypy** — Type checking
- **pytest** — Run tests

This mirrors the CI pipeline, so if pre-push passes, CI should pass too.

## CI/CD Pipeline

### Continuous Integration

Every push and pull request triggers the CI workflow which runs:

1. **Linting** — `ruff check .`
2. **Format Check** — `ruff format --check .`
3. **Type Checking** — `mypy src`
4. **Tests** — `pytest --cov`
5. **Coverage Upload** — Results uploaded to Codecov

All checks must pass before a PR can be merged.

### Automated Releases

When changes are merged to `main`:

1. **Semantic Release** analyzes commits since last release
2. If releasable commits exist:
   - Version is bumped based on commit types
   - CHANGELOG.md is updated
   - GitHub release is created
   - Package is published to PyPI

## Pull Request Process

1. **Fork** the repository and create a feature branch
2. **Make changes** following the code style guidelines
3. **Write tests** for new functionality
4. **Commit** using conventional commit format
5. **Push** — pre-push hooks automatically run CI checks (lint, format, type check, tests)
6. **Open a Pull Request** once pre-push checks pass
7. **Address feedback** from code review

> **Note:** If you need to bypass pre-push hooks (not recommended), use `git push --no-verify`

## Common Development Tasks

### Adding a new field type

1. Add the type to `FieldType` enum in `src/prisme/spec/fields.py`
2. Update generators that map field types to output code (models, schemas, TypeScript types)
3. Update Jinja2 templates that reference field type mappings
4. Add/update validators in `validators.py` if cross-model rules apply
5. Add tests in `tests/spec/` and affected generator test directories

### Adding a new generator

1. Create generator class in `src/prisme/generators/<layer>/`
2. Inherit from base, implement `generate()` → `GeneratorResult`
3. Add Jinja2 templates in `src/prisme/templates/jinja2/<layer>/`
4. Register in `cli.py`'s `_run_generators()` pipeline
5. Add tests in `tests/generators/<layer>/`

### Adding a CLI command

1. Add Click command/group in `src/prisme/cli.py`
2. Use Rich console for output (spinners, tables, panels)
3. Add tests in `tests/cli/`

### Modifying a Jinja2 template

1. Find template in `src/prisme/templates/jinja2/`
2. Update template (templates mirror generator structure)
3. Run affected generator tests to verify output
4. Check `FileStrategy` — if `GENERATE_BASE`, ensure user extensions aren't broken

## Code Style

- Follow PEP 8 guidelines (enforced by ruff)
- Use type hints for all function signatures
- Write docstrings for public APIs
- Keep functions focused and small
- Prefer composition over inheritance
- Line length: 100 characters (ruff)
- Target Python version: 3.13

## Testing Guidelines

- Write tests for all new functionality
- Maintain or improve code coverage
- Use descriptive test names
- Use fixtures for common test data (see `tests/conftest.py` for shared fixtures)
- Mark slow tests with `@pytest.mark.slow`
- Mark end-to-end tests with `@pytest.mark.e2e`
- Mark Docker-dependent tests with `@pytest.mark.docker`
- Tests have a 120-second timeout by default

## Development Documentation

Internal development documentation is maintained in the `dev/` folder:

- **[dev/dev-docs.md](dev/dev-docs.md)** — Conventions, templates, and file naming guidelines
- **[dev/roadmap.md](dev/roadmap.md)** — Development roadmap and priorities
- **dev/issues/** — Active issue tracking documents
- **dev/plans/** — Implementation plans for features
- **dev/tasks/** — Active task tracking documents

See [dev/dev-docs.md](dev/dev-docs.md) for document templates and naming conventions.

## Questions?

Feel free to open an issue for questions or discussions about contributing.
