Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5a22f18
chore(7): add backup and restore helper scripts for SQLite data folder
Pertempto Oct 23, 2025
473651c
chore(7): document explicit local data bind and named-volume alternat…
Pertempto Oct 23, 2025
0423675
docs(7): document SQLite storage and Docker notes for future agents i…
Pertempto Oct 23, 2025
efe0383
docs(7): add Docker Compose persistent data notes and backup/restore …
Pertempto Oct 23, 2025
f9984eb
docs(7): add data persistence and backup/restore guide
Pertempto Oct 23, 2025
e7c5692
docs: clarify /do-pr must run tests, commit, push, create PR, and upd…
Pertempto Oct 23, 2025
aad87bc
fix: do-pr command
Pertempto Oct 23, 2025
c3bdc3b
docs: Require confirmation in /start-pr before branching or writing T…
Pertempto Oct 23, 2025
cf3b8df
docs: Move /start-pr guidance into command file; remove duplicate AGE…
Pertempto Oct 23, 2025
d5e980d
docs: update commands
Pertempto Oct 23, 2025
6705285
docs(7): move data-persistence doc to site content and note restore s…
Pertempto Oct 23, 2025
414da2d
chore: add changelog entry for PR #62
Pertempto Oct 23, 2025
4e3ae85
docs: clarify PR title/description and changelog rules to avoid issue…
Pertempto Oct 23, 2025
30ee88f
chore: fix changelog entry for PR #62 (remove issue number from entry)
Pertempto Oct 23, 2025
2bbe660
feat(7): add --dir option to backup script and move AGENTS guidance
Pertempto Oct 23, 2025
0e97b9b
feat(7): address PR feedback — relocate AGENTS storage notes, add --d…
Pertempto Oct 23, 2025
7160a47
docs: improve AGENTs.md layout
Pertempto Oct 23, 2025
b2fe5be
docs(7): document --dir option for backup script in docs and README
Pertempto Oct 23, 2025
38c6ded
docs: updates
Pertempto Oct 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions .opencode/command/do-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,40 @@ description: Develop the changes for a new pull request
agent: build
---

If the user has NOT previously ran the /start-pr command, exit early and ask them to run that command.
IMPORTANT: This command must run the full non-interactive flow for creating a PR. That means it MUST run the test suite(s), commit any changes, push the branch, create the GitHub pull request, update `CHANGELOG.md` with the PR number, and push the changelog — all without asking the user for additional input.

If the user has NOT previously run the `/start-pr` command, prompt them for the issue number to work on.

Required behavior (non-interactive flow)

1. Read the spec for the given issue in `specs/` and determine the next incomplete section from the Task List.
2. For each task in the incomplete section:
- Implement the task.
- Run the relevant automated tests immediately after implementing the change. Tests must be run and pass before committing. Typical commands to run are:
- Unit/contract/integration (with race):
- `go test -race ./tests/unit ./tests/contract ./tests/integration`
- Performance tests (optional, without race):
- `go test ./tests/performance`
- If a change only affects unit tests, run the narrower set of packages to save time.
- If tests fail, refine the code until tests pass. Do not proceed to committing that TODO item until its tests pass.
- Once tests pass, update the spec (check off corresponding item) and commit the change locally using a descriptive conventional commit message (example `feat(7): add backup script`).
- Use: `git add -A && git commit -m "<scope>: <short description>"`
3. After all task items for the current section are completed and committed locally:
- Push the branch to the remote:
- `git push -u origin "$(git rev-parse --abbrev-ref HEAD)"`
- Create the pull request non-interactively using `gh` (GitHub CLI). Provide a clear title and a PR body via a HEREDOC to avoid shell quoting issues. Example:
- `gh pr create --title "<PR title>" --body "$(cat <<'EOF'\n<PR body>\nEOF\n)"`
- Retrieve the created PR number and URL to update `CHANGELOG.md`.
- Example to get the PR number: `gh pr view --json number,url --jq '.number'`
- Update `CHANGELOG.md` at the top (under the current unreleased section) with a single entry referencing the PR number in the repository style, for example:
- `- [#NN](https://github.com/kwila-cloud/simple-sync/pull/NN): Short description`
- Commit the `CHANGELOG.md` update and push the commit (it must be on the same branch so the changelog change is included in the PR):
- `git add CHANGELOG.md && git commit -m "chore: add changelog entry for PR #NN" && git push`
- Ask the user for code review feedback on the new pull request.
- DO NOT suggest starting on the next section of the task list.

Error handling and constraints

- The command must NOT prompt the user for extra confirmation during the flow. If an operation would normally require input (for example, `gh pr create` in interactive mode), invoke the non-interactive flags and provide the input programmatically (HEREDOC or CLI flags).
- If network push or GH CLI operations fail, surface the error and abort; do not attempt destructive recovery automatically.

