diff --git a/.aider.conf.yml b/.aider.conf.yml new file mode 100644 index 00000000..650aa3ab --- /dev/null +++ b/.aider.conf.yml @@ -0,0 +1,462 @@ +########################################################## +# Sample .aider.conf.yml +# This file lists *all* the valid configuration entries. +# Place in your home dir, or at the root of your git repo. +########################################################## + +# Note: You can only put OpenAI and Anthropic API keys in the yaml +# config file. Keys for all APIs can be stored in a .env file +# https://aider.chat/docs/config/dotenv.html + +########## +# options: + +## show this help message and exit +#help: xxx + +############# +# Main model: + +## Specify the model to use for the main chat +model: gemini-2.5-pro + +######################## +# API Keys and settings: + +## Specify the OpenAI API key +#openai-api-key: xxx + +## Specify the Anthropic API key +#anthropic-api-key: xxx + +## Specify the api base url +#openai-api-base: xxx + +## (deprecated, use --set-env OPENAI_API_TYPE=) +#openai-api-type: xxx + +## (deprecated, use --set-env OPENAI_API_VERSION=) +#openai-api-version: xxx + +## (deprecated, use --set-env OPENAI_API_DEPLOYMENT_ID=) +#openai-api-deployment-id: xxx + +## (deprecated, use --set-env OPENAI_ORGANIZATION=) +#openai-organization-id: xxx + +## Set an environment variable (to control API settings, can be used multiple times) +#set-env: xxx +## Specify multiple values like this: +#set-env: +# - xxx +# - yyy +# - zzz + +## Set an API key for a provider (eg: --api-key provider= sets PROVIDER_API_KEY=) +#api-key: xxx +## Specify multiple values like this: +#api-key: +# - xxx +# - yyy +# - zzz + +################# +# Model settings: + +## List known models which match the (partial) MODEL name +#list-models: xxx + +## Specify a file with aider model settings for unknown models +#model-settings-file: .aider.model.settings.yml + +## Specify a file with context window and costs for unknown models +#model-metadata-file: .aider.model.metadata.json + +## Add a model alias (can be used multiple times) +#alias: xxx +## Specify multiple values like this: +#alias: +# - xxx +# - yyy +# - zzz + +## Set the reasoning_effort API parameter (default: not set) +## depends on the concrete model if and how this is supported +reasoning-effort: high + +## Set the thinking token budget for models that support it (default: not set) +## depends on the concrete model if and how this is supported +#thinking-tokens: xxx + +## Verify the SSL cert when connecting to models (default: True) +#verify-ssl: true + +## Timeout in seconds for API calls (default: None) +#timeout: xxx + +## Specify what edit format the LLM should use (default depends on model) +#edit-format: xxx + +## Use architect edit format for the main chat +#architect: false + +## Enable/disable automatic acceptance of architect changes (default: True) +#auto-accept-architect: true + +## Specify the model to use for commit messages and chat history summarization (default depends on --model) +#weak-model: xxx + +## Specify the model to use for editor tasks (default depends on --model) +#editor-model: xxx + +## Specify the edit format for the editor model (default: depends on editor model) +#editor-edit-format: xxx + +## Only work with models that have meta-data available (default: True) +#show-model-warnings: true + +## Check if model accepts settings like reasoning_effort/thinking_tokens (default: True) +#check-model-accepts-settings: true + +## Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. +#max-chat-history-tokens: xxx + +################# +# Cache settings: + +## Enable caching of prompts (default: False) +#cache-prompts: false + +## Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) +#cache-keepalive-pings: false + +################### +# Repomap settings: + +## Suggested number of tokens to use for repo map, use 0 to disable +#map-tokens: xxx + +## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) +#map-refresh: auto + +## Multiplier for map tokens when no files are specified (default: 2) +#map-multiplier-no-files: true + +################ +# History Files: + +## Specify the chat input history file (default: .aider.input.history) +#input-history-file: .aider.input.history + +## Specify the chat history file (default: .aider.chat.history.md) +#chat-history-file: .aider.chat.history.md + +## Restore the previous chat history messages (default: False) +#restore-chat-history: false + +## Log the conversation with the LLM to this file (for example, .aider.llm.history) +#llm-history-file: xxx + +################## +# Output settings: + +## Use colors suitable for a dark terminal background (default: False) +#dark-mode: false + +## Use colors suitable for a light terminal background (default: False) +#light-mode: false + +## Enable/disable pretty, colorized output (default: True) +#pretty: true + +## Enable/disable streaming responses (default: True) +#stream: true + +## Set the color for user input (default: #00cc00) +#user-input-color: "#00cc00" + +## Set the color for tool output (default: None) +#tool-output-color: "xxx" + +## Set the color for tool error messages (default: #FF2222) +#tool-error-color: "#FF2222" + +## Set the color for tool warning messages (default: #FFA500) +#tool-warning-color: "#FFA500" + +## Set the color for assistant output (default: #0088ff) +#assistant-output-color: "#0088ff" + +## Set the color for the completion menu (default: terminal's default text color) +#completion-menu-color: "xxx" + +## Set the background color for the completion menu (default: terminal's default background color) +#completion-menu-bg-color: "xxx" + +## Set the color for the current item in the completion menu (default: terminal's default background color) +#completion-menu-current-color: "xxx" + +## Set the background color for the current item in the completion menu (default: terminal's default text color) +#completion-menu-current-bg-color: "xxx" + +## Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light, or a Pygments builtin style, see https://pygments.org/styles for available themes) +#code-theme: default + +## Show diffs when committing changes (default: False) +#show-diffs: false + +############### +# Git settings: + +## Enable/disable looking for a git repo (default: True) +#git: true + +## Enable/disable adding .aider* to .gitignore (default: True) +#gitignore: true + +## Specify the aider ignore file (default: .aiderignore in git root) +#aiderignore: .aiderignore + +## Only consider files in the current subtree of the git repository +#subtree-only: false + +## Enable/disable auto commit of LLM changes (default: True) +auto-commits: false + +## Enable/disable commits when repo is found dirty (default: True) +#dirty-commits: true + +## Attribute aider code changes in the git author name (default: True) +#attribute-author: true + +## Attribute aider commits in the git committer name (default: True) +#attribute-committer: true + +## Prefix commit messages with 'aider: ' if aider authored the changes (default: False) +#attribute-commit-message-author: false + +## Prefix all commit messages with 'aider: ' (default: False) +#attribute-commit-message-committer: false + +## Enable/disable git pre-commit hooks with --no-verify (default: False) +#git-commit-verify: false + +## Commit all pending changes with a suitable commit message, then exit +#commit: false + +## Specify a custom prompt for generating commit messages +#commit-prompt: xxx + +## Perform a dry run without modifying files (default: False) +#dry-run: false + +## Skip the sanity check for the git repository (default: False) +#skip-sanity-check-repo: false + +## Enable/disable watching files for ai coding comments (default: False) +#watch-files: false + +######################## +# Fixing and committing: + +## Lint and fix provided files, or dirty files if none provided +lint: false + +## Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times) +# lint-cmd: gw-spotless # won't work because aider does not support bash aliases +## Specify multiple values like this: +#lint-cmd: +# - xxx +# - yyy +# - zzz + +## Enable/disable automatic linting after changes (default: True) +#auto-lint: true + +## Specify command to run tests +#test-cmd: xxx + +## Enable/disable automatic testing after changes (default: False) +#auto-test: false + +## Run tests, fix problems found and then exit +#test: false + +############ +# Analytics: + +## Enable/disable analytics for current session (default: random) +#analytics: xxx + +## Specify a file to log analytics events +#analytics-log: xxx + +## Permanently disable analytics +#analytics-disable: false + +############ +# Upgrading: + +## Check for updates and return status in the exit code +#just-check-update: false + +## Check for new aider versions on launch +#check-update: true + +## Show release notes on first run of new version (default: None, ask user) +#show-release-notes: xxx + +## Install the latest version from the main branch +#install-main-branch: false + +## Upgrade aider to the latest version from PyPI +#upgrade: false + +## Show the version number and exit +#version: xxx + +######## +# Modes: + +## Specify a single message to send the LLM, process reply then exit (disables chat mode) +#message: xxx + +## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode) +#message-file: xxx + +## Run aider in your browser (default: False) +#gui: false + +## Enable automatic copy/paste of chat between aider and web UI (default: False) +#copy-paste: false + +## Apply the changes from the given file instead of running the chat (debug) +#apply: xxx + +## Apply clipboard contents as edits using the main model's editor format +#apply-clipboard-edits: false + +## Do all startup activities then exit before accepting user input (debug) +#exit: false + +## Print the repo map and exit (debug) +#show-repo-map: false + +## Print the system prompts and exit (debug) +#show-prompts: false + +################# +# Voice settings: + +## Audio format for voice recording (default: wav). webm and mp3 require ffmpeg +#voice-format: wav + +## Specify the language for voice using ISO 639-1 code (default: auto) +#voice-language: en + +## Specify the input device name for voice recording +#voice-input-device: xxx + +################# +# Other settings: + +## specify a file to edit (can be used multiple times) +#file: xxx +## Specify multiple values like this: +#file: +# - xxx +# - yyy +# - zzz + +## specify a read-only file (can be used multiple times) +read: CONVENTIONS.md + +## Specify multiple values like this: +# read: +# - CONVENTIONS.md +# - ... +# - ... + +## Use VI editing mode in the terminal (default: False) +#vim: false + +## Specify the language to use in the chat (default: None, uses system settings) +#chat-language: xxx + +## Always say yes to every confirmation +#yes-always: false + +## Enable verbose output +#verbose: false + +## Load and execute /commands from a file on launch +#load: xxx + +## Specify the encoding for input and output (default: utf-8) +#encoding: utf-8 + +## Line endings to use when writing files (default: platform) +#line-endings: platform + +## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory) +#config: xxx + +## Specify the .env file to load (default: .env in git root) +#env-file: .env + +## Enable/disable suggesting shell commands (default: True) +#suggest-shell-commands: true + +## Enable/disable fancy input with history and completion (default: True) +#fancy-input: true + +## Enable/disable multi-line input mode with Meta-Enter to submit (default: False) +#multiline: false + +## Enable/disable terminal bell notifications when LLM responses are ready (default: False) +#notifications: false + +## Specify a command to run for notifications instead of the terminal bell. If not specified, a default command for your OS may be used. +#notifications-command: xxx + +## Enable/disable detection and offering to add URLs to chat (default: True) +#detect-urls: true + +## Specify which editor to use for the /editor command +#editor: xxx + +############################ +# Deprecated model settings: + +## Use claude-3-opus-20240229 model for the main chat (deprecated, use --model) +#opus: false + +## Use anthropic/claude-3-7-sonnet-20250219 model for the main chat (deprecated, use --model) +#sonnet: false + +## Use claude-3-5-haiku-20241022 model for the main chat (deprecated, use --model) +#haiku: false + +## Use gpt-4-0613 model for the main chat (deprecated, use --model) +#4: false + +## Use gpt-4o model for the main chat (deprecated, use --model) +#4o: false + +## Use gpt-4o-mini model for the main chat (deprecated, use --model) +#mini: false + +## Use gpt-4-1106-preview model for the main chat (deprecated, use --model) +#4-turbo: false + +## Use gpt-3.5-turbo model for the main chat (deprecated, use --model) +#35turbo: false + +## Use deepseek/deepseek-chat model for the main chat (deprecated, use --model) +#deepseek: false + +## Use o1-mini model for the main chat (deprecated, use --model) +#o1-mini: false + +## Use o1-preview model for the main chat (deprecated, use --model) +#o1-preview: false diff --git a/.gitignore b/.gitignore index bd8ec3fe..8f9613a5 100644 --- a/.gitignore +++ b/.gitignore @@ -142,3 +142,8 @@ Desktop.ini ###################### /.environment* /src/test/resources/migration-prod/* +.aider/ +.aider.tags.cache.* +.aider.chat.history.md +.aider.input.history +.cache diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 00000000..18ab2d1b --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,111 @@ +# Code Generting Conventions + +This document outlines the coding conventions for this project to be used by any AI agent. +Ask the user to add these files to the AI agent before generating anything. + +## Initially + +At the beginning of each code generation session, determine all files which are not yet added, but might need to be changed and new files which might need to be created. + +Consider: +- related Java-classes (*.java), including test classes +- also Java-classes files in the same package as the mainly related class, e.g. patcher +- related liquibase changesets (*.sql) +- related openapi specs (*.yaml) +- related i18n files (*.properties) + +Make sure production code and test code stay in sync, +a change in one usually means the other has also to be changed. + +## Java Conventions (`*.java` files) + +### General Rules for Java Files + +These rules apply to all `.java` files in `src/**/*.java` but not those located in `**/generated/**`, `build/**`, or `.gradle/**` directories. + +1. **Imports**: No wildcard imports. Unused imports must be removed. +2. **Indentation**: Use 4 spaces for indentation. Do not use tabs. +3. **End of File**: All files must end with a newline character. +4. **Formatting Control**: Spotless formatting can be temporarily disabled for specific code blocks using comments: + ```java + // spotless:off + // ... code that should not be formatted ... + // spotless:on + ``` +* Follow existing code style and patterns within the project. + - Avoid reassigning variables and use `final var` where possible. + - Use `final` for method parameters. +* Use meaningful names for variables, methods, and classes. +* Write clear and concise comments where necessary to explain complex logic or intent. + +### toString via Stringify + +For assertions, keep in mind, that the Stringify implementation of the toString method skips null values. Thus, do not add null values in assertions if a Stringify-based toString implementation is tested! + + +## PostgreSQL Conventions (`*.sql` files) + +Do only Liquibase changesets if they got created in the same branch. + +If they already exist in the master branch, generate a new Liquibase changeset. + +Add new Liquibase changesets to existing files where they belong, +e.g. add a changeset with an ALTER TABLE directly after the related CREATE TABLE changeset. + +If creating a new Liquibase changeset, there is no need to check if the change already exists, Liquibase will check that. + +## i18n Conventions (`*.properties` files) + +Use the English translation as the key in the `messages_*.properties` file, +'=' and ' ' need to be quoted. + +## YAML Conventions (*.yaml files) + +Always use exactly 4 spaces for indentation. + +## General Conventions + +### general strategy + +At the beginning of each task, always determine all files which might need to be changed and new files which might need to be created. + +### adding/deleting/amending fields/properties + +If a field in a database table is added, deleted or amended, the following steps must be taken: + +- The property must be added to the Java class on which the entity/entities are based; it must also be included in the toString method. Also amend the related unit test. + +- If the related entity has a patcher class, also add the new property to the patcher (usually ending with EntityPatcher) and its unit test (usually ending with EntityPatcherUnitTest). + +- The property must be included in (potentially 3) JSON resources (POST, GET, PATCH) in the OpenAPI specification. + +- The property must be added to the SQL table, so either enforce it via Liquibase or create a new Liquibase changeset. + +- The property must be included in the restricted view, which must be dropped and recreated due to the structural change; this view is generated by a stored procedure from the RBAC system. + +- The property must be added to the RBAC update trigger; for this, the RBAC DSL, the static method rbac() in the entity class(es), must be adjusted. The generator should automatically force Liquibase to reapply the changeset. + +- The tests may need to be adjusted; the new field should also be tested in an integration test for POST, GET, and PATCH. + +## While Generating CHanges + +Check all added files, if they need to be changed for the new feature. +Most likely, all added files need some sort of change. + +Make sure production code and test code stay in sync, +a change in one usually means the other has also to be changed. + +## Executing Commands + +### Generating from OpenAPI + +If OpenAPI specs (*.yaml) got changed, `gw openApiGenerate` needs to be executed. + +### Generating from RBAC DSL + +If any RBAC spec of an entity has changed, the static rbac() method in an entity class, `gw rbacGenerate` has to be executed before any test can run. + +### Test Execution + +Use the alias `gw-test` to run the tests with a proper environment. +Do not suggest to run `./gradlew test`, it won't work without a correect environment. diff --git a/README.md b/README.md index 1997dcf9..162885ce 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # hsadminNg Development +(The origin repository for this project can be found at [Hostsharing eG](https://git.hostsharing.net/hostsharing/hs.hsadmin.ng).) + This documents gives an overview of the development environment and tools. For architecture consider the files in the `doc` and `adr` folder. @@ -361,6 +363,9 @@ You can explore the prototype as follows: ### Directory and Package Structure #### General Directory Structure + +`.aider.conf.yml` + Configuration for the _aider AI_ coding agent. `.aliases` Shell-aliases for common tasks. @@ -371,6 +376,9 @@ You can explore the prototype as follows: `build.gradle.kts` Gradle build-file (Kotlin-Script). Contains dependencies and build configurations. +`CONVENTIONS.md` + Coding conventions for use by an AI agent. + `doc/` Contains project documentation. @@ -932,6 +940,126 @@ BEGIN END $$; ``` +### How to Use _aider AI_ - Pair Programming in Your Terminal + +[aider](https://aider.chat/) is an [open source](https://github.com/Aider-AI/aider) AI agent in the shape of a command-line tool that lets you code with large language models (LLMs) OpenAI GPT, Claude Sonnet or Google Gemini. +It allows you to easily analyze and edit files by chatting with the AI. + +*BEWARE*: aider is going to send your source code to the LLM! + +_hsadmin-NG_ is open source, so this is not a big problem. +For more information about security regarding aider, please have a look at the end of this chapter and check out [the aider privacy policy](https://aider.chat/docs/legal/privacy.html). + +#### Installation + +Assuming you have Python 3 and `pipx` installed (a tool to install and run Python applications in isolated environments), you can install `aider-chat` like this: + +```shell +pipx install aider-chat +``` + +If you want to use specific features like OpenAI's vision capabilities, you might need to add the following dependencies: + +```shell +pipx inject aider-chat openai --include-apps +``` + +To add support for Google's Gemini AI, you can add the `google-generativeai` package: + +```shell +pipx inject aider-chat google-generativeai --include-apps +``` + +#### Configuration + +`aider` requires an API key for the AI model you want to use. + +E.g. for _OpenAI GPT_, set the `OPENAI_API_KEY` environment variable: + +```shell +export OPENAI_API_KEY="your-api-key-here" +``` + +And e.g. for _Google Gemini_, set the `GEMINI_API_KEY` environment variable: + +```shell +export GEMINI_API_KEY="your-api-key-here" +``` + +You might want to add this to your shell's startup file (e.g., `.bashrc`, `.zshrc`). + +#### Usage + +1. Navigate to your project's root directory in the terminal. +2. Start `aider` by simply typing: + ```shell + aider # see also .aider.conf.yml + ``` +3. Add the files you want the AI to work with: + ``` + /add path/to/your/file.java path/to/another/file.py + ``` +4. Start chatting! Describe the changes you want, ask questions, or request code generation. `aider` will propose changes and apply them directly to your files after your confirmation. +5. Use `/quit` to exit `aider`. + +Refer to the [official aider documentation](https://aider.chat/docs/usage.html) for more commands and advanced features. + +#### Example Session + +Aider is not yet very good at figuring out which files to amend in a large code base. +I tried giving hints with `/ask`, but it was always missing too many files. +With some of my approaches, it even wanted to create new files, which is not necessary for this task. + +I even tried with other language models, like gpt-o4 or r1 (deepseek-reasoning), no success. +Maybe somebody else can figure it out, or it gets better with time? + +For now, I just determined the files myself. +As I knew that the new filed needs to be supported everywhere, +where the existing field `registrationOffice` occurs, I could simply use grep: + +```shell + aider `grep -rl registrationOffice src/main/java/ src/test/java/ src/main/resources/api-definition src/main/resources/db/` +``` + +Then I requested my change to the _aider AI_ chat: + +> I want to add a text field `notes` to the database table `hs_office.partner_details` and related files. + Files to amend have already been added to aider AI. + Please apply all required changes for Java production+test-code, + add the Liquibase changeset and amend the OpenAPI-Spec. + +I ran the tests and found that patching the partner details did not work. +So, I told the _aider AI_ about it: + +> Please doublecheck if you followed all conventions. + Any other amendments necessary to support the new field `notes` in the partner details? + +Then I saw, that _aider AI_ did add some notes to the test data, but not to the assertions. +I decided that the changes in the test-data are not necessary and reverted thos files using git. + +Now, all tests passed. + +Try it yourself, but keep in mind that LLMs use a concept called _temperature_ which specifies a level of randomness. +This means, you might get different results. + +#### Security + +To reassure myself which files _aider AI_ accesses, I checked this with `strace`: + +``` +# run aider under strace: +strace -f -t -e trace=file -o build/aider.strace aider ... + +# and in another terminal check the strace log: +tail -f build/aider.strace | grep -oP '"\K[^\n"]+(?=")' +``` + +At the time I've checked it, all accessed files made sense. +Of course, as with any locally installed application, there is no guarantee. + +There is a _Docker_ image for _aider AI_, but it's pretty restriced +and to be able to use some features, you'd need to rebuild the image. + ## Further Documentation diff --git a/build.gradle.kts b/build.gradle.kts index 33500bcc..4f219c57 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -71,9 +71,11 @@ repositories { maven { url = uri("https://repo.spring.io/milestone") } } +val JAVA_VERSION = 21 + java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion.set(JavaLanguageVersion.of(JAVA_VERSION)) vendor.set(JvmVendorSpec.ADOPTIUM) implementation.set(JvmImplementation.VENDOR_SPECIFIC) } @@ -623,6 +625,20 @@ tasks.register("convertMarkdownToHtml") { dependsOn(tasks.named("scenarioTest")) } +// HOWTO re-generate the RBAC rules (PostgreSQL code) from the RBAC specs in the entities rbac()-method +// in a shell run `gw rbacGenerate` +tasks.register("rbacGenerate") { + group = "application" + mainClass.set("net.hostsharing.hsadminng.rbac.generator.RbacSpec") + classpath = sourceSets["main"].runtimeClasspath + + // This ensures the task uses the Java version from the defined toolchain. + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(JAVA_VERSION)) + vendor.set(JvmVendorSpec.ADOPTIUM) + implementation.set(JvmImplementation.VENDOR_SPECIFIC) + }) +} // shortcut for compiling all files tasks.register("compile") {