diff --git a/.github/workflows/ci-node-packages.yml b/.github/workflows/ci-node-packages.yml deleted file mode 100644 index b85a1a1..0000000 --- a/.github/workflows/ci-node-packages.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: CI — Node packages - -on: - push: - paths: - - 'packages/**' - pull_request: - paths: - - 'packages/**' - -jobs: - test-packages: - name: Test packages/* - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - - - name: Run tests for each package - shell: bash - run: | - set -euo pipefail - - # Find all package directories under packages/ that contain a package.json - packages=(packages/*) - found=0 - - for p in "${packages[@]}"; do - if [ -d "$p" ] && [ -f "$p/package.json" ]; then - found=1 - echo "\n===== Package: $p =====" - - echo "-> Installing dependencies in $p" - (cd "$p" && npm ci) || (cd "$p" && npm install) - - echo "-> Running tests in $p" - (cd "$p" && npm test) - - echo "-> Running pack-inspect in $p" - (cd "$p" && npm run pack-inspect) - fi - done - - if [ "$found" -eq 0 ]; then - echo "No packages with package.json found under packages/" - fi diff --git a/.github/workflows/publish-ansible-example.yml b/.github/workflows/publish-ansible-example.yml deleted file mode 100644 index 45e045b..0000000 --- a/.github/workflows/publish-ansible-example.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Publish Ansible Example - -on: - push: - tags: - - 'v*' - workflow_dispatch: {} - -jobs: - verify: - name: Verify package - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js 18 - uses: actions/setup-node@v4 - with: - node-version: '18' - - - name: Install dependencies (packages/@ansible/example) - working-directory: packages/@ansible/example - run: | - # prefer CI install when a lockfile exists, otherwise fall back to install - if [ -f package-lock.json ] || [ -f pnpm-lock.yaml ] || [ -f yarn.lock ]; then - npm ci - else - npm install - fi - - - name: Run tests - working-directory: packages/@ansible/example - run: npm test - - - name: Run pack-inspect - working-directory: packages/@ansible/example - run: npm run pack-inspect - - publish: - name: Publish to npm - runs-on: ubuntu-latest - needs: verify - if: ${{ ((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch')) && (secrets.NPM_TOKEN != '') }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js 18 - uses: actions/setup-node@v4 - with: - node-version: '18' - - - name: Create ephemeral .npmrc with token - run: | - set -euo pipefail - # write token to a temporary npmrc with restricted permissions (0600) - printf "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}\n" > ~/.npmrc - chmod 600 ~/.npmrc - - - name: Publish package - working-directory: packages/@ansible/example - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - set -euo pipefail - # publish publicly; rely on npmrc for auth - npm publish --access public - - - name: Remove ephemeral .npmrc (always) - if: always() - run: | - set -euo pipefail - # attempt secure removal, fall back to plain removal - if [ -f ~/.npmrc ]; then - shred -u -z ~/.npmrc 2>/dev/null || rm -f ~/.npmrc || true - fi diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 10f6c1b..0000000 --- a/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM python:3.13-slim - -# Install minimal system deps -RUN apt-get update \ - && apt-get install -y --no-install-recommends build-essential curl ca-certificates \ - && rm -rf /var/lib/apt/lists/* - -# Create non-root user for running the app -RUN useradd -m -s /bin/bash app - -WORKDIR /home/app/app - -# Copy project files -COPY . /home/app/app - -# Upgrade pip and install all project dependencies from pyproject.toml -RUN python -m pip install --upgrade pip -RUN pip install . - -# Fix permissions -RUN chown -R app:app /home/app - -USER app -ENV PYTHONPATH=/home/app/app - -EXPOSE 8501 - -# Simple healthcheck that queries the Streamlit root -HEALTHCHECK --interval=30s --timeout=3s --start-period=10s CMD curl -f http://localhost:8501/ || exit 1 - -# Run the multi-page Streamlit app -CMD ["streamlit", "run", "Home.py", "--server.port=8501", "--server.address=0.0.0.0"] diff --git a/README.md b/README.md index f5ece33..2b775c2 100644 --- a/README.md +++ b/README.md @@ -72,10 +72,6 @@ The app will be available at http://localhost:8501. - **LLM:** QWEN via OpenRouter (OpenAI-compatible) - **Package Manager:** uv -## Deployment - -See [docs/deployment/ansible-package-deploy.md](docs/deployment/ansible-package-deploy.md) for server deployment instructions using the Ansible package. - ## License [Your license here] diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg deleted file mode 100644 index 0c7ef86..0000000 --- a/ansible/ansible.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[defaults] -inventory = inventory.ini -remote_user = webapps - -[ssh_connection] -ssh_args = -o ForwardAgent=yes -o ControlMaster=auto -o ControlPersist=60s diff --git a/ansible/deploy.sh b/ansible/deploy.sh deleted file mode 100755 index 6e49710..0000000 --- a/ansible/deploy.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -ansible-playbook -i inventory.ini deploy.yaml diff --git a/ansible/deploy.yaml b/ansible/deploy.yaml deleted file mode 100644 index f75d7b7..0000000 --- a/ansible/deploy.yaml +++ /dev/null @@ -1,67 +0,0 @@ ---- -- name: deploy motief application - hosts: sgeboers.nl - remote_user: webapps - - tasks: - - name: ensure git.sgeboers.nl SSH config uses port 222 - ansible.builtin.blockinfile: - path: /home/webapps/.ssh/config - create: yes - mode: '0600' - marker: "# {mark} ANSIBLE MANAGED: git.sgeboers.nl" - block: | - Host git.sgeboers.nl - User git - Port 222 - IdentityFile /home/webapps/.ssh/ed25519 - - - name: ensure git.sgeboers.nl is in known_hosts - ansible.builtin.known_hosts: - name: "[git.sgeboers.nl]:222" - key: "{{ lookup('pipe', 'ssh-keyscan -p 222 git.sgeboers.nl') }}" - state: present - - - name: pull latest code - ansible.builtin.git: - repo: ssh://git@git.sgeboers.nl:222/sgeboers/motief.git - dest: ~/motief - clone: yes - force: yes - key_file: /home/webapps/.ssh/ed25519 - accept_newhostkey: yes - - - name: sync dependencies with uv - ansible.builtin.shell: - cmd: /home/webapps/.local/bin/uv sync - chdir: ~/motief - - - name: stop existing streamlit process - ansible.builtin.shell: - cmd: pkill -f "streamlit run Home.py" || true - ignore_errors: yes - - - name: ensure data directory exists on server - ansible.builtin.file: - path: /home/webapps/motief/data - state: directory - mode: '0755' - - - name: sync motions.db to server - ansible.builtin.synchronize: - src: ../data/motions.db - dest: /home/webapps/motief/data/motions.db - checksum: yes - - - name: start streamlit - ansible.builtin.shell: - cmd: nohup /home/webapps/.local/bin/uv run streamlit run Home.py --server.port=8501 --server.address=0.0.0.0 --server.headless=true --server.enableCORS=false & - chdir: ~/motief - - - name: wait for streamlit to be ready - ansible.builtin.uri: - url: http://127.0.0.1:8501/_stcore/health - method: GET - status_code: 200 - retries: 30 - delay: 2 diff --git a/ansible/inventory.ini b/ansible/inventory.ini deleted file mode 100644 index 3742fa4..0000000 --- a/ansible/inventory.ini +++ /dev/null @@ -1 +0,0 @@ -sgeboers.nl ansible_user=webapps diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 9070d7b..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: "3.9" - -services: - motief: - image: ${DOCKER_REGISTRY}/sgeboers/stemwijzer:latest - ports: - - "127.0.0.1:8501:8501" - volumes: - - ${DATA_DIR:-/home/webapps/motief/data}:/home/app/app/data - restart: unless-stopped - environment: - - PYTHONPATH=/home/app/app - - OPENROUTER_API_KEY - - DB_PATH=/home/app/app/data/motions.db - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8501/"] - interval: 30s - timeout: 3s - retries: 3 - start_period: 15s diff --git a/docs/deployment/ansible-package-deploy.md b/docs/deployment/ansible-package-deploy.md deleted file mode 100644 index 033346c..0000000 --- a/docs/deployment/ansible-package-deploy.md +++ /dev/null @@ -1,42 +0,0 @@ -# Ansible package deploy (defaults) - -This document describes the default values and recommended steps for deploying the `packages/@ansible/example` package to a server using the provided Ansible playbooks. - -Defaults -- DEPLOY_HOST: `motief.sgeboers.nl` -- DEPLOY_USER: `webapps` -- Recommended systemd service name: `motief` - -Secrets / environment variables -- DEPLOY_SSH_KEY: private SSH key used by CI to connect to the host -- DEPLOY_HOST: (override) host to deploy to -- DEPLOY_USER: (override) user to use for deployment (default: `webapps`) -- DEPLOY_PATH: (optional) path on the remote host to deploy the package to. If unset, the playbook will use its configured default. Set this value in CI if your installation directory differs from the playbook default. - -Granting access (server-side steps) -1. As the server administrator, ensure the `webapps` user exists: - - sudo useradd -m -s /bin/bash webapps - -2. Create the `.ssh` directory and add the public key that matches your CI `DEPLOY_SSH_KEY`: - - sudo -u webapps mkdir -p /home/webapps/.ssh - sudo -u webapps chmod 700 /home/webapps/.ssh - # paste the public key from your CI into /home/webapps/.ssh/authorized_keys - sudo -u webapps sh -c 'cat >> /home/webapps/.ssh/authorized_keys' - sudo -u webapps chmod 600 /home/webapps/.ssh/authorized_keys - -3. If the playbook requires sudo operations, add the necessary sudoers entry (use with care): - - echo "webapps ALL=(ALL) NOPASSWD: /bin/systemctl restart motief" | sudo tee /etc/sudoers.d/webapps-motief - -Deployment notes -- The playbooks assume the above defaults. If your host, user or install path differ, set the appropriate environment variables in your CI (DEPLOY_HOST, DEPLOY_USER, DEPLOY_PATH) before running the deploy job. -- The recommended systemd service name is `motief`. If you change the service name in the playbook or systemd unit, ensure any helper scripts or CI steps refer to the same name. - -Security -- Only add trusted public keys to `/home/webapps/.ssh/authorized_keys`. -- Limit sudo privileges to only the commands required for deploy/service restart. - -Troubleshooting -- If the CI runner cannot connect, verify the private key in `DEPLOY_SSH_KEY` matches the public key on the server and the `DEPLOY_HOST`/`DEPLOY_USER` values are correct. diff --git a/docs/plans/2026-04-24-002-fix-docker-compose-scheduler-plan.md b/docs/plans/2026-04-24-002-fix-docker-compose-scheduler-plan.md deleted file mode 100644 index 850a9e2..0000000 --- a/docs/plans/2026-04-24-002-fix-docker-compose-scheduler-plan.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: "fix: docker-compose.yml references missing scheduler.py" -type: fix -status: active -date: 2026-04-24 ---- - -# Fix: docker-compose.yml Missing scheduler.py - -## Overview - -`docker-compose.yml` defines a `scheduler` service that runs `python scheduler.py`, but no `scheduler.py` exists in the repo. This causes `docker-compose up` to fail for the scheduler service. - -## Problem Frame - -- The scheduler service is a deployment bug -- Either the file was never created, or it was removed and the compose file was not updated -- The `schedule` dependency in pyproject.toml suggests automated scheduling was intended - -## Requirements Trace - -- R1. docker-compose.yml must reference only existing files -- R2. If scheduling is desired, create scheduler.py; if not, remove the service - -## Scope Boundaries - -**Included:** -- Fix docker-compose.yml - -**Excluded:** -- Implementing actual scheduling logic (unless user confirms) - -## Implementation Units - -- [ ] U1. **Determine scheduler intent** - -**Goal:** Decide whether to create scheduler.py or remove the service. - -**Requirements:** R1, R2 - -**Dependencies:** None - -**Files:** -- Read: `docker-compose.yml`, `pyproject.toml` - -**Approach:** -- Check if `schedule` dependency is used anywhere -- Check if there's a scheduling script under another name -- Decision: If scheduling is not implemented, remove the service for now and create a plan for it later - -**Test expectation:** none — decision unit. - -**Verification:** -- Clear decision documented in this plan - ---- - -- [ ] U2. **Apply fix** - -**Goal:** Make docker-compose.yml valid. - -**Requirements:** R1 - -**Dependencies:** U1 - -**Files:** -- Modify: `docker-compose.yml` - -**Approach:** -- Option A: Remove scheduler service (if scheduling is deferred) -- Option B: Create minimal scheduler.py (if scheduling is desired now) - -**Test scenarios:** -- Integration: `docker-compose config` validates without error -- Happy path: `docker-compose up motief` works (existing service unchanged) - -**Verification:** -- `docker-compose config` passes -- No reference to missing scheduler.py - ---- - -## Risks & Dependencies - -| Risk | Mitigation | -|------|------------| -| Removing service breaks someone's workflow | Only remove if confirmed unused; otherwise create stub | - -## Sources & References - -- `docker-compose.yml` -- `pyproject.toml` (schedule dependency) diff --git a/docs/plans/2026-04-24-ROADMAP-stemwijzer-improvements.md b/docs/plans/2026-04-24-ROADMAP-stemwijzer-improvements.md index f3c25f3..c2f19ad 100644 --- a/docs/plans/2026-04-24-ROADMAP-stemwijzer-improvements.md +++ b/docs/plans/2026-04-24-ROADMAP-stemwijzer-improvements.md @@ -14,7 +14,7 @@ This roadmap captures 17 improvement opportunities identified during a codebase | # | Improvement | Priority | Effort | Plan | TDD | |---|------------|----------|--------|------|-----| | 1 | Fix broken CI test workflow (mindmodel-schedule.yml references missing requirements.txt) | High | Small | P1-001 | Yes | -| 2 | Fix docker-compose.yml (missing scheduler.py) | High | Small | P1-002 | No (config) | +| 2 | ~~Fix docker-compose.yml (missing scheduler.py)~~ — *Removed: Docker deployment not used* | — | — | — | — | | 3 | Consolidate duplicate config sources (config.py vs analysis/config.py) | Medium | Small | P1-003 | Yes | | 4 | Rewrite README.md (22 lines → proper quickstart) | High | Small | P1-004 | No (docs) | | 5 | Add pyright type-checking to CI | Medium | Small | P1-005 | Yes | @@ -98,7 +98,7 @@ Phase 1 must come first. Phase 2 makes Phase 3/4 safer. Phase 3 unlocks some Pha ## Recommended Execution Order -**Sprint 1:** Items 1, 2, 4, 6 (CI + docs + pre-commit) +**Sprint 1:** Items 1, 4, 6 (CI + docs + pre-commit) **Sprint 2:** Items 5, 7, 8 (type checking + logging + errors) **Sprint 3:** Item 10 (explorer decomposition) **Sprint 4:** Items 12, 15, 17 (pipeline automation + health checks) @@ -111,7 +111,7 @@ Phase 1 must come first. Phase 2 makes Phase 3/4 safer. Phase 3 unlocks some Pha | Plan ID | File | Status | |---------|------|--------| | P1-001 | docs/plans/2026-04-24-001-fix-ci-test-workflow-plan.md | Planned | -| P1-002 | docs/plans/2026-04-24-002-fix-docker-compose-scheduler-plan.md | Planned | +| P1-002 | ~~docs/plans/2026-04-24-002-fix-docker-compose-scheduler-plan.md~~ | Removed | | P1-003 | docs/plans/2026-04-24-003-consolidate-config-sources-plan.md | Planned | | P1-004 | docs/plans/2026-04-24-004-rewrite-readme-plan.md | Planned | | P1-005 | docs/plans/2026-04-24-005-add-pyright-ci-plan.md | Planned | @@ -127,5 +127,5 @@ Phase 1 must come first. Phase 2 makes Phase 3/4 safer. Phase 3 unlocks some Pha ## Notes - All implementation plans use TDD (test-first) for code-bearing units. -- Config-only units (README, docker-compose fix) skip TDD but include verification checklists. +- Config-only units (README) skip TDD but include verification checklists. - Existing plans (e.g., explorer decomposition) are referenced rather than duplicated. diff --git a/packages/@ansible/example/README.md b/packages/@ansible/example/README.md deleted file mode 100644 index 901aee6..0000000 --- a/packages/@ansible/example/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# @ansible/example - -A minimal example npm-scoped package for the @ansible scope. Provided as a publishable example maintained by Sven Geboers. - -Usage: - -const example = require('@ansible/example'); -console.log(example('world')); - -Author: Sven Geboers - -Publishing - -This package is intended to be published from CI using a repository secret named NPM_TOKEN. Create a git tag (e.g. `v0.1.0`) and push it; the GitHub Actions workflow will run and publish when `NPM_TOKEN` is configured. For local testing, run `npm pack` in the package directory. - -Refer to the repository docs for full deploy and publish instructions. - -Make sure to keep this README short and useful. diff --git a/packages/@ansible/example/package.json b/packages/@ansible/example/package.json deleted file mode 100644 index 5e8de15..0000000 --- a/packages/@ansible/example/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "@ansible/example", - "version": "1.0.0", - "author": "Sven Geboers ", - "publishConfig": { - "access": "public" - }, - "files": [ - "dist", - "lib" - ] - , - "scripts": { - "test": "node tests/run.js" - } -} diff --git a/packages/@ansible/example/src/index.js b/packages/@ansible/example/src/index.js deleted file mode 100644 index 891f6d6..0000000 --- a/packages/@ansible/example/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -// Minimal entrypoint for @ansible/example -module.exports = function example(name) { - if (!name) return 'hello'; - return `hello ${name}`; -}; - -// When required directly, export a default behaviour too -module.exports.default = module.exports; diff --git a/packages/@ansible/example/tests/_pack_helpers.js b/packages/@ansible/example/tests/_pack_helpers.js deleted file mode 100644 index 42cd7cd..0000000 --- a/packages/@ansible/example/tests/_pack_helpers.js +++ /dev/null @@ -1,11 +0,0 @@ -const { execSync } = require('child_process'); -const path = require('path'); -module.exports.runPack = function runPack() { - const cwd = path.join(__dirname, '..'); - // run npm pack and capture output - const out = execSync('npm pack', { cwd, encoding: 'utf8' }).trim(); - // npm pack prints the filename on the last line - const lines = out.split(/\r?\n/).filter(Boolean); - const filename = lines[lines.length - 1]; - return { cwd, filename }; -}; diff --git a/packages/@ansible/example/tests/run.js b/packages/@ansible/example/tests/run.js deleted file mode 100644 index b5286a1..0000000 --- a/packages/@ansible/example/tests/run.js +++ /dev/null @@ -1,20 +0,0 @@ -const { execSync } = require('child_process'); -const path = require('path'); -const tests = [ - 'test_package_json.js', - 'test_pack_inspect.js' -]; - -const cwd = path.join(__dirname); -let failed = false; -for (const t of tests) { - console.log('Running', t); - try { - execSync(`node ${t}`, { cwd, stdio: 'inherit' }); - } catch (e) { - console.error(t, 'failed'); - failed = true; - break; - } -} -process.exit(failed ? 1 : 0); diff --git a/packages/@ansible/example/tests/test_pack_inspect.js b/packages/@ansible/example/tests/test_pack_inspect.js deleted file mode 100644 index 50886e6..0000000 --- a/packages/@ansible/example/tests/test_pack_inspect.js +++ /dev/null @@ -1,28 +0,0 @@ -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); -const { runPack } = require('./_pack_helpers'); -try { - const { cwd, filename } = runPack(); - const tarPath = path.join(cwd, filename); - if (!fs.existsSync(tarPath)) throw new Error('tarball not found: ' + tarPath); - // inspect package/package.json within tarball using tar -xOzf - const execSync = require('child_process').execSync; - let pkgJsonStr; - try { - pkgJsonStr = execSync(`tar -xOzf ${filename} package/package.json`, { cwd, encoding: 'utf8' }); - } catch (e) { - throw new Error('failed to extract package.json from tarball; ensure `tar` is available'); - } - const pkg = JSON.parse(pkgJsonStr); - assert.strictEqual(pkg.name, '@ansible/example', 'tarball package.json name mismatch'); - assert.ok(pkg.version, 'tarball package.json missing version'); - console.log('test_pack_inspect: OK'); - // cleanup: remove tarball - try { fs.unlinkSync(tarPath); } catch (e) {} - process.exit(0); -} catch (err) { - console.error('test_pack_inspect: FAILED'); - console.error(err && err.message ? err.message : err); - process.exit(1); -} diff --git a/packages/@ansible/example/tests/test_package_json.js b/packages/@ansible/example/tests/test_package_json.js deleted file mode 100644 index 8b1d424..0000000 --- a/packages/@ansible/example/tests/test_package_json.js +++ /dev/null @@ -1,17 +0,0 @@ -const assert = require('assert'); -const path = require('path'); -const pkg = require(path.join(__dirname, '..', 'package.json')); - -try { - assert.strictEqual(pkg.name, '@ansible/example', 'package name must be @ansible/example'); - assert.ok(pkg.version && typeof pkg.version === 'string', 'version must be present'); - assert.ok(pkg.author && pkg.author.includes('Sven'), 'author must be Sven Geboers'); - assert.ok(pkg.publishConfig && pkg.publishConfig.access === 'public', 'publishConfig.access must be public'); - assert.ok(Array.isArray(pkg.files), 'files array must exist'); - console.log('test_package_json: OK'); - process.exit(0); -} catch (err) { - console.error('test_package_json: FAILED'); - console.error(err && err.message ? err.message : err); - process.exit(1); -}