1. Use the `todoread` tool to get the TODO list for the current issue
1. For each item in the TODO list:
1. Carefully implement change
1. Run relevant automated tests
1. Refine based on test results
1. Check off corresponding item in the issue spec
1. Commit
1. After all items on the TODO list are complete:
1. Push
1. Create pull request
1. Update changelog
1. Push
26 changes: 13 additions & 13 deletions .opencode/command/start-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ Use the user input as the issue number.

If the user input is empty or invalid, prompt the user for the issue number.

1. Check the spec for the given issue in `specs/`
1. Determine the next incomplete section from the Task List
1. Create branch using format `{issue-number}-{section-name}`
- DO NOT create branch if already in the correct branch for the issue number and section name
1. Research codebase to understand what's needed for the section
1. Ask the user any clarifying questions needed to implement the section
1. Create a TODO list with the `todowrite` tool
1. Explain the TODO list to the user
1. Refine TODO list based on user feedback
1. Prompt the user to run `/do-pr` when they are ready
Required behavior and confirmation flow

Example usage:
- User: `/start-pr 7`
- Agent: Checks `specs/7-data-persistence.md`, finds next incomplete section, creates branch like `7-storage-interface-updates`, researches requirements, explains plan
1. Read the spec for the given issue in `specs/` and determine the next incomplete section from the Task List.
2. Branch creation rules:
- Create a new branch only when the current branch name does **not** already match the desired `{issue-number}-{section-name}` for the section.
- If the current branch already matches the section, do not create or switch branches.
- If the user explicitly requests to stay on the current branch, do not create a branch.
3. Research the codebase to gather information about the change.
4. Ask the user clarifying questions.
- Clearly number the questions.
- Clearly letter the options for each question.
5. Update the Task List section with any new updates based on your research and the user's answers.
6. Explain the current Task List section to the user.
7. When the Task List section is approved by the user, instruct the user to run `/do-pr` to begin implementing the changes. Do not use the word “proceed” as the final prompt — always reference `/do-pr`.
63 changes: 49 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,31 +141,61 @@ See `specs/7-data-persistence.md` for a well-structured specification that:

- **Recommendation:** When programmatically constructing search patterns, either validate the regex before use or default to fixed-string searches. If you are unsure whether a pattern contains regex metacharacters, use `-F` to avoid surprises.

### PR Title & Description Rules
- **Always inspect the full diff for the branch before creating a PR.** Use Git to view changes against the base branch and confirm the final, combined diff that will become the PR.

- View commits on your branch relative to `main`:
- `git fetch origin && git log --oneline origin/main...HEAD`
- View a concise file/status diff against `main`:
- `git fetch origin && git diff --name-status origin/main...HEAD`
- View a human-readable patch summary before creating the PR:
- `git fetch origin && git diff --stat origin/main...HEAD`
- View the full patch if needed:
- `git fetch origin && git diff origin/main...HEAD`

- **Title rules:**
- The PR title must be a short, descriptive summary of the change and MUST NOT include the issue number.
- Example — incorrect: `docs(7): documentation and restore script fixes for data persistence`
- Example — correct: `docs: documentation and restore script fixes for data persistence`

- **Description rules:**
- The PR body/description MUST include the issue number (and link) that the PR addresses. Prefer an explicit `Fixes #<issue>` or `Related to #<issue>` line.
- Example body snippet:

Issue: https://github.com/kwila-cloud/simple-sync/issues/7

This PR moves the data-persistence doc into the site content and adds a checklist to verify `restore.sh` behavior.

Fixes #7

- **How to get the final PR number non-interactively:**
- After creating the PR, capture the assigned number:
- `gh pr view --json number,url --jq '.number'` (use the branch name if needed)

### Changelog
- **ALWAYS add a new line to `CHANGELOG.md` for each new *pull request* (PR).** Do not link to the issue number — reference the PR number.
- Document new features, enhancements, bug fixes, and breaking changes
- Follow the existing format with PR links and clear descriptions (see examples below)
- Keep entries concise but descriptive for users and maintainers
- **IMPORTANT**: Always verify the actual PR details before updating the changelog. Use `gh pr view <PR-number>` or `gh pr view <branch>` to confirm the PR number, title, and changed files.
- **ALWAYS add a new line to `CHANGELOG.md` for each new *pull request* (PR).** Do not include or link to the issue number — reference the PR number only.
- Document new features, enhancements, bug fixes, and breaking changes.
- Follow the existing format with PR links and clear descriptions (see examples below).
- Keep entries concise but descriptive for users and maintainers.
- **IMPORTANT**: Always verify the actual PR details **and the PR title** before updating the changelog. Use `gh pr view <PR-number>` or `gh pr view <branch>` to confirm the PR number, title, and changed files.

