Skip to main content

Overview

Aya uses a Make-based workflow with quality gates enforced at every step. All changes go through the same process: branch → develop → test → commit → pull request.
Before starting: Ensure you have Deno, Go 1.22+, Docker, and Make installed. Run make init in the project root to set up development tools.

Development Setup

1

Fork and Clone

Fork the repository on GitHub, then clone your fork:
git clone https://github.com/YOUR_USERNAME/aya.is.git
cd aya.is
2

Initialize Project

Install tools, dependencies, and pre-commit hooks:
make init
This installs:
  • Pre-commit hooks (runs linters automatically)
  • Go tools: sqlc, golangci-lint, mockery, air
  • Frontend dependencies via Deno
3

Start Development Environment

Start all services with Docker Compose:
make up      # Start containers
make watch   # Start with hot-reload
make logs    # View logs
Services available:
4

Verify Setup

Run all quality checks to ensure everything works:
make ok
This runs:
  • Backend: make lint, make check, make test
  • Frontend: deno lint, deno fmt --check, deno task test:ci

Branch Strategy

Aya uses a trunk-based development workflow with short-lived feature branches.

Branch Naming Convention

Use descriptive branch names with prefixes:
# New features
feat/user-profile-pages
feat/markdown-editor

# Bug fixes
fix/login-redirect
fix/null-check-stories

# Refactoring
refactor/extract-query-logic
refactor/hexagonal-profiles

# Documentation
docs/contributing-guide
docs/api-examples

# Chores (dependencies, config)
chore/update-deno
chore/golangci-config

Creating a Feature Branch

1

Pull Latest Changes

git checkout main
git pull upstream main
2

Create Feature Branch

git checkout -b feat/your-feature-name
3

Make Changes

Develop your feature, making frequent commits:
# Make changes...
git add .
git commit -m "feat: add user profile page"
4

Keep Branch Updated

Regularly sync with main to avoid conflicts:
git fetch upstream
git rebase upstream/main
Never use git checkout or git restore to revert file contents. This can destroy work from parallel agents/contributors. Use git revert for commits or manually undo changes.

Development Loop

Follow this cycle for efficient development:

Frontend Development

# Navigate to frontend
cd apps/webclient

# Start dev server (with hot reload)
deno task dev

# In another terminal, run checks
deno lint
deno fmt --check
deno task test:ci

# Format code
deno fmt

# Update snapshots after intentional UI changes
deno task test:update

Backend Development

# Navigate to backend
cd apps/services

# Run with hot reload
make dev

# In another terminal, run checks
make lint      # golangci-lint
make check     # govulncheck, betteralign, modernize
make test      # Run tests with race detection

# Fix formatting and alignment
make fix

Full Stack Verification

Before committing, always run from the project root:
make ok
This is the mandatory quality gate that runs:
  • Backend linting, static analysis, and tests
  • Frontend linting, formatting checks, and snapshot tests (CI mode)
Pro tip: Pre-commit hooks automatically run make ok before commits. If you skip hooks with --no-verify, you must run make ok manually.

Commit Guidelines

Aya follows Conventional Commits for clear, semantic commit history.

Commit Format

<type>(<scope>): <subject>

<body>

<footer>

Commit Types

TypeDescriptionExample
featNew featurefeat(profiles): add bio field to user profiles
fixBug fixfix(auth): handle null user in session check
refactorCode restructuringrefactor(api): extract pure functions for testing
perfPerformance improvementperf(queries): add index to story_tx.locale_code
testAdd or fix teststest(profiles): add snapshot tests for profile card
docsDocumentation changesdocs(contributing): add testing guidelines
styleCode style (formatting)style(webclient): fix deno fmt issues
choreMaintenance taskschore(deps): update golangci-lint to v2.0
ciCI/CD changesci(github): add Go test coverage action

Scope Examples

  • Backend: profiles, stories, auth, api, business, adapters
  • Frontend: webclient, components, routes, modules, i18n
  • Infrastructure: docker, makefile, ci, deps