- **CRITICAL**: Add exactly ONE entry per PR. Never add multiple entries for the same pull request, even if the PR contains multiple types of changes. Combine all changes into a single, concise description.

Examples (incorrect vs correct):

- Incorrect (links to issue instead of PR):
- Incorrect (links to issue rather than PR, or includes issue numbers in the text):
- `- [#7](https://github.com/kwila-cloud/simple-sync/issues/7): Implement ACL rule storage (CreateAclRule, GetAclRules)`

- Correct (match existing style — use PR link and number):
- Correct (match existing style — use PR link and number, no issue numbers in entry):
- `- [#59](https://github.com/kwila-cloud/simple-sync/pull/59): Implement ACL rule storage (CreateAclRule, GetAclRules)`

Recommended workflow to avoid mistakes:

1. Create the PR on the branch (`gh pr create`), or push the branch and open the PR on GitHub.
2. Immediately run `gh pr view --json number,url,title --jq '.number'` or `gh pr view <branch>` to retrieve the assigned PR number.
- Example: `gh pr view 7-acl-rule-storage --json number,url,title`
3. Edit `CHANGELOG.md` at the top (under the current unreleased version) and add a single line using the PR number as shown in the "Correct" example above.
4. Commit the changelog update to the same branch so the changelog change is included in the PR.
5. Push the branch and verify the PR body/changed files if necessary.
1. Inspect the full diff using the `git` commands above and confirm the intended changes.
2. Create the PR non-interactively using `gh pr create` with a title (no issue number) and a body that includes the issue link/number.
3. Immediately run `gh pr view --json number,url,title --jq '.number'` to get the PR number.
4. Update `CHANGELOG.md` at the top (under the current unreleased version) with a single entry referencing the **PR number only**.
5. Commit the changelog update to the same branch so the changelog change is included in the PR.

Notes:
- The changelog should always reference the PR number (not the issue number) because the PR is the canonical unit that contains the implemented changes and the exact diff reviewers will see.
Expand Down Expand Up @@ -195,7 +225,6 @@ See `.opencode/command/` directory for examples.

### Idiomtic Go


#### Looping

Prefer `for i := range n` (Go 1.22+) over `for i := 0; i < n; i++` when iterating a fixed integer count; prefer `for i := range slice` when iterating slices.
Expand Down Expand Up @@ -223,3 +252,9 @@ Prefer `for i := range n` (Go 1.22+) over `for i := 0; i < n; i++` when iteratin
- ❌ Bad: Creating custom string formatting helpers

4. **When in doubt**: If you're about to write a helper function, first check the Go standard library documentation for existing solutions

### SQLite Storage
- The project uses SQLite for persistent storage; production/dev processes expect a local file under `./data` by default (`./data/simple-sync.db`).
- Docker Compose is configured to bind-mount `./data` into the container (`./data:/app/data`) so the DB file is stored on the host. This is the recommended setup for development and simple deployments because it makes backups and inspection straightforward.
- If you need a Docker-managed volume, a named volume `simple-sync-data` exists in `docker-compose.yml` (commented). Using a named volume is fine for environments where host access is not required, but it makes manual backups/restores less obvious.

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Release History

## [0.4.0] - unreleased
- [#62](https://github.com/kwila-cloud/simple-sync/pull/62): Add storage documentation
- [#61](https://github.com/kwila-cloud/simple-sync/pull/61): Add performance and concurrency tests for SQLite storage
- [#60](https://github.com/kwila-cloud/simple-sync/pull/60): Implement SQLite setup token and API key storage
- [#59](https://github.com/kwila-cloud/simple-sync/pull/59): Implement SQLite ACL rule storage
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ services:
- simple-sync
```

### Persistent Data (Docker Compose)
The Docker Compose configuration mounts a local `./data` directory into the container (`./data:/app/data`) by default. This is the recommended setup for development and simple deployments because it keeps the SQLite database file on the host, making backups and inspection straightforward.

If you prefer Docker-managed storage, a named volume `simple-sync-data` is declared in `docker-compose.yml`; you can switch to it by uncommenting the named volume line and removing the `./data` bind mount.

Backup and restore helper scripts are provided in `./scripts`:
- `./scripts/backup.sh [--stop] [--dir <backup-dir>] [path-to-db]` — copy the DB file to `./backups/` (or specified directory) (use `--stop` to stop the container during backup)
- `./scripts/restore.sh <backup-file> [--stop]` — restore a backup into `./data/simple-sync.db` (moves the existing DB aside first)

Example (take a backup and then start):

```bash
# create a backup (stop service during the copy)
./scripts/backup.sh --stop
# start services
docker compose up -d
```

Developer note: the app uses `github.com/mattn/go-sqlite3` which requires `libsqlite3-dev` and `CGO_ENABLED=1` when building locally or in CI.


## Development

### Building
Expand Down
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ services:
environment:
- PORT=8080
volumes:
- ./data:/app/data
- ./data:/app/data # explicit local bind for persistent DB file (recommended for development)
# Alternative: use a named volume managed by Docker
# - simple-sync-data:/app/data
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "-s", "http://localhost:8080/api/v1/health"]
Expand Down
73 changes: 73 additions & 0 deletions scripts/backup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail

# Simple Sync backup script
# Usage: ./scripts/backup.sh [--stop] [--dir <backup-dir>] [path-to-db]
# If --stop is provided, the script will stop the docker-compose service before copying and restart it afterwards.
# If --dir is provided, it specifies the directory to store backups (defaults to ./backups).

STOP=false
BACKUP_DIR="./backups"
DB_PATH="./data/simple-sync.db"
DB_PATH_PROVIDED=false

while [ "$#" -gt 0 ]; do
case "$1" in
--stop)
STOP=true
shift
;;
--dir)
if [ -z "${2:-}" ]; then
echo "Error: --dir requires a directory argument"
exit 2
fi
BACKUP_DIR="$2"
shift 2
;;
--dir=*)
BACKUP_DIR="${1#--dir=}"
shift
;;
--help|-h)
echo "Usage: $0 [--stop] [--dir <backup-dir>] [path-to-db]"
exit 0
;;
*)
if [ "$DB_PATH_PROVIDED" = false ]; then
DB_PATH="$1"
DB_PATH_PROVIDED=true
shift
else
echo "Unknown argument: $1"
exit 2
fi
;;
esac
done

mkdir -p "$BACKUP_DIR"

if [ ! -f "$DB_PATH" ]; then
echo "Error: database file not found at $DB_PATH"
exit 1
fi

TIMESTAMP=$(date +%Y%m%d%H%M%S)
BACKUP_FILE="$BACKUP_DIR/simple-sync-$TIMESTAMP.db"

if [ "$STOP" = true ]; then
echo "Stopping simple-sync service..."
docker compose stop simple-sync || true
fi

echo "Copying $DB_PATH -> $BACKUP_FILE"
cp -- "$DB_PATH" "$BACKUP_FILE"

if [ "$STOP" = true ]; then
echo "Starting simple-sync service..."
docker compose start simple-sync || true
fi

echo "Backup complete: $BACKUP_FILE"
exit 0
51 changes: 51 additions & 0 deletions scripts/restore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -euo pipefail

# Simple Sync restore script
# Usage: ./scripts/restore.sh <backup-file> [--stop]
# Restores the given backup file into ./data/simple-sync.db. If --stop is provided, the service will be stopped before restore and started after.

if [ "$#" -lt 1 ]; then
echo "Usage: $0 <backup-file> [--stop]"
exit 2
fi

BACKUP_FILE="$1"
shift

STOP=false
if [ "${1:-}" = "--stop" ]; then
STOP=true
fi

DB_DIR="./data"
DB_PATH="$DB_DIR/simple-sync.db"

if [ ! -f "$BACKUP_FILE" ]; then
echo "Error: backup file not found: $BACKUP_FILE"
exit 1
fi

mkdir -p "$DB_DIR"

if [ "$STOP" = true ]; then
echo "Stopping simple-sync service..."
docker compose stop simple-sync || true
fi

# Safety: move existing DB aside
if [ -f "$DB_PATH" ]; then
OLD_TS=$(date +%Y%m%d%H%M%S)
mv -- "$DB_PATH" "$DB_DIR/simple-sync.db.bak.$OLD_TS"
echo "Moved existing DB to $DB_DIR/simple-sync.db.bak.$OLD_TS"
fi

cp -- "$BACKUP_FILE" "$DB_PATH"

if [ "$STOP" = true ]; then
echo "Starting simple-sync service..."
docker compose start simple-sync || true
fi

echo "Restore complete: $DB_PATH"
exit 0
10 changes: 5 additions & 5 deletions specs/7-data-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ Encryption at rest will be addressed separately (issue #17) using SQLCipher or f
- [x] Validate concurrent access and large dataset handling

### Documentation and Configuration Updates
- [ ] Update Docker configuration for data persistence
- [ ] Update AGENTS.md with SQLite storage information
- [ ] Update README.md with data persistence features and setup instructions
- [ ] Update user-facing documentation in docs/ with SQLite configuration
- [ ] Document backup/restore procedures and security considerations
- [x] Update Docker configuration for data persistence
- [x] Update AGENTS.md with SQLite storage information
- [x] Update README.md with data persistence features and setup instructions
- [x] Update user-facing documentation in `src/content/docs` with SQLite configuration
- [x] Document backup/restore

### Clean Up
- [ ] Handle remaining TODO comments for issue #7
Loading