Example Commits

Good commits (descriptive, explain “why”):
feat(profiles): add 3-tier locale fallback for translations

Implements requested default any fallback logic for profile_tx
joins. Ensures profiles always display content even when the exact
locale isn't available.

Resolves #123
fix(auth): use explicit null check instead of truthy

Previously used `if (!user)` which failed for valid user objects with
falsy properties. Now uses `if (user === null)` per coding standards.
refactor(api): extract pure functions for Deno testing

Separates locale validation logic from config.ts into locale-utils.ts
to avoid import.meta.env dependencies. Enables direct testing with
Deno without Vite runtime.
Bad commits (vague, no context):
 fix stuff
 wip
 update code
 fix bug in profiles

Commit Message Best Practices

Do:
  • Use imperative mood (“add feature” not “added feature”)
  • Explain WHY the change was made, not just WHAT changed
  • Reference issue numbers when applicable
  • Keep subject line under 72 characters
  • Add body for complex changes
Don’t:
  • Use vague messages like “fix bug” or “update”
  • Include personal frustrations or complaints
  • Write multi-line subjects
  • Add unnecessary details about HOW (code shows this)
One logical change per commit:Good:
# Commit 1: Add feature
feat(profiles): add bio field to profile schema

# Commit 2: Add tests
test(profiles): add tests for bio field validation

# Commit 3: Update docs
docs(api): document bio field in profile endpoints
Bad:
# Single commit with unrelated changes
feat: add bio field, fix login bug, update readme

Testing Requirements

Every contribution must include tests. See Testing Guidelines for details. Before committing:
# Backend tests
cd apps/services
make test

# Frontend tests (snapshot tests)
cd apps/webclient
deno task test:ci

# All tests from root
make ok

Pre-Commit Checklist

Before every commit, verify:
  • Code follows code style guidelines
  • All tests pass (make ok)
  • New functionality has tests
  • No console.log or debug statements
  • Commit message follows Conventional Commits
  • No TODOs or placeholder code
  • Documentation updated (if needed)

Submitting Changes

Once your feature is complete and tested:
1

Final Quality Check

make ok  # Must pass!
2

Push to Your Fork

git push origin feat/your-feature-name
3

Create Pull Request

Open a PR on GitHub from your fork to eser/aya.is:main.Follow the Pull Request Guidelines for PR format and requirements.
4

Address Review Feedback

Respond to reviewer comments, make changes, and push updates:
# Make changes based on feedback
git add .
git commit -m "refactor: address PR feedback"
git push origin feat/your-feature-name

Common Workflows

Keep your fork updated with the main repository:
# Add upstream remote (once)
git remote add upstream https://github.com/eser/aya.is.git

# Sync with upstream
git checkout main
git fetch upstream
git rebase upstream/main
git push origin main
If your branch conflicts with main:
git fetch upstream
git rebase upstream/main

# Resolve conflicts in editor
# Then continue rebase
git add .
git rebase --continue

# Force push (rewritten history)
git push --force-with-lease origin feat/your-feature
If CI fails after pushing:
  1. Check the CI logs on GitHub
  2. Run the same checks locally:
    make ok
    
  3. Fix issues and commit:
    git add .
    git commit -m "fix: resolve linting issues"
    git push origin feat/your-feature
    
Clean up commit history before PR:
# Interactive rebase to squash/reorder commits
git rebase -i upstream/main

# Or squash all commits in branch
git reset --soft upstream/main
git commit -m "feat: descriptive summary of all changes"
git push --force-with-lease origin feat/your-feature

Getting Help

If you’re stuck:
  1. Check Documentation: Review Code Style and Testing guides
  2. Search Issues: See if others had similar problems
  3. Ask in Discussions: Use GitHub Discussions for questions
  4. Read Source Code: Look at similar features for examples
Never commit code that doesn’t pass make ok. This is the single most important rule. Pre-commit hooks enforce this, but if bypassed, your PR will fail CI.

Build docs developers (and LLMs